From ba8ea45b3465947eb7e33c9d41f9e90771f7386d Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 31 Mar 2025 17:57:14 +0100 Subject: [PATCH 01/65] Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt --- app/build.gradle.kts | 1 - .../data/model/CurrencyEntity.java | 6 +- .../main/java/com/brainwallet/di/Module.kt | 4 +- .../presenter/activities/util/BRActivity.java | 4 +- .../tools/manager/BRApiManager.java | 317 +++++++++--------- .../currency/BackupRateFetchTests.kt | 6 +- .../java/com/brainwallet/data/BaseURLTests.kt | 19 +- .../tools/util/ProdAPIManagerTests.kt | 26 +- 8 files changed, 185 insertions(+), 198 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d20ad2c8..7922396b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -188,7 +188,6 @@ dependencies { } implementation("androidx.webkit:webkit:1.9.0") - implementation("com.squareup.moshi:moshi-kotlin:1.15.2") implementation(libs.androidx.core) implementation(libs.androidx.appcompat) implementation(libs.androidx.legacy.support) diff --git a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java index 319ed216..f0c31051 100644 --- a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java +++ b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java @@ -5,13 +5,13 @@ public class CurrencyEntity implements Serializable { //Change this after modifying the class - private static final long serialVersionUID = 7526472295622777000L; + private static final long serialVersionUID = 7526472295622776147L; public static final String TAG = CurrencyEntity.class.getName(); public String code; - public String name = ""; + public String name; public float rate; - public String symbol = ""; + public String symbol; public CurrencyEntity(String code, String name, float rate, String symbol) { this.code = code; diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 05db629b..75a2cf5f 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -5,7 +5,7 @@ import android.content.SharedPreferences import com.brainwallet.BuildConfig import com.brainwallet.data.repository.SettingRepository import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.ui.screens.home.SettingsViewModel import com.brainwallet.ui.screens.inputwords.InputWordsViewModel @@ -32,7 +32,7 @@ val dataModule = module { it.initialize() } } - single { APIManager(get()) } + single { BRApiManager(get()) } single { CurrencyDataSource.getInstance(get()) } single { provideSharedPreferences(context = androidApplication()) } single { SettingRepository.Impl(get(), get()) } diff --git a/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java index bd118415..6f62d97c 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java @@ -16,7 +16,7 @@ import com.brainwallet.presenter.activities.intro.RecoverActivity; import com.brainwallet.presenter.activities.intro.WriteDownActivity; import com.brainwallet.tools.animation.BRAnimator; -import com.brainwallet.tools.manager.APIManager; +import com.brainwallet.tools.manager.BRApiManager; import com.brainwallet.tools.manager.InternetManager; import com.brainwallet.tools.security.AuthManager; import com.brainwallet.tools.security.BRKeyStore; @@ -148,7 +148,7 @@ public static void init(Activity app) { if (!(app instanceof RecoverActivity || app instanceof WriteDownActivity)) { - APIManager apiManager = KoinJavaComponent.get(APIManager.class); + BRApiManager apiManager = KoinJavaComponent.get(BRApiManager.class); apiManager.startTimer(app); } diff --git a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java index e298b178..9b7a81de 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java @@ -30,7 +30,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; -import java.util.Optional; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -38,164 +37,158 @@ import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; -// -//public class BRApiManager { -// private Timer timer; -// -// private TimerTask timerTask; -// -// private Handler handler; -// -// private RemoteConfigSource remoteConfigSource; -// -// public BRApiManager(RemoteConfigSource remoteConfigSource) { -// this.remoteConfigSource = remoteConfigSource; -// this.handler = new Handler(); -// } -// -// private Set getCurrencies(Activity context) { -// Set set = new LinkedHashSet<>(); -// try { -// JSONArray arr = fetchRates(context); -// FeeManager.updateFeePerKb(context); -// if (arr != null) { -// String selectedISO = BRSharedPrefs.getIsoSymbol(context); -// int length = arr.length(); -// for (int i = 0; i < length; i++) { -// CurrencyEntity tempCurrencyEntity = new CurrencyEntity(); -// try { -// JSONObject tmpJSONObj = (JSONObject) arr.get(i); -// tempCurrencyEntity.name = "no_currency_name"; -// if (tmpJSONObj.getString("name").toString() != null) { -// tempCurrencyEntity.name = tmpJSONObj.getString("name"); -// } -// tempCurrencyEntity.code = tmpJSONObj.getString("code"); -// tempCurrencyEntity.rate = (float) tmpJSONObj.getDouble("n"); -// tempCurrencyEntity.symbol = new String(""); -// if (tempCurrencyEntity.code.equalsIgnoreCase(selectedISO)) { -// BRSharedPrefs.putIso(context, tempCurrencyEntity.code); -// BRSharedPrefs.putCurrencyListPosition(context, i - 1); -// } -// set.add(tempCurrencyEntity); -// Timber.d(":::timber: CE: %s",tempCurrencyEntity.code); -// -// } catch (JSONException e) { -// ///Timber.e(e); -// // Timber.d(":::timber: ERROR: %s",e); -// } -// } -// } else { -// Timber.d("timber: getCurrencies: failed to get currencies"); -// } -// } catch (Exception e) { -// Timber.e(e); -// } -// List tempList = new ArrayList<>(set); -// Collections.reverse(tempList); -// return new LinkedHashSet<>(set); -// } -// -// -// private void initializeTimerTask(final Context context) { -// timerTask = new TimerTask() { -// public void run() { -// //use a handler to run a toast that shows the current timestamp -// handler.post(new Runnable() { -// public void run() { -// BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { -// @Override -// public void run() { -// Set tmp = getCurrencies((Activity) context); -// CurrencyDataSource.getInstance(context).putCurrencies(tmp); -// } -// }); -// } -// }); -// } -// }; -// } -// -// public void startTimer(Context context) { -// //set a new Timer -// if (timer != null) return; -// timer = new Timer(); -// -// //initialize the TimerTask's job -// initializeTimerTask(context); -// -// //schedule the timer, after the first 0ms the TimerTask will run every 60000ms -// timer.schedule(timerTask, 0, 4000); -// } -// -// public JSONArray fetchRates(Activity activity) { -// String jsonString = createGETRequestURL(activity, BW_API_PROD_HOST + "/api/v1/rates"); -// JSONArray jsonArray = null; -// if (jsonString == null) return null; -// try { -// jsonArray = new JSONArray(jsonString); -// // DEV Uncomment to view values -// // Timber.d("timber: baseUrlProd: %s", getBaseUrlProd()); -// // Timber.d("timber: JSON %s",jsonArray.toString()); -// } catch (JSONException ex) { -// Timber.e(ex); -// } -// if (jsonArray != null && !BuildConfig.DEBUG) { -// AnalyticsManager.logCustomEvent(_20250222_PAC); -// } -// return jsonArray == null ? backupFetchRates(activity) : jsonArray; -// } -// -// public JSONArray backupFetchRates(Activity activity) { -// String jsonString = createGETRequestURL(activity, BW_API_DEV_HOST + "/api/v1/rates"); -// -// JSONArray jsonArray = null; -// if (jsonString == null) return null; -// try { -// jsonArray = new JSONArray(jsonString); -// -// } catch (JSONException e) { -// Timber.e(e); -// } -// if (jsonArray != null && !BuildConfig.DEBUG) { -// AnalyticsManager.logCustomEvent(_20230113_BAC); -// } -// -// return jsonArray; -// } -// -// // createGETRequestURL -// // Creates the params and headers to make a GET Request -// private String createGETRequestURL(Context app, String myURL) { -// Request request = new Request.Builder() -// .url(myURL) -// .header("Content-Type", "application/json") -// .header("Accept", "application/json") -// .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) -// .get().build(); -// String response = null; -// Response resp = APIClient.getInstance(app).sendRequest(request, false, 0); -// -// try { -// if (resp == null) { -// Timber.i("timber: urlGET: %s resp is null", myURL); -// return null; -// } -// ///Set timestamp to prefs -// long timeStamp = new Date().getTime(); -// BRSharedPrefs.putSecureTime(app, timeStamp); -// -// assert resp.body() != null; -// response = resp.body().string(); -// -// } catch (IOException e) { -// Timber.e(e); -// } finally { -// if (resp != null) resp.close(); -// } -// return response; -// } -// -// public String getBaseUrlProd() { -// return BW_API_PROD_HOST; -// } -//} + +public class BRApiManager { + private Timer timer; + + private TimerTask timerTask; + + private Handler handler; + + private RemoteConfigSource remoteConfigSource; + + public BRApiManager(RemoteConfigSource remoteConfigSource) { + this.remoteConfigSource = remoteConfigSource; + this.handler = new Handler(); + } + + private Set getCurrencies(Activity context) { + Set set = new LinkedHashSet<>(); + try { + JSONArray arr = fetchRates(context); + FeeManager.updateFeePerKb(context); + if (arr != null) { + String selectedISO = BRSharedPrefs.getIsoSymbol(context); + int length = arr.length(); + for (int i = 0; i < length; i++) { + CurrencyEntity tempCurrencyEntity = new CurrencyEntity(); + try { + JSONObject tmpJSONObj = (JSONObject) arr.get(i); + tempCurrencyEntity.name = tmpJSONObj.getString("name"); + tempCurrencyEntity.code = tmpJSONObj.getString("code"); + tempCurrencyEntity.rate = (float) tmpJSONObj.getDouble("n"); + tempCurrencyEntity.symbol = new String(""); + if (tempCurrencyEntity.code.equalsIgnoreCase(selectedISO)) { + BRSharedPrefs.putIso(context, tempCurrencyEntity.code); + BRSharedPrefs.putCurrencyListPosition(context, i - 1); + } + set.add(tempCurrencyEntity); + } catch (JSONException e) { + Timber.e(e); + } + } + } else { + Timber.d("timber: getCurrencies: failed to get currencies"); + } + } catch (Exception e) { + Timber.e(e); + } + List tempList = new ArrayList<>(set); + Collections.reverse(tempList); + return new LinkedHashSet<>(set); + } + + + private void initializeTimerTask(final Context context) { + timerTask = new TimerTask() { + public void run() { + //use a handler to run a toast that shows the current timestamp + handler.post(new Runnable() { + public void run() { + BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { + @Override + public void run() { + Set tmp = getCurrencies((Activity) context); + CurrencyDataSource.getInstance(context).putCurrencies(tmp); + } + }); + } + }); + } + }; + } + + public void startTimer(Context context) { + //set a new Timer + if (timer != null) return; + timer = new Timer(); + + //initialize the TimerTask's job + initializeTimerTask(context); + + //schedule the timer, after the first 0ms the TimerTask will run every 60000ms + timer.schedule(timerTask, 0, 4000); + } + + public JSONArray fetchRates(Activity activity) { + String jsonString = createGETRequestURL(activity, BW_API_PROD_HOST + "/api/v1/rates"); + JSONArray jsonArray = null; + if (jsonString == null) return null; + try { + jsonArray = new JSONArray(jsonString); + // DEV Uncomment to view values + // Timber.d("timber: baseUrlProd: %s", getBaseUrlProd()); + // Timber.d("timber: JSON %s",jsonArray.toString()); + } catch (JSONException ex) { + Timber.e(ex); + } + if (jsonArray != null && !BuildConfig.DEBUG) { + AnalyticsManager.logCustomEvent(_20250222_PAC); + } + return jsonArray == null ? backupFetchRates(activity) : jsonArray; + } + + public JSONArray backupFetchRates(Activity activity) { + String jsonString = createGETRequestURL(activity, BW_API_DEV_HOST + "/api/v1/rates"); + + JSONArray jsonArray = null; + if (jsonString == null) return null; + try { + jsonArray = new JSONArray(jsonString); + + } catch (JSONException e) { + Timber.e(e); + } + if (jsonArray != null && !BuildConfig.DEBUG) { + AnalyticsManager.logCustomEvent(_20230113_BAC); + } + + return jsonArray; + } + + // createGETRequestURL + // Creates the params and headers to make a GET Request + private String createGETRequestURL(Context app, String myURL) { + Request request = new Request.Builder() + .url(myURL) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) + .get().build(); + String response = null; + Response resp = APIClient.getInstance(app).sendRequest(request, false, 0); + + try { + if (resp == null) { + Timber.i("timber: urlGET: %s resp is null", myURL); + return null; + } + ///Set timestamp to prefs + long timeStamp = new Date().getTime(); + BRSharedPrefs.putSecureTime(app, timeStamp); + + assert resp.body() != null; + response = resp.body().string(); + + } catch (IOException e) { + Timber.e(e); + } finally { + if (resp != null) resp.close(); + } + return response; + } + + public String getBaseUrlProd() { + return BW_API_PROD_HOST; + } +} diff --git a/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt b/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt index 4932a7fb..ba5c19ec 100644 --- a/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt +++ b/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt @@ -4,7 +4,7 @@ import android.app.Activity import android.content.Context import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.presenter.activities.util.ActivityUTILS -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.tools.util.Utils import com.platform.APIClient @@ -22,11 +22,11 @@ import org.junit.Test class BackupRateFetchTests { private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: APIManager + private lateinit var apiManager: BRApiManager @Before fun setUp() { - apiManager = spyk(APIManager(remoteConfigSource), recordPrivateCalls = true) + apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) } @Test diff --git a/app/src/test/java/com/brainwallet/data/BaseURLTests.kt b/app/src/test/java/com/brainwallet/data/BaseURLTests.kt index fa603bf2..d0163299 100644 --- a/app/src/test/java/com/brainwallet/data/BaseURLTests.kt +++ b/app/src/test/java/com/brainwallet/data/BaseURLTests.kt @@ -1,7 +1,7 @@ package com.brainwallet.data import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.util.BRConstants import io.mockk.every import io.mockk.mockk @@ -13,25 +13,20 @@ import org.junit.Test class BaseURLTests { private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: APIManager + private lateinit var apiManager: BRApiManager @Before fun setUp() { - apiManager = spyk(APIManager(remoteConfigSource), recordPrivateCalls = true) + apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) } @Test - fun `invoke getPRODBaseURL with KEY_API_BASEURL_PROD_NEW_ENABLED true, then should return new getPRODBaseURL`() { + fun `invoke getBaseUrlProd with KEY_API_BASEURL_PROD_NEW_ENABLED true, then should return new baseUrlProd`() { every { remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) } returns true - val actual = apiManager.getPRODBaseURL() - assertEquals(BRConstants.BW_API_PROD_HOST, actual) - } - @Test - fun `invoke getDEVBaseURL with KEY_API_BASEURL_DEV_NEW_ENABLED true, then should return new getDEVBaseURL`() { - every { remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_DEV_NEW_ENABLED) } returns true - val actual = apiManager.getDEVBaseURL() - assertEquals(BRConstants.BW_API_DEV_HOST, actual) + val actual = apiManager.baseUrlProd + + assertEquals(BRConstants.BW_API_PROD_HOST, actual) } } diff --git a/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt b/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt index 75af20f7..2386d1f0 100644 --- a/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt +++ b/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt @@ -4,7 +4,7 @@ import android.app.Activity import android.content.Context import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.presenter.activities.util.ActivityUTILS -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.platform.APIClient import io.mockk.every import io.mockk.mockk @@ -22,11 +22,11 @@ import org.junit.Test class ProdAPIManagerTests { private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: APIManager + private lateinit var apiManager: BRApiManager @Before fun setUp() { - apiManager = spyk(APIManager(remoteConfigSource), recordPrivateCalls = true) + apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) } @Test @@ -85,17 +85,17 @@ class ProdAPIManagerTests { .body(responseString.toResponseBody()) .build() - val currencyEntityList = apiManager.fetchRates(activity) - val jsonUSD = currencyEntityList?.get(154) - val jsonEUR = currencyEntityList?.get(49) - val jsonGBP = currencyEntityList?.get(52) + val result = apiManager.fetchRates(activity) + val jsonUSD = result.getJSONObject(154) + val jsonEUR = result.getJSONObject(49) + val jsonGBP = result.getJSONObject(52) - assertEquals("USD", jsonUSD?.code) - assertEquals("US Dollar", jsonUSD?.name) - assertEquals("EUR", jsonEUR?.code) - assertEquals("Euro", jsonEUR?.name) - assertEquals("GBP", jsonGBP?.code) - assertEquals("British Pound Sterling", jsonGBP?.name) + assertEquals("USD", jsonUSD.optString("code")) + assertEquals("US Dollar", jsonUSD.optString("name")) + assertEquals("EUR", jsonEUR.optString("code")) + assertEquals("Euro", jsonEUR.optString("name")) + assertEquals("GBP", jsonGBP.optString("code")) + assertEquals("British Pound Sterling", jsonGBP.optString("name")) ///DEV: Very flaky test not enough time for the response verifyAll { From 638ce3a3b76b7114b60ef6dc8f398dc26b8e2b25 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 31 Mar 2025 19:09:11 +0100 Subject: [PATCH 02/65] Reverted the Kotlin APIManager. --- app/build.gradle.kts | 4 +- .../brainwallet/tools/manager/APIManager.kt | 119 ------------------ 2 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 app/src/main/java/com/brainwallet/tools/manager/APIManager.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7922396b..7d06d2e7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202503281 - versionName = "v4.4.1" + versionCode = 202503312 + versionName = "v4.4.3" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/src/main/java/com/brainwallet/tools/manager/APIManager.kt b/app/src/main/java/com/brainwallet/tools/manager/APIManager.kt deleted file mode 100644 index fe3b2072..00000000 --- a/app/src/main/java/com/brainwallet/tools/manager/APIManager.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.brainwallet.tools.manager - -import android.app.Activity -import android.content.Context -import com.brainwallet.data.model.CurrencyEntity -import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.presenter.entities.ServiceItems -import com.brainwallet.tools.sqlite.CurrencyDataSource -import com.brainwallet.tools.util.BRConstants.BW_API_DEV_HOST -import com.brainwallet.tools.util.BRConstants.BW_API_PROD_HOST -import com.brainwallet.tools.util.Utils -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import okhttp3.OkHttpClient -import okhttp3.Request -import com.squareup.moshi.Moshi -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Types -import timber.log.Timber -import java.io.IOException -import java.util.* -import kotlin.collections.LinkedHashSet - -class APIManager (private val remoteConfigSource: RemoteConfigSource) { - fun getPRODBaseURL(): String = BW_API_PROD_HOST - fun getDEVBaseURL(): String = BW_API_DEV_HOST - - private var timer: Timer? = null - private var pollPeriod : Long = 5000 - - private val client = OkHttpClient() - private val moshi: Moshi = Moshi.Builder().build() - private val type = Types.newParameterizedType(List::class.java, CurrencyEntity::class.java) - private val jsonAdapter: JsonAdapter> = moshi.adapter(type) - - fun getCurrencies(context: Activity): Set { - val set = LinkedHashSet() - try { - val arr = fetchRates(context) - FeeManager.updateFeePerKb(context) - arr?.let { currencyList -> - val selectedISO = BRSharedPrefs.getIsoSymbol(context) - currencyList.forEachIndexed { i, tempCurrencyEntity -> - if (tempCurrencyEntity.code.equals(selectedISO, ignoreCase = true)) { - BRSharedPrefs.putIso(context, tempCurrencyEntity.code) - BRSharedPrefs.putCurrencyListPosition(context, i - 1) - } - set.add(tempCurrencyEntity) - } - } ?: Timber.d("timber: getCurrencies: failed to get currencies") - } catch (e: Exception) { - Timber.e(e) - } - return set.reversed().toSet() - } - - private fun initializeTimerTask(context: Context) { - timer = Timer().apply { - schedule(object : TimerTask() { - override fun run() { - CoroutineScope(Dispatchers.IO).launch { - val tmp = getCurrencies(context as Activity) - withContext(Dispatchers.Main) { - CurrencyDataSource.getInstance(context).putCurrencies(tmp) - } - } - } - }, 0, pollPeriod) - } - } - - fun startTimer(context: Context) { - if (timer != null) return - initializeTimerTask(context) - } - - fun fetchRates(activity: Activity): List? { - val jsonString = createGETRequestURL(activity, "$BW_API_PROD_HOST/api/v1/rates") - return parseJsonArray(jsonString) ?: backupFetchRates(activity) - } - - private fun backupFetchRates(activity: Activity): List? { - val jsonString = createGETRequestURL(activity, "$BW_API_DEV_HOST/api/v1/rates") - return parseJsonArray(jsonString) - } - - private fun parseJsonArray(jsonString: String?): List? { - return try { - jsonString?.let { jsonAdapter.fromJson(it) } - } catch (e: IOException) { - Timber.e(e) - null - } - } - - private fun createGETRequestURL(app: Context, url: String): String? { - val request = Request.Builder() - .url(url) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) - .header("bw-client-code", Utils.fetchServiceItem(app, ServiceItems.CLIENTCODE)) - .get() - .build() - - return try { - client.newCall(request).execute().use { response -> - response.body?.string().also { - BRSharedPrefs.putSecureTime(app, System.currentTimeMillis()) - } - } - } catch (e: IOException) { - Timber.e(e) - null - } - } -} From 5344a96a6a0c56895945e7e8d0005eee30dbfd39 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 31 Mar 2025 19:43:55 +0100 Subject: [PATCH 03/65] Add version and code to welcome screen --- .../ui/screens/welcome/WelcomeScreen.kt | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index 370b9574..4472eb38 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -41,6 +41,7 @@ import com.brainwallet.R import com.brainwallet.navigation.OnNavigate import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect +import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.composable.BorderedLargeButton import com.brainwallet.ui.composable.BrainwalletButton import com.brainwallet.ui.composable.DarkModeToggleButton @@ -75,7 +76,7 @@ fun WelcomeScreen( val halfLeadTrailPadding = leadTrailPadding / 2 val doubleLeadTrailPadding = leadTrailPadding * 2 val rowPadding = 8 - val activeRowHeight = 70 + val activeRowHeight = 58 val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.welcomeemoji20250212)) val progress by animateLottieCompositionAsState( @@ -91,7 +92,7 @@ fun WelcomeScreen( verticalArrangement = Arrangement.SpaceBetween ) { - Spacer(modifier = Modifier.weight(0.4f)) + Spacer(modifier = Modifier.weight(0.2f)) Image( painterResource(R.drawable.brainwallet_logotype_white), @@ -125,15 +126,16 @@ fun WelcomeScreen( modifier = Modifier .fillMaxWidth() .height(activeRowHeight.dp) - .padding(horizontal = halfLeadTrailPadding.dp) + .padding(horizontal = leadTrailPadding.dp) .padding(vertical = rowPadding.dp), horizontalArrangement = Arrangement.SpaceEvenly ) { - Spacer(modifier = Modifier.weight(0.1f)) - + BrainwalletButton( - modifier = Modifier.weight(0.9f), + modifier = Modifier + .weight(1f) + .fillMaxWidth(), onClick = { viewModel.onEvent(WelcomeEvent.OnLanguageSelectorButtonClick) } @@ -145,7 +147,7 @@ fun WelcomeScreen( ) } - Spacer(modifier = Modifier.weight(0.2f)) + Spacer(modifier = Modifier.weight(0.1f)) DarkModeToggleButton( modifier = Modifier @@ -157,10 +159,12 @@ fun WelcomeScreen( } ) - Spacer(modifier = Modifier.weight(0.2f)) + Spacer(modifier = Modifier.weight(0.1f)) BrainwalletButton( - modifier = Modifier.weight(0.9f), + modifier = Modifier + .weight(1f) + .fillMaxWidth(), onClick = { viewModel.onEvent(WelcomeEvent.OnFiatButtonClick) } ) { Text( @@ -170,8 +174,6 @@ fun WelcomeScreen( ) } - Spacer(modifier = Modifier.weight(0.1f)) - } // Ready Button BorderedLargeButton( @@ -180,7 +182,7 @@ fun WelcomeScreen( }, shape = RoundedCornerShape(50), modifier = Modifier - .padding(horizontal = halfLeadTrailPadding.dp) + .padding(horizontal = leadTrailPadding.dp) .padding(vertical = rowPadding.dp) .height(activeRowHeight.dp) @@ -199,7 +201,7 @@ fun WelcomeScreen( }, shape = RoundedCornerShape(50), modifier = Modifier - .padding(horizontal = halfLeadTrailPadding.dp) + .padding(horizontal = leadTrailPadding.dp) .padding(vertical = rowPadding.dp) .height(activeRowHeight.dp) .clip(RoundedCornerShape(50)) @@ -211,6 +213,12 @@ fun WelcomeScreen( ) } + Text( modifier = Modifier + .padding(vertical = 8.dp), + text = BRConstants.APP_VERSION_NAME_CODE, + fontSize = 13.sp, + color = BrainwalletTheme.colors.content + ) Spacer(modifier = Modifier.weight(0.5f)) } From ebc3bb9a47dbb8d1e0fe9af6ddb9ee14e959a1cf Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 31 Mar 2025 19:48:18 +0100 Subject: [PATCH 04/65] reset padding --- .../com/brainwallet/ui/screens/welcome/WelcomeScreen.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index 4472eb38..f4d8ba3a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -76,6 +76,7 @@ fun WelcomeScreen( val halfLeadTrailPadding = leadTrailPadding / 2 val doubleLeadTrailPadding = leadTrailPadding * 2 val rowPadding = 8 + val versionPadding = 12 val activeRowHeight = 58 val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.welcomeemoji20250212)) @@ -131,7 +132,7 @@ fun WelcomeScreen( horizontalArrangement = Arrangement.SpaceEvenly ) { - + BrainwalletButton( modifier = Modifier .weight(1f) @@ -214,12 +215,11 @@ fun WelcomeScreen( } Text( modifier = Modifier - .padding(vertical = 8.dp), + .padding(vertical = versionPadding.dp), text = BRConstants.APP_VERSION_NAME_CODE, fontSize = 13.sp, color = BrainwalletTheme.colors.content ) - Spacer(modifier = Modifier.weight(0.5f)) } //language selector From c770f01549d7d1847a6672bbb97b247fd7ab1a40 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 31 Mar 2025 17:57:14 +0100 Subject: [PATCH 05/65] Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt --- app/build.gradle.kts | 1 - .../data/model/CurrencyEntity.java | 6 +- .../main/java/com/brainwallet/di/Module.kt | 4 +- .../presenter/activities/util/BRActivity.java | 4 +- .../tools/manager/BRApiManager.java | 317 +++++++++--------- .../currency/BackupRateFetchTests.kt | 6 +- .../java/com/brainwallet/data/BaseURLTests.kt | 19 +- .../tools/util/ProdAPIManagerTests.kt | 26 +- 8 files changed, 185 insertions(+), 198 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d20ad2c8..7922396b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -188,7 +188,6 @@ dependencies { } implementation("androidx.webkit:webkit:1.9.0") - implementation("com.squareup.moshi:moshi-kotlin:1.15.2") implementation(libs.androidx.core) implementation(libs.androidx.appcompat) implementation(libs.androidx.legacy.support) diff --git a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java index 319ed216..f0c31051 100644 --- a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java +++ b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java @@ -5,13 +5,13 @@ public class CurrencyEntity implements Serializable { //Change this after modifying the class - private static final long serialVersionUID = 7526472295622777000L; + private static final long serialVersionUID = 7526472295622776147L; public static final String TAG = CurrencyEntity.class.getName(); public String code; - public String name = ""; + public String name; public float rate; - public String symbol = ""; + public String symbol; public CurrencyEntity(String code, String name, float rate, String symbol) { this.code = code; diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 05db629b..75a2cf5f 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -5,7 +5,7 @@ import android.content.SharedPreferences import com.brainwallet.BuildConfig import com.brainwallet.data.repository.SettingRepository import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.ui.screens.home.SettingsViewModel import com.brainwallet.ui.screens.inputwords.InputWordsViewModel @@ -32,7 +32,7 @@ val dataModule = module { it.initialize() } } - single { APIManager(get()) } + single { BRApiManager(get()) } single { CurrencyDataSource.getInstance(get()) } single { provideSharedPreferences(context = androidApplication()) } single { SettingRepository.Impl(get(), get()) } diff --git a/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java index bd118415..6f62d97c 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java @@ -16,7 +16,7 @@ import com.brainwallet.presenter.activities.intro.RecoverActivity; import com.brainwallet.presenter.activities.intro.WriteDownActivity; import com.brainwallet.tools.animation.BRAnimator; -import com.brainwallet.tools.manager.APIManager; +import com.brainwallet.tools.manager.BRApiManager; import com.brainwallet.tools.manager.InternetManager; import com.brainwallet.tools.security.AuthManager; import com.brainwallet.tools.security.BRKeyStore; @@ -148,7 +148,7 @@ public static void init(Activity app) { if (!(app instanceof RecoverActivity || app instanceof WriteDownActivity)) { - APIManager apiManager = KoinJavaComponent.get(APIManager.class); + BRApiManager apiManager = KoinJavaComponent.get(BRApiManager.class); apiManager.startTimer(app); } diff --git a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java index e298b178..9b7a81de 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java @@ -30,7 +30,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; -import java.util.Optional; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -38,164 +37,158 @@ import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; -// -//public class BRApiManager { -// private Timer timer; -// -// private TimerTask timerTask; -// -// private Handler handler; -// -// private RemoteConfigSource remoteConfigSource; -// -// public BRApiManager(RemoteConfigSource remoteConfigSource) { -// this.remoteConfigSource = remoteConfigSource; -// this.handler = new Handler(); -// } -// -// private Set getCurrencies(Activity context) { -// Set set = new LinkedHashSet<>(); -// try { -// JSONArray arr = fetchRates(context); -// FeeManager.updateFeePerKb(context); -// if (arr != null) { -// String selectedISO = BRSharedPrefs.getIsoSymbol(context); -// int length = arr.length(); -// for (int i = 0; i < length; i++) { -// CurrencyEntity tempCurrencyEntity = new CurrencyEntity(); -// try { -// JSONObject tmpJSONObj = (JSONObject) arr.get(i); -// tempCurrencyEntity.name = "no_currency_name"; -// if (tmpJSONObj.getString("name").toString() != null) { -// tempCurrencyEntity.name = tmpJSONObj.getString("name"); -// } -// tempCurrencyEntity.code = tmpJSONObj.getString("code"); -// tempCurrencyEntity.rate = (float) tmpJSONObj.getDouble("n"); -// tempCurrencyEntity.symbol = new String(""); -// if (tempCurrencyEntity.code.equalsIgnoreCase(selectedISO)) { -// BRSharedPrefs.putIso(context, tempCurrencyEntity.code); -// BRSharedPrefs.putCurrencyListPosition(context, i - 1); -// } -// set.add(tempCurrencyEntity); -// Timber.d(":::timber: CE: %s",tempCurrencyEntity.code); -// -// } catch (JSONException e) { -// ///Timber.e(e); -// // Timber.d(":::timber: ERROR: %s",e); -// } -// } -// } else { -// Timber.d("timber: getCurrencies: failed to get currencies"); -// } -// } catch (Exception e) { -// Timber.e(e); -// } -// List tempList = new ArrayList<>(set); -// Collections.reverse(tempList); -// return new LinkedHashSet<>(set); -// } -// -// -// private void initializeTimerTask(final Context context) { -// timerTask = new TimerTask() { -// public void run() { -// //use a handler to run a toast that shows the current timestamp -// handler.post(new Runnable() { -// public void run() { -// BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { -// @Override -// public void run() { -// Set tmp = getCurrencies((Activity) context); -// CurrencyDataSource.getInstance(context).putCurrencies(tmp); -// } -// }); -// } -// }); -// } -// }; -// } -// -// public void startTimer(Context context) { -// //set a new Timer -// if (timer != null) return; -// timer = new Timer(); -// -// //initialize the TimerTask's job -// initializeTimerTask(context); -// -// //schedule the timer, after the first 0ms the TimerTask will run every 60000ms -// timer.schedule(timerTask, 0, 4000); -// } -// -// public JSONArray fetchRates(Activity activity) { -// String jsonString = createGETRequestURL(activity, BW_API_PROD_HOST + "/api/v1/rates"); -// JSONArray jsonArray = null; -// if (jsonString == null) return null; -// try { -// jsonArray = new JSONArray(jsonString); -// // DEV Uncomment to view values -// // Timber.d("timber: baseUrlProd: %s", getBaseUrlProd()); -// // Timber.d("timber: JSON %s",jsonArray.toString()); -// } catch (JSONException ex) { -// Timber.e(ex); -// } -// if (jsonArray != null && !BuildConfig.DEBUG) { -// AnalyticsManager.logCustomEvent(_20250222_PAC); -// } -// return jsonArray == null ? backupFetchRates(activity) : jsonArray; -// } -// -// public JSONArray backupFetchRates(Activity activity) { -// String jsonString = createGETRequestURL(activity, BW_API_DEV_HOST + "/api/v1/rates"); -// -// JSONArray jsonArray = null; -// if (jsonString == null) return null; -// try { -// jsonArray = new JSONArray(jsonString); -// -// } catch (JSONException e) { -// Timber.e(e); -// } -// if (jsonArray != null && !BuildConfig.DEBUG) { -// AnalyticsManager.logCustomEvent(_20230113_BAC); -// } -// -// return jsonArray; -// } -// -// // createGETRequestURL -// // Creates the params and headers to make a GET Request -// private String createGETRequestURL(Context app, String myURL) { -// Request request = new Request.Builder() -// .url(myURL) -// .header("Content-Type", "application/json") -// .header("Accept", "application/json") -// .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) -// .get().build(); -// String response = null; -// Response resp = APIClient.getInstance(app).sendRequest(request, false, 0); -// -// try { -// if (resp == null) { -// Timber.i("timber: urlGET: %s resp is null", myURL); -// return null; -// } -// ///Set timestamp to prefs -// long timeStamp = new Date().getTime(); -// BRSharedPrefs.putSecureTime(app, timeStamp); -// -// assert resp.body() != null; -// response = resp.body().string(); -// -// } catch (IOException e) { -// Timber.e(e); -// } finally { -// if (resp != null) resp.close(); -// } -// return response; -// } -// -// public String getBaseUrlProd() { -// return BW_API_PROD_HOST; -// } -//} + +public class BRApiManager { + private Timer timer; + + private TimerTask timerTask; + + private Handler handler; + + private RemoteConfigSource remoteConfigSource; + + public BRApiManager(RemoteConfigSource remoteConfigSource) { + this.remoteConfigSource = remoteConfigSource; + this.handler = new Handler(); + } + + private Set getCurrencies(Activity context) { + Set set = new LinkedHashSet<>(); + try { + JSONArray arr = fetchRates(context); + FeeManager.updateFeePerKb(context); + if (arr != null) { + String selectedISO = BRSharedPrefs.getIsoSymbol(context); + int length = arr.length(); + for (int i = 0; i < length; i++) { + CurrencyEntity tempCurrencyEntity = new CurrencyEntity(); + try { + JSONObject tmpJSONObj = (JSONObject) arr.get(i); + tempCurrencyEntity.name = tmpJSONObj.getString("name"); + tempCurrencyEntity.code = tmpJSONObj.getString("code"); + tempCurrencyEntity.rate = (float) tmpJSONObj.getDouble("n"); + tempCurrencyEntity.symbol = new String(""); + if (tempCurrencyEntity.code.equalsIgnoreCase(selectedISO)) { + BRSharedPrefs.putIso(context, tempCurrencyEntity.code); + BRSharedPrefs.putCurrencyListPosition(context, i - 1); + } + set.add(tempCurrencyEntity); + } catch (JSONException e) { + Timber.e(e); + } + } + } else { + Timber.d("timber: getCurrencies: failed to get currencies"); + } + } catch (Exception e) { + Timber.e(e); + } + List tempList = new ArrayList<>(set); + Collections.reverse(tempList); + return new LinkedHashSet<>(set); + } + + + private void initializeTimerTask(final Context context) { + timerTask = new TimerTask() { + public void run() { + //use a handler to run a toast that shows the current timestamp + handler.post(new Runnable() { + public void run() { + BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { + @Override + public void run() { + Set tmp = getCurrencies((Activity) context); + CurrencyDataSource.getInstance(context).putCurrencies(tmp); + } + }); + } + }); + } + }; + } + + public void startTimer(Context context) { + //set a new Timer + if (timer != null) return; + timer = new Timer(); + + //initialize the TimerTask's job + initializeTimerTask(context); + + //schedule the timer, after the first 0ms the TimerTask will run every 60000ms + timer.schedule(timerTask, 0, 4000); + } + + public JSONArray fetchRates(Activity activity) { + String jsonString = createGETRequestURL(activity, BW_API_PROD_HOST + "/api/v1/rates"); + JSONArray jsonArray = null; + if (jsonString == null) return null; + try { + jsonArray = new JSONArray(jsonString); + // DEV Uncomment to view values + // Timber.d("timber: baseUrlProd: %s", getBaseUrlProd()); + // Timber.d("timber: JSON %s",jsonArray.toString()); + } catch (JSONException ex) { + Timber.e(ex); + } + if (jsonArray != null && !BuildConfig.DEBUG) { + AnalyticsManager.logCustomEvent(_20250222_PAC); + } + return jsonArray == null ? backupFetchRates(activity) : jsonArray; + } + + public JSONArray backupFetchRates(Activity activity) { + String jsonString = createGETRequestURL(activity, BW_API_DEV_HOST + "/api/v1/rates"); + + JSONArray jsonArray = null; + if (jsonString == null) return null; + try { + jsonArray = new JSONArray(jsonString); + + } catch (JSONException e) { + Timber.e(e); + } + if (jsonArray != null && !BuildConfig.DEBUG) { + AnalyticsManager.logCustomEvent(_20230113_BAC); + } + + return jsonArray; + } + + // createGETRequestURL + // Creates the params and headers to make a GET Request + private String createGETRequestURL(Context app, String myURL) { + Request request = new Request.Builder() + .url(myURL) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) + .get().build(); + String response = null; + Response resp = APIClient.getInstance(app).sendRequest(request, false, 0); + + try { + if (resp == null) { + Timber.i("timber: urlGET: %s resp is null", myURL); + return null; + } + ///Set timestamp to prefs + long timeStamp = new Date().getTime(); + BRSharedPrefs.putSecureTime(app, timeStamp); + + assert resp.body() != null; + response = resp.body().string(); + + } catch (IOException e) { + Timber.e(e); + } finally { + if (resp != null) resp.close(); + } + return response; + } + + public String getBaseUrlProd() { + return BW_API_PROD_HOST; + } +} diff --git a/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt b/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt index 4932a7fb..ba5c19ec 100644 --- a/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt +++ b/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt @@ -4,7 +4,7 @@ import android.app.Activity import android.content.Context import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.presenter.activities.util.ActivityUTILS -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.tools.util.Utils import com.platform.APIClient @@ -22,11 +22,11 @@ import org.junit.Test class BackupRateFetchTests { private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: APIManager + private lateinit var apiManager: BRApiManager @Before fun setUp() { - apiManager = spyk(APIManager(remoteConfigSource), recordPrivateCalls = true) + apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) } @Test diff --git a/app/src/test/java/com/brainwallet/data/BaseURLTests.kt b/app/src/test/java/com/brainwallet/data/BaseURLTests.kt index fa603bf2..d0163299 100644 --- a/app/src/test/java/com/brainwallet/data/BaseURLTests.kt +++ b/app/src/test/java/com/brainwallet/data/BaseURLTests.kt @@ -1,7 +1,7 @@ package com.brainwallet.data import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.util.BRConstants import io.mockk.every import io.mockk.mockk @@ -13,25 +13,20 @@ import org.junit.Test class BaseURLTests { private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: APIManager + private lateinit var apiManager: BRApiManager @Before fun setUp() { - apiManager = spyk(APIManager(remoteConfigSource), recordPrivateCalls = true) + apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) } @Test - fun `invoke getPRODBaseURL with KEY_API_BASEURL_PROD_NEW_ENABLED true, then should return new getPRODBaseURL`() { + fun `invoke getBaseUrlProd with KEY_API_BASEURL_PROD_NEW_ENABLED true, then should return new baseUrlProd`() { every { remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) } returns true - val actual = apiManager.getPRODBaseURL() - assertEquals(BRConstants.BW_API_PROD_HOST, actual) - } - @Test - fun `invoke getDEVBaseURL with KEY_API_BASEURL_DEV_NEW_ENABLED true, then should return new getDEVBaseURL`() { - every { remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_DEV_NEW_ENABLED) } returns true - val actual = apiManager.getDEVBaseURL() - assertEquals(BRConstants.BW_API_DEV_HOST, actual) + val actual = apiManager.baseUrlProd + + assertEquals(BRConstants.BW_API_PROD_HOST, actual) } } diff --git a/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt b/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt index 75af20f7..2386d1f0 100644 --- a/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt +++ b/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt @@ -4,7 +4,7 @@ import android.app.Activity import android.content.Context import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.presenter.activities.util.ActivityUTILS -import com.brainwallet.tools.manager.APIManager +import com.brainwallet.tools.manager.BRApiManager import com.platform.APIClient import io.mockk.every import io.mockk.mockk @@ -22,11 +22,11 @@ import org.junit.Test class ProdAPIManagerTests { private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: APIManager + private lateinit var apiManager: BRApiManager @Before fun setUp() { - apiManager = spyk(APIManager(remoteConfigSource), recordPrivateCalls = true) + apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) } @Test @@ -85,17 +85,17 @@ class ProdAPIManagerTests { .body(responseString.toResponseBody()) .build() - val currencyEntityList = apiManager.fetchRates(activity) - val jsonUSD = currencyEntityList?.get(154) - val jsonEUR = currencyEntityList?.get(49) - val jsonGBP = currencyEntityList?.get(52) + val result = apiManager.fetchRates(activity) + val jsonUSD = result.getJSONObject(154) + val jsonEUR = result.getJSONObject(49) + val jsonGBP = result.getJSONObject(52) - assertEquals("USD", jsonUSD?.code) - assertEquals("US Dollar", jsonUSD?.name) - assertEquals("EUR", jsonEUR?.code) - assertEquals("Euro", jsonEUR?.name) - assertEquals("GBP", jsonGBP?.code) - assertEquals("British Pound Sterling", jsonGBP?.name) + assertEquals("USD", jsonUSD.optString("code")) + assertEquals("US Dollar", jsonUSD.optString("name")) + assertEquals("EUR", jsonEUR.optString("code")) + assertEquals("Euro", jsonEUR.optString("name")) + assertEquals("GBP", jsonGBP.optString("code")) + assertEquals("British Pound Sterling", jsonGBP.optString("name")) ///DEV: Very flaky test not enough time for the response verifyAll { From f8c1bd50ca6d4031a27060dad4c337a0660c36ea Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 31 Mar 2025 19:09:11 +0100 Subject: [PATCH 06/65] Reverted the Kotlin APIManager. --- app/build.gradle.kts | 4 +- .../brainwallet/tools/manager/APIManager.kt | 119 ------------------ 2 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 app/src/main/java/com/brainwallet/tools/manager/APIManager.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7922396b..7d06d2e7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202503281 - versionName = "v4.4.1" + versionCode = 202503312 + versionName = "v4.4.3" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/src/main/java/com/brainwallet/tools/manager/APIManager.kt b/app/src/main/java/com/brainwallet/tools/manager/APIManager.kt deleted file mode 100644 index fe3b2072..00000000 --- a/app/src/main/java/com/brainwallet/tools/manager/APIManager.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.brainwallet.tools.manager - -import android.app.Activity -import android.content.Context -import com.brainwallet.data.model.CurrencyEntity -import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.presenter.entities.ServiceItems -import com.brainwallet.tools.sqlite.CurrencyDataSource -import com.brainwallet.tools.util.BRConstants.BW_API_DEV_HOST -import com.brainwallet.tools.util.BRConstants.BW_API_PROD_HOST -import com.brainwallet.tools.util.Utils -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import okhttp3.OkHttpClient -import okhttp3.Request -import com.squareup.moshi.Moshi -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.Types -import timber.log.Timber -import java.io.IOException -import java.util.* -import kotlin.collections.LinkedHashSet - -class APIManager (private val remoteConfigSource: RemoteConfigSource) { - fun getPRODBaseURL(): String = BW_API_PROD_HOST - fun getDEVBaseURL(): String = BW_API_DEV_HOST - - private var timer: Timer? = null - private var pollPeriod : Long = 5000 - - private val client = OkHttpClient() - private val moshi: Moshi = Moshi.Builder().build() - private val type = Types.newParameterizedType(List::class.java, CurrencyEntity::class.java) - private val jsonAdapter: JsonAdapter> = moshi.adapter(type) - - fun getCurrencies(context: Activity): Set { - val set = LinkedHashSet() - try { - val arr = fetchRates(context) - FeeManager.updateFeePerKb(context) - arr?.let { currencyList -> - val selectedISO = BRSharedPrefs.getIsoSymbol(context) - currencyList.forEachIndexed { i, tempCurrencyEntity -> - if (tempCurrencyEntity.code.equals(selectedISO, ignoreCase = true)) { - BRSharedPrefs.putIso(context, tempCurrencyEntity.code) - BRSharedPrefs.putCurrencyListPosition(context, i - 1) - } - set.add(tempCurrencyEntity) - } - } ?: Timber.d("timber: getCurrencies: failed to get currencies") - } catch (e: Exception) { - Timber.e(e) - } - return set.reversed().toSet() - } - - private fun initializeTimerTask(context: Context) { - timer = Timer().apply { - schedule(object : TimerTask() { - override fun run() { - CoroutineScope(Dispatchers.IO).launch { - val tmp = getCurrencies(context as Activity) - withContext(Dispatchers.Main) { - CurrencyDataSource.getInstance(context).putCurrencies(tmp) - } - } - } - }, 0, pollPeriod) - } - } - - fun startTimer(context: Context) { - if (timer != null) return - initializeTimerTask(context) - } - - fun fetchRates(activity: Activity): List? { - val jsonString = createGETRequestURL(activity, "$BW_API_PROD_HOST/api/v1/rates") - return parseJsonArray(jsonString) ?: backupFetchRates(activity) - } - - private fun backupFetchRates(activity: Activity): List? { - val jsonString = createGETRequestURL(activity, "$BW_API_DEV_HOST/api/v1/rates") - return parseJsonArray(jsonString) - } - - private fun parseJsonArray(jsonString: String?): List? { - return try { - jsonString?.let { jsonAdapter.fromJson(it) } - } catch (e: IOException) { - Timber.e(e) - null - } - } - - private fun createGETRequestURL(app: Context, url: String): String? { - val request = Request.Builder() - .url(url) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) - .header("bw-client-code", Utils.fetchServiceItem(app, ServiceItems.CLIENTCODE)) - .get() - .build() - - return try { - client.newCall(request).execute().use { response -> - response.body?.string().also { - BRSharedPrefs.putSecureTime(app, System.currentTimeMillis()) - } - } - } catch (e: IOException) { - Timber.e(e) - null - } - } -} From ff58b57c1d2150cf791bd4a3da4fb6ec6a8ec67a Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Sat, 5 Apr 2025 00:19:01 +0700 Subject: [PATCH 07/65] fix: fix crash when FragmentSignal dismissed --- .../com/brainwallet/presenter/fragments/FragmentSignal.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java index 05bbed1e..bf936591 100644 --- a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java +++ b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java @@ -13,6 +13,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import com.brainwallet.R; @@ -20,7 +21,7 @@ import timber.log.Timber; -public class FragmentSignal extends Fragment { +public class FragmentSignal extends DialogFragment { public static final String TITLE = "title"; public static final String ICON_DESCRIPTION = "iconDescription"; public static final String RES_ID = "resId"; @@ -34,7 +35,7 @@ public class FragmentSignal extends Fragment { @Override public void run() { if (isAdded()) { - getParentFragmentManager().popBackStack(); + dismiss(); handler.postDelayed(completionRunnable, 300); } } From d64ea930d45d0adeabf2a97d4d7f7070ba15d62e Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Mon, 7 Apr 2025 10:39:48 +0700 Subject: [PATCH 08/65] fix: fix sync after wipe --- .../com/brainwallet/tools/manager/SyncManager.java | 2 +- .../ui/screens/inputwords/InputWordsViewModel.kt | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java b/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java index 924c6fc6..42e195f5 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java @@ -22,7 +22,7 @@ public class SyncManager { private static SyncManager instance; private static final long SYNC_PERIOD = TimeUnit.HOURS.toMillis(24); private static SyncProgressTask syncTask; - public boolean running; + public volatile boolean running; public static SyncManager getInstance() { if (instance == null) instance = new SyncManager(); diff --git a/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt index bb2243dc..7da2b003 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt @@ -94,12 +94,12 @@ class InputWordsViewModel : BrainwalletViewModel() { return } - BRWalletManager.getInstance().run { - wipeWalletButKeystore(event.context) - wipeKeyStore(event.context) - PostAuth.getInstance().setPhraseForKeyStore(cleanPhrase) - BRSharedPrefs.putAllowSpend(event.context, false) - } + BRWalletManager.getInstance().wipeAll(event.context) + + BRSharedPrefs.putAllowSpend(event.context, false) + BRSharedPrefs.putStartHeight(event.context, 0) + + PostAuth.getInstance().setPhraseForKeyStore(cleanPhrase) viewModelScope.launch { EventBus.emit(EventBus.Event.Message(EFFECT_LEGACY_RECOVER_WALLET_AUTH)) From 9a8a20f6b636543858d5592897d61b9b86f28762 Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Tue, 8 Apr 2025 05:49:27 +0700 Subject: [PATCH 09/65] fix: fix wrong lifecycle to trigger callback at FragmentSignal --- .../presenter/fragments/FragmentSignal.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java index bf936591..4c136b41 100644 --- a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java +++ b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java @@ -14,13 +14,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; import com.brainwallet.R; import com.brainwallet.presenter.interfaces.BROnSignalCompletion; -import timber.log.Timber; - public class FragmentSignal extends DialogFragment { public static final String TITLE = "title"; public static final String ICON_DESCRIPTION = "iconDescription"; @@ -34,10 +31,8 @@ public class FragmentSignal extends DialogFragment { private final Runnable popBackStackRunnable = new Runnable() { @Override public void run() { - if (isAdded()) { - dismiss(); - handler.postDelayed(completionRunnable, 300); - } + dismiss(); + handler.postDelayed(completionRunnable, 300); } }; @@ -88,8 +83,8 @@ public void run() { }; @Override - public void onDestroyView() { - super.onDestroyView(); + public void onDestroy() { + super.onDestroy(); // Remove callbacks to prevent execution after the fragment is destroyed handler.removeCallbacks(popBackStackRunnable); handler.removeCallbacks(completionRunnable); From 832fa36a00f21e511c4cdfddfb89ccd7c8f010d9 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Tue, 8 Apr 2025 09:28:37 +0100 Subject: [PATCH 10/65] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..dd84ea78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From b294cd602138cf934863c6cecdd266ed691cc54a Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Tue, 8 Apr 2025 20:52:44 +0100 Subject: [PATCH 11/65] updated core changes per @andhikayuana --- app/src/main/jni/core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/jni/core b/app/src/main/jni/core index 5b9905a7..86649c2d 160000 --- a/app/src/main/jni/core +++ b/app/src/main/jni/core @@ -1 +1 @@ -Subproject commit 5b9905a72205a461e0a9935dce22f516d59e752e +Subproject commit 86649c2dd89d4c1e13fb58de4aa07567f3ac11bd From 089995ada123903b9848d0924e868558fe10c8de Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Fri, 11 Apr 2025 13:17:03 +0700 Subject: [PATCH 12/65] Rename .java to .kt --- .../data/model/{CurrencyEntity.java => CurrencyEntity.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/brainwallet/data/model/{CurrencyEntity.java => CurrencyEntity.kt} (100%) diff --git a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt similarity index 100% rename from app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java rename to app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt From 7e85987bf446994eb9a648d85517d730898bf99c Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Fri, 11 Apr 2025 13:17:07 +0700 Subject: [PATCH 13/65] chore: refactor BRApiManager & APIClient --- app/build.gradle.kts | 4 +- .../brainwallet/data/model/CurrencyEntity.kt | 61 ++++-- .../data/repository/LtcRepository.kt | 40 ++++ .../data/source/RemoteApiSource.kt | 17 ++ .../main/java/com/brainwallet/di/Module.kt | 76 ++++++- .../presenter/activities/util/BRActivity.java | 11 +- .../tools/manager/BRApiManager.java | 194 ------------------ .../brainwallet/tools/manager/FeeManager.java | 1 + .../worker/CurrencyUpdateWorker.kt | 32 +++ app/src/main/java/com/platform/APIClient.java | 1 + .../currency/BackupRateFetchTests.kt | 140 ++++++------- .../java/com/brainwallet/data/BaseURLTests.kt | 34 +-- .../tools/util/ProdAPIManagerTests.kt | 170 +++++++-------- gradle/libs.versions.toml | 13 +- 14 files changed, 390 insertions(+), 404 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt delete mode 100644 app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java create mode 100644 app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7d06d2e7..b8f91239 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -216,7 +216,9 @@ dependencies { implementation(platform(libs.koin.bom)) implementation(libs.bundles.koin) - implementation(libs.squareup.okhttp) + implementation(platform(libs.squareup.okhttp.bom)) + implementation(libs.bundles.squareup.okhttp) + implementation(libs.bundles.squareup.retrofit) implementation(libs.jakewarthon.timber) implementation(libs.commons.io) implementation(libs.bundles.eclipse.jetty) diff --git a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt index f0c31051..1ccba70c 100644 --- a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt +++ b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt @@ -1,25 +1,42 @@ -package com.brainwallet.data.model; +package com.brainwallet.data.model -import java.io.Serializable; +import kotlinx.serialization.SerialName +import java.io.Serializable -public class CurrencyEntity implements Serializable { - - //Change this after modifying the class - private static final long serialVersionUID = 7526472295622776147L; - - public static final String TAG = CurrencyEntity.class.getName(); - public String code; - public String name; - public float rate; - public String symbol; - - public CurrencyEntity(String code, String name, float rate, String symbol) { - this.code = code; - this.name = name; - this.rate = rate; - this.symbol = symbol; - } - - public CurrencyEntity() { - } +@kotlinx.serialization.Serializable +data class CurrencyEntity( + @JvmField + var code: String ="", + @JvmField + var name: String = "", + @JvmField + @SerialName("n") + var rate: Float = 0F, + @JvmField + var symbol: String = "" +) : Serializable { +// @JvmField +// var code: String? = null +// @JvmField +// var name: String? = null +// @JvmField +// var rate: Float = 0f +// @JvmField +// var symbol: String? = null +// +// constructor(code: String?, name: String?, rate: Float, symbol: String?) { +// this.code = code +// this.name = name +// this.rate = rate +// this.symbol = symbol +// } +// +// constructor() +// +// companion object { +// //Change this after modifying the class +// private const val serialVersionUID = 7526472295622776147L +// +// val TAG: String = CurrencyEntity::class.java.name +// } } diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt new file mode 100644 index 00000000..02358b34 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -0,0 +1,40 @@ +package com.brainwallet.data.repository + +import android.content.Context +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.source.RemoteApiSource +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.tools.manager.FeeManager +import com.brainwallet.tools.sqlite.CurrencyDataSource + +interface LtcRepository { + suspend fun fetchRates(): List + //todo + + class Impl( + private val context: Context, + private val remoteApiSource: RemoteApiSource, + private val currencyDataSource: CurrencyDataSource + ) : LtcRepository { + + //todo: make it offline first here later, currently just using CurrencyDataSource.getAllCurrencies + override suspend fun fetchRates(): List { + val rates = remoteApiSource.getRates() + + //legacy logic + FeeManager.updateFeePerKb(context) + val selectedISO = BRSharedPrefs.getIsoSymbol(context) + rates.forEachIndexed { index, currencyEntity -> + if (currencyEntity.code.equals(selectedISO, ignoreCase = true)) { + BRSharedPrefs.putIso(context, currencyEntity.code) + BRSharedPrefs.putCurrencyListPosition(context, index - 1) + } + } + + //save to local + currencyDataSource.putCurrencies(rates) + return rates + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt b/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt new file mode 100644 index 00000000..0ce3bdc8 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt @@ -0,0 +1,17 @@ +package com.brainwallet.data.source + +import com.brainwallet.data.model.CurrencyEntity +import retrofit2.http.GET + +//TODO +interface RemoteApiSource { + + @GET("api/v1/rates") + suspend fun getRates(): List + + @GET("v1/fee-per-kb") + suspend fun getFeePerKb() + +// https://prod.apigsltd.net/moonpay/buy?address=ltc1qjnsg3p9rt4r4vy7ncgvrywdykl0zwhkhcp8ue0&code=USD&idate=1742331930290&uid=ec51fa950b271ff3 +// suspend fun getMoonPayBuy() +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 75a2cf5f..2da6b071 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -3,10 +3,12 @@ package com.brainwallet.di import android.content.Context import android.content.SharedPreferences import com.brainwallet.BuildConfig +import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.screens.home.SettingsViewModel import com.brainwallet.ui.screens.inputwords.InputWordsViewModel import com.brainwallet.ui.screens.ready.ReadyViewModel @@ -17,25 +19,43 @@ import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItViewModel import com.brainwallet.ui.screens.yourseedwords.YourSeedWordsViewModel import com.brainwallet.util.cryptography.KeyStoreKeyGenerator import com.brainwallet.util.cryptography.KeyStoreManager +import com.brainwallet.worker.CurrencyUpdateWorker import com.google.firebase.ktx.Firebase import com.google.firebase.remoteconfig.ktx.remoteConfig +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor import org.koin.android.ext.koin.androidApplication import org.koin.core.module.dsl.viewModel import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.kotlinx.serialization.asConverterFactory //todo module using koin as di framework here +val json = Json { + ignoreUnknownKeys = true + explicitNulls = false + prettyPrint = true +} + val dataModule = module { + factory { provideOkHttpClient() } + single { provideRetrofit(get(), BRConstants.BW_API_PROD_HOST) } + + single { provideApi(get()) } + single { RemoteConfigSource.FirebaseImpl(Firebase.remoteConfig).also { it.initialize() } } - single { BRApiManager(get()) } single { CurrencyDataSource.getInstance(get()) } single { provideSharedPreferences(context = androidApplication()) } single { SettingRepository.Impl(get(), get()) } + single { LtcRepository.Impl(get(), get(), get()) } } val viewModelModule = module { @@ -51,6 +71,7 @@ val viewModelModule = module { val appModule = module { single { KeyStoreManager(get(), KeyStoreKeyGenerator.Impl()) } + single { CurrencyUpdateWorker(get()) } } private fun provideSharedPreferences( @@ -58,4 +79,53 @@ private fun provideSharedPreferences( name: String = "${BuildConfig.APPLICATION_ID}.prefs" ): SharedPreferences { return context.getSharedPreferences(name, Context.MODE_PRIVATE) -} \ No newline at end of file +} + +private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() + .addInterceptor { chain -> + val requestBuilder = chain.request() + .newBuilder() + .addHeader("Accept", "application/json") + .addHeader("Content-Type", "application/json") + .addHeader("X-Litecoin-Testnet", "false") + .addHeader("Accept-Language", "en") +// .addHeader("User-agent",) + chain.proceed(requestBuilder.build()) + } + .addInterceptor { chain -> + val request = chain.request() + runCatching { + chain.proceed(request) + }.getOrElse { + //retry using dev host + val newRequest = request.newBuilder() + .url(BRConstants.BW_API_DEV_HOST + request.url.encodedPath) + .build() + chain.proceed(newRequest) + } + } + .addInterceptor(HttpLoggingInterceptor().apply { + setLevel( + when { + BuildConfig.DEBUG -> HttpLoggingInterceptor.Level.BODY + else -> HttpLoggingInterceptor.Level.NONE + } + ) + }) + .build() + +internal fun provideRetrofit( + okHttpClient: OkHttpClient, + baseUrl: String = BRConstants.BW_API_PROD_HOST +): Retrofit = Retrofit.Builder() + .baseUrl(baseUrl) + .client(okHttpClient) + .addConverterFactory( + json.asConverterFactory( + "application/json; charset=UTF8".toMediaType() + ) + ) + .build() + +internal fun provideApi(retrofit: Retrofit): RemoteApiSource = + retrofit.create(RemoteApiSource::class.java) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java index 6f62d97c..df68dc39 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/util/BRActivity.java @@ -16,7 +16,6 @@ import com.brainwallet.presenter.activities.intro.RecoverActivity; import com.brainwallet.presenter.activities.intro.WriteDownActivity; import com.brainwallet.tools.animation.BRAnimator; -import com.brainwallet.tools.manager.BRApiManager; import com.brainwallet.tools.manager.InternetManager; import com.brainwallet.tools.security.AuthManager; import com.brainwallet.tools.security.BRKeyStore; @@ -25,6 +24,7 @@ import com.brainwallet.tools.threads.BRExecutor; import com.brainwallet.tools.util.BRConstants; import com.brainwallet.wallet.BRWalletManager; +import com.brainwallet.worker.CurrencyUpdateWorker; import org.koin.java.KoinJavaComponent; @@ -51,11 +51,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } -// @Override -// protected void attachBaseContext(Context newBase) { -// super.attachBaseContext(LocaleHelper.Companion.getInstance().setLocale(newBase)); -// } - @Override protected void onStop() { super.onStop(); @@ -148,8 +143,8 @@ public static void init(Activity app) { if (!(app instanceof RecoverActivity || app instanceof WriteDownActivity)) { - BRApiManager apiManager = KoinJavaComponent.get(BRApiManager.class); - apiManager.startTimer(app); + CurrencyUpdateWorker currencyUpdateWorker = KoinJavaComponent.get(CurrencyUpdateWorker.class); + currencyUpdateWorker.start(); } //show wallet locked if it is diff --git a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java deleted file mode 100644 index 9b7a81de..00000000 --- a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.brainwallet.tools.manager; - -import static com.brainwallet.tools.util.BRConstants.BW_API_DEV_HOST; -import static com.brainwallet.tools.util.BRConstants.BW_API_PROD_HOST; -import static com.brainwallet.tools.util.BRConstants._20230113_BAC; -import static com.brainwallet.tools.util.BRConstants._20250222_PAC; - -import android.app.Activity; -import android.content.Context; -import android.os.Handler; - -import com.brainwallet.BuildConfig; -import com.brainwallet.data.model.CurrencyEntity; -import com.brainwallet.tools.sqlite.CurrencyDataSource; -import com.brainwallet.tools.threads.BRExecutor; -import com.brainwallet.tools.util.Utils; -import com.brainwallet.data.source.RemoteConfigSource; -import com.platform.APIClient; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; - -import okhttp3.Request; -import okhttp3.Response; -import timber.log.Timber; - -public class BRApiManager { - private Timer timer; - - private TimerTask timerTask; - - private Handler handler; - - private RemoteConfigSource remoteConfigSource; - - public BRApiManager(RemoteConfigSource remoteConfigSource) { - this.remoteConfigSource = remoteConfigSource; - this.handler = new Handler(); - } - - private Set getCurrencies(Activity context) { - Set set = new LinkedHashSet<>(); - try { - JSONArray arr = fetchRates(context); - FeeManager.updateFeePerKb(context); - if (arr != null) { - String selectedISO = BRSharedPrefs.getIsoSymbol(context); - int length = arr.length(); - for (int i = 0; i < length; i++) { - CurrencyEntity tempCurrencyEntity = new CurrencyEntity(); - try { - JSONObject tmpJSONObj = (JSONObject) arr.get(i); - tempCurrencyEntity.name = tmpJSONObj.getString("name"); - tempCurrencyEntity.code = tmpJSONObj.getString("code"); - tempCurrencyEntity.rate = (float) tmpJSONObj.getDouble("n"); - tempCurrencyEntity.symbol = new String(""); - if (tempCurrencyEntity.code.equalsIgnoreCase(selectedISO)) { - BRSharedPrefs.putIso(context, tempCurrencyEntity.code); - BRSharedPrefs.putCurrencyListPosition(context, i - 1); - } - set.add(tempCurrencyEntity); - } catch (JSONException e) { - Timber.e(e); - } - } - } else { - Timber.d("timber: getCurrencies: failed to get currencies"); - } - } catch (Exception e) { - Timber.e(e); - } - List tempList = new ArrayList<>(set); - Collections.reverse(tempList); - return new LinkedHashSet<>(set); - } - - - private void initializeTimerTask(final Context context) { - timerTask = new TimerTask() { - public void run() { - //use a handler to run a toast that shows the current timestamp - handler.post(new Runnable() { - public void run() { - BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { - @Override - public void run() { - Set tmp = getCurrencies((Activity) context); - CurrencyDataSource.getInstance(context).putCurrencies(tmp); - } - }); - } - }); - } - }; - } - - public void startTimer(Context context) { - //set a new Timer - if (timer != null) return; - timer = new Timer(); - - //initialize the TimerTask's job - initializeTimerTask(context); - - //schedule the timer, after the first 0ms the TimerTask will run every 60000ms - timer.schedule(timerTask, 0, 4000); - } - - public JSONArray fetchRates(Activity activity) { - String jsonString = createGETRequestURL(activity, BW_API_PROD_HOST + "/api/v1/rates"); - JSONArray jsonArray = null; - if (jsonString == null) return null; - try { - jsonArray = new JSONArray(jsonString); - // DEV Uncomment to view values - // Timber.d("timber: baseUrlProd: %s", getBaseUrlProd()); - // Timber.d("timber: JSON %s",jsonArray.toString()); - } catch (JSONException ex) { - Timber.e(ex); - } - if (jsonArray != null && !BuildConfig.DEBUG) { - AnalyticsManager.logCustomEvent(_20250222_PAC); - } - return jsonArray == null ? backupFetchRates(activity) : jsonArray; - } - - public JSONArray backupFetchRates(Activity activity) { - String jsonString = createGETRequestURL(activity, BW_API_DEV_HOST + "/api/v1/rates"); - - JSONArray jsonArray = null; - if (jsonString == null) return null; - try { - jsonArray = new JSONArray(jsonString); - - } catch (JSONException e) { - Timber.e(e); - } - if (jsonArray != null && !BuildConfig.DEBUG) { - AnalyticsManager.logCustomEvent(_20230113_BAC); - } - - return jsonArray; - } - - // createGETRequestURL - // Creates the params and headers to make a GET Request - private String createGETRequestURL(Context app, String myURL) { - Request request = new Request.Builder() - .url(myURL) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) - .get().build(); - String response = null; - Response resp = APIClient.getInstance(app).sendRequest(request, false, 0); - - try { - if (resp == null) { - Timber.i("timber: urlGET: %s resp is null", myURL); - return null; - } - ///Set timestamp to prefs - long timeStamp = new Date().getTime(); - BRSharedPrefs.putSecureTime(app, timeStamp); - - assert resp.body() != null; - response = resp.body().string(); - - } catch (IOException e) { - Timber.e(e); - } finally { - if (resp != null) resp.close(); - } - return response; - } - - public String getBaseUrlProd() { - return BW_API_PROD_HOST; - } -} diff --git a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java index 3ca79a7b..91e12a9e 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java @@ -95,6 +95,7 @@ public static void updateFeePerKb(Context app) { // createGETRequestURL // Creates the params and headers to make a GET Request + @Deprecated private static String createGETRequestURL(Context app, String myURL) { Request request = new Request.Builder() .url(myURL) diff --git a/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt b/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt new file mode 100644 index 00000000..739da912 --- /dev/null +++ b/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt @@ -0,0 +1,32 @@ +package com.brainwallet.worker + +import com.brainwallet.data.repository.LtcRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch + +class CurrencyUpdateWorker( + private val ltcRepository: LtcRepository +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + private var job: Job? = null + + fun start() { + if (job?.isActive == true && job != null) { + job?.cancel() + } + + job = scope.launch(Dispatchers.IO) { + while (isActive) { + ltcRepository.fetchRates() + delay(4000L) //4secs + } + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/platform/APIClient.java b/app/src/main/java/com/platform/APIClient.java index da333b08..d55592cf 100644 --- a/app/src/main/java/com/platform/APIClient.java +++ b/app/src/main/java/com/platform/APIClient.java @@ -35,6 +35,7 @@ import static com.brainwallet.tools.util.BRCompressor.gZipExtract; +@Deprecated public class APIClient { // proto is the transport protocol to use for talking to the API (either http or https) diff --git a/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt b/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt index ba5c19ec..9e997f57 100644 --- a/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt +++ b/app/src/test/java/com/brainwallet/currency/BackupRateFetchTests.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.Context import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.presenter.activities.util.ActivityUTILS -import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.tools.util.Utils import com.platform.APIClient @@ -20,74 +19,75 @@ import okhttp3.ResponseBody.Companion.toResponseBody import org.junit.Before import org.junit.Test +//TODO: need update this test after refactor class BackupRateFetchTests { - private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: BRApiManager - - @Before - fun setUp() { - apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) - } - - @Test - fun `invoke backupFetchRates, should return success with parsed JSONArray`() { - val activity: Activity = mockk(relaxed = true) - val responseString = """ - [ - { - "code" : "CZK", - "price" : "Kč3065.541255", - "name" : "Czech Republic Koruna", - "n" : 3065.541255 - }, - { - "code" : "KRW", - "price" : "₩183797.935875", - "name" : "South Korean Won", - "n" : 183797.935875 - }, - { - "code" : "BYN", - "price" : "Br418.909259625", - "n" : 418.909259625 - }, - { - "code" : "CNY", - "price" : "CN¥927.7974375", - "name" : "Chinese Yuan", - "n" : 927.7974375 - } - ] - """.trimIndent() - mockkStatic(ActivityUTILS::class) - mockkObject(APIClient.getInstance(activity)) - every { - remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) - } returns false - every { - apiManager invoke "createGETRequestURL" withArguments (listOf( - activity as Context, - BRConstants.BW_API_DEV_HOST - )) - } returns responseString - every { ActivityUTILS.isMainThread() } returns false - every { APIClient.getInstance(activity).getCurrentLocale(activity) } returns "en" - - val request = Request.Builder() - .url(BRConstants.BW_API_DEV_HOST) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("User-agent", Utils.getAgentString(activity, "android/HttpURLConnection")) - .get().build() - every { - APIClient.getInstance(activity).sendRequest(request, false, 0) - } returns Response.Builder() - .request(request) - .protocol(Protocol.HTTP_1_1) - .code(200) - .message("OK") - .body(responseString.toResponseBody()) - .build() - - } +// private val remoteConfigSource: RemoteConfigSource = mockk() +// private lateinit var apiManager: BRApiManager +// +// @Before +// fun setUp() { +// apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) +// } +// +// @Test +// fun `invoke backupFetchRates, should return success with parsed JSONArray`() { +// val activity: Activity = mockk(relaxed = true) +// val responseString = """ +// [ +// { +// "code" : "CZK", +// "price" : "Kč3065.541255", +// "name" : "Czech Republic Koruna", +// "n" : 3065.541255 +// }, +// { +// "code" : "KRW", +// "price" : "₩183797.935875", +// "name" : "South Korean Won", +// "n" : 183797.935875 +// }, +// { +// "code" : "BYN", +// "price" : "Br418.909259625", +// "n" : 418.909259625 +// }, +// { +// "code" : "CNY", +// "price" : "CN¥927.7974375", +// "name" : "Chinese Yuan", +// "n" : 927.7974375 +// } +// ] +// """.trimIndent() +// mockkStatic(ActivityUTILS::class) +// mockkObject(APIClient.getInstance(activity)) +// every { +// remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) +// } returns false +// every { +// apiManager invoke "createGETRequestURL" withArguments (listOf( +// activity as Context, +// BRConstants.BW_API_DEV_HOST +// )) +// } returns responseString +// every { ActivityUTILS.isMainThread() } returns false +// every { APIClient.getInstance(activity).getCurrentLocale(activity) } returns "en" +// +// val request = Request.Builder() +// .url(BRConstants.BW_API_DEV_HOST) +// .header("Content-Type", "application/json") +// .header("Accept", "application/json") +// .header("User-agent", Utils.getAgentString(activity, "android/HttpURLConnection")) +// .get().build() +// every { +// APIClient.getInstance(activity).sendRequest(request, false, 0) +// } returns Response.Builder() +// .request(request) +// .protocol(Protocol.HTTP_1_1) +// .code(200) +// .message("OK") +// .body(responseString.toResponseBody()) +// .build() +// +// } } \ No newline at end of file diff --git a/app/src/test/java/com/brainwallet/data/BaseURLTests.kt b/app/src/test/java/com/brainwallet/data/BaseURLTests.kt index d0163299..f0423f90 100644 --- a/app/src/test/java/com/brainwallet/data/BaseURLTests.kt +++ b/app/src/test/java/com/brainwallet/data/BaseURLTests.kt @@ -1,7 +1,6 @@ package com.brainwallet.data import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.util.BRConstants import io.mockk.every import io.mockk.mockk @@ -10,24 +9,25 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test +//TODO: need update this test after refactor class BaseURLTests { - private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: BRApiManager - - @Before - fun setUp() { - apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) - } - - @Test - fun `invoke getBaseUrlProd with KEY_API_BASEURL_PROD_NEW_ENABLED true, then should return new baseUrlProd`() { - every { remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) } returns true - - val actual = apiManager.baseUrlProd - - assertEquals(BRConstants.BW_API_PROD_HOST, actual) - } +// private val remoteConfigSource: RemoteConfigSource = mockk() +// private lateinit var apiManager: BRApiManager +// +// @Before +// fun setUp() { +// apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) +// } +// +// @Test +// fun `invoke getBaseUrlProd with KEY_API_BASEURL_PROD_NEW_ENABLED true, then should return new baseUrlProd`() { +// every { remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) } returns true +// +// val actual = apiManager.baseUrlProd +// +// assertEquals(BRConstants.BW_API_PROD_HOST, actual) +// } } diff --git a/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt b/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt index 2386d1f0..1dfee111 100644 --- a/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt +++ b/app/src/test/java/com/brainwallet/tools/util/ProdAPIManagerTests.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.Context import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.presenter.activities.util.ActivityUTILS -import com.brainwallet.tools.manager.BRApiManager import com.platform.APIClient import io.mockk.every import io.mockk.mockk @@ -20,89 +19,90 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test +//TODO: need update this test after refactor class ProdAPIManagerTests { - private val remoteConfigSource: RemoteConfigSource = mockk() - private lateinit var apiManager: BRApiManager - - @Before - fun setUp() { - apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) - } - - @Test - fun `invoke fetchRates, should return success with parsed JSONArray`() { - val activity: Activity = mockk(relaxed = true) - - val responseString = """ - [ - { - "code": "USD", - "n": 416.81128312406213, - "price": "USD416.811283124062145364", - "name": "US Dollar" - }, - { - "code": "EUR", - "n": 7841.21263788453, - "price": "Af7841.212637884529266812", - "name": "Euro" - }, - { - "code": "GBP", - "n": 10592.359754930994, - "price": "ALL10592.359754930995026136", - "name": "British Pound" - } - ] - """.trimIndent() - mockkStatic(ActivityUTILS::class) - mockkObject(APIClient.getInstance(activity)) - every { - remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) - } returns false - every { - apiManager invoke "createGETRequestURL" withArguments (listOf( - activity as Context, - BRConstants.BW_API_PROD_HOST - )) - } returns responseString - every { ActivityUTILS.isMainThread() } returns false - every { APIClient.getInstance(activity).getCurrentLocale(activity) } returns "en" - - val request = Request.Builder() - .url(BRConstants.BW_API_PROD_HOST) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("User-agent", Utils.getAgentString(activity, "android/HttpURLConnection")) - .get().build() - every { - APIClient.getInstance(activity).sendRequest(request, false, 0) - } returns Response.Builder() - .request(request) - .protocol(Protocol.HTTP_1_1) - .code(200) - .message("OK") - .body(responseString.toResponseBody()) - .build() - - val result = apiManager.fetchRates(activity) - val jsonUSD = result.getJSONObject(154) - val jsonEUR = result.getJSONObject(49) - val jsonGBP = result.getJSONObject(52) - - assertEquals("USD", jsonUSD.optString("code")) - assertEquals("US Dollar", jsonUSD.optString("name")) - assertEquals("EUR", jsonEUR.optString("code")) - assertEquals("Euro", jsonEUR.optString("name")) - assertEquals("GBP", jsonGBP.optString("code")) - assertEquals("British Pound Sterling", jsonGBP.optString("name")) - - ///DEV: Very flaky test not enough time for the response - verifyAll { - ActivityUTILS.isMainThread() - APIClient.getInstance(activity).getCurrentLocale(activity) - APIClient.getInstance(activity).sendRequest(any(), any(), any()) - } - - } +// private val remoteConfigSource: RemoteConfigSource = mockk() +// private lateinit var apiManager: BRApiManager +// +// @Before +// fun setUp() { +// apiManager = spyk(BRApiManager(remoteConfigSource), recordPrivateCalls = true) +// } +// +// @Test +// fun `invoke fetchRates, should return success with parsed JSONArray`() { +// val activity: Activity = mockk(relaxed = true) +// +// val responseString = """ +// [ +// { +// "code": "USD", +// "n": 416.81128312406213, +// "price": "USD416.811283124062145364", +// "name": "US Dollar" +// }, +// { +// "code": "EUR", +// "n": 7841.21263788453, +// "price": "Af7841.212637884529266812", +// "name": "Euro" +// }, +// { +// "code": "GBP", +// "n": 10592.359754930994, +// "price": "ALL10592.359754930995026136", +// "name": "British Pound" +// } +// ] +// """.trimIndent() +// mockkStatic(ActivityUTILS::class) +// mockkObject(APIClient.getInstance(activity)) +// every { +// remoteConfigSource.getBoolean(RemoteConfigSource.KEY_API_BASEURL_PROD_NEW_ENABLED) +// } returns false +// every { +// apiManager invoke "createGETRequestURL" withArguments (listOf( +// activity as Context, +// BRConstants.BW_API_PROD_HOST +// )) +// } returns responseString +// every { ActivityUTILS.isMainThread() } returns false +// every { APIClient.getInstance(activity).getCurrentLocale(activity) } returns "en" +// +// val request = Request.Builder() +// .url(BRConstants.BW_API_PROD_HOST) +// .header("Content-Type", "application/json") +// .header("Accept", "application/json") +// .header("User-agent", Utils.getAgentString(activity, "android/HttpURLConnection")) +// .get().build() +// every { +// APIClient.getInstance(activity).sendRequest(request, false, 0) +// } returns Response.Builder() +// .request(request) +// .protocol(Protocol.HTTP_1_1) +// .code(200) +// .message("OK") +// .body(responseString.toResponseBody()) +// .build() +// +// val result = apiManager.fetchRates(activity) +// val jsonUSD = result.getJSONObject(154) +// val jsonEUR = result.getJSONObject(49) +// val jsonGBP = result.getJSONObject(52) +// +// assertEquals("USD", jsonUSD.optString("code")) +// assertEquals("US Dollar", jsonUSD.optString("name")) +// assertEquals("EUR", jsonEUR.optString("code")) +// assertEquals("Euro", jsonEUR.optString("name")) +// assertEquals("GBP", jsonGBP.optString("code")) +// assertEquals("British Pound Sterling", jsonGBP.optString("name")) +// +// ///DEV: Very flaky test not enough time for the response +// verifyAll { +// ActivityUTILS.isMainThread() +// APIClient.getInstance(activity).getCurrentLocale(activity) +// APIClient.getInstance(activity).sendRequest(any(), any(), any()) +// } +// +// } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f4ab271f..90f8dedd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,8 @@ google-zxing = "3.5.2" google-play-asset-delivery = "2.2.2" google-play-feature-delivery = "2.1.0" google-play-review = "2.0.1" -squareup-okhttp = "4.12.0" +squareup-okhttp-bom = "4.12.0" +squareup-retrofit = "2.11.0" firebase-bom = "32.7.1" jakewarthon-timber = "4.7.1" eclipse-jetty = "9.2.19.v20160908" @@ -68,8 +69,6 @@ androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui- androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-work = { module = "androidx.work:work-runtime-ktx", version.ref = "androidx-work" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.7.1" } -#google-dagger = { module = "com.google.dagger:dagger", version.ref = "google-dagger" } -#google-dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "google-dagger" } google-zxing = { module = "com.google.zxing:core", version.ref = "google-zxing" } google-material = { module = "com.google.android.material:material", version.ref = "google-material" } google-play-asset-delivery = { module = "com.google.android.play:asset-delivery", version.ref = "google-play-asset-delivery" } @@ -78,7 +77,11 @@ google-play-feature-delivery = { module = "com.google.android.play:feature-deliv google-play-feature-delivery-ktx = { module = "com.google.android.play:feature-delivery-ktx", version.ref = "google-play-feature-delivery" } google-play-review = { module = "com.google.android.play:review", version.ref = "google-play-review" } google-play-review-ktx = { module = "com.google.android.play:review-ktx", version.ref = "google-play-review" } -squareup-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "squareup-okhttp" } +squareup-okhttp-bom = { module = "com.squareup.okhttp3:okhttp-bom", version.ref = "squareup-okhttp-bom" } +squareup-okhttp = { module = "com.squareup.okhttp3:okhttp" } +squareup-okhttp-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor" } +squareup-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "squareup-retrofit" } +squareup-retrofit-kotlinx-serialization-json = { module = "com.squareup.retrofit2:converter-kotlinx-serialization", version.ref = "squareup-retrofit" } firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" } firebase-analytics = { module = "com.google.firebase:firebase-analytics" } firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" } @@ -123,6 +126,8 @@ eclipse-jetty = ["eclipse-jetty-webapp", "eclipse-jetty-websocket", "eclipse-jet android-test = ["androidx-test-core", "androidx-test-core-ktx", "androidx-test-rules","androidx-test-espresso-core", "androidx-test-junit-ext","androidx-test-juniext-ext-ktx", "androidx-test-runner", "androidx-test-uiautomator"] androidx-compose-ui-test = ["androidx-compose-ui-test-junit4", "androidx-compose-ui-test-manifest"] koin = ["koin-android", "koin-android-compat", "koin-compose", "koin-compose-viewmodel"] +squareup-retrofit = ["squareup-retrofit", "squareup-retrofit-kotlinx-serialization-json"] +squareup-okhttp = ["squareup-okhttp", "squareup-okhttp-logging-interceptor"] [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 0aa41e77d719adf9524f2ec5a20644722dbc560d Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Mon, 14 Apr 2025 13:25:26 +0700 Subject: [PATCH 14/65] chore: remove unused part at APIClient --- app/src/main/java/com/platform/APIClient.java | 99 +++---------------- 1 file changed, 15 insertions(+), 84 deletions(-) diff --git a/app/src/main/java/com/platform/APIClient.java b/app/src/main/java/com/platform/APIClient.java index d55592cf..90b22f68 100644 --- a/app/src/main/java/com/platform/APIClient.java +++ b/app/src/main/java/com/platform/APIClient.java @@ -1,24 +1,17 @@ package com.platform; -import android.annotation.TargetApi; +import static com.brainwallet.tools.util.BRCompressor.gZipExtract; + import android.content.Context; -import android.content.pm.ApplicationInfo; import android.net.Uri; -import android.os.Build; import android.os.NetworkOnMainThreadException; import com.brainwallet.BrainwalletApp; -import com.brainwallet.BrainwalletApp; -import com.brainwallet.BuildConfig; import com.brainwallet.presenter.activities.util.ActivityUTILS; -import com.brainwallet.tools.util.BRConstants; import com.brainwallet.tools.util.Utils; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.concurrent.TimeUnit; @@ -30,11 +23,8 @@ import okhttp3.Response; import okhttp3.ResponseBody; import timber.log.Timber; -import com.brainwallet.tools.manager.AnalyticsManager; -import com.brainwallet.tools.util.BRConstants; - -import static com.brainwallet.tools.util.BRCompressor.gZipExtract; +//some part still used e.g. [sendRequest] @Deprecated public class APIClient { @@ -55,12 +45,12 @@ public class APIClient { private static final boolean PRINT_FILES = false; - private SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + private final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); - private boolean platformUpdating = false; + private final boolean platformUpdating = false; private AtomicInteger itemsLeftToUpdate = new AtomicInteger(0); - private Context ctx; + private final Context ctx; public static synchronized APIClient getInstance(Context context) { if (ourInstance == null) ourInstance = new APIClient(context); @@ -72,42 +62,14 @@ private APIClient(Context context) { itemsLeftToUpdate = new AtomicInteger(0); } - //returns the fee per kb or 0 if something went wrong - public long feePerKb() { - if (ActivityUTILS.isMainThread()) { - throw new NetworkOnMainThreadException(); - } - Response response = null; - try { - String strUtl = BASE_URL + FEE_PER_KB_URL; - Request request = new Request.Builder().url(strUtl).get().build(); - String body = null; - try { - response = sendRequest(request, false, 0); - body = response.body().string(); - Timber.d("timber: fee per kb %s",body); - } catch (IOException e) { - Timber.e(e); - AnalyticsManager.logCustomEvent(BRConstants._20200111_RNI); - } - JSONObject object = null; - object = new JSONObject(body); - return (long) object.getInt("fee_per_kb"); - } catch (JSONException e) { - Timber.e(e); - } finally { - if (response != null) response.close(); - } - return 0; - } - + // sendRequest still using, e.g. inside RemoteKVStore public Response sendRequest(Request locRequest, boolean needsAuth, int retryCount) { if (retryCount > 1) throw new RuntimeException("sendRequest: Warning retryCount is: " + retryCount); if (ActivityUTILS.isMainThread()) { throw new NetworkOnMainThreadException(); } - String lang = getCurrentLocale(ctx); + String lang = ctx.getResources().getConfiguration().locale.getLanguage(); Request request = locRequest.newBuilder() .header("X-Litecoin-Testnet", "false") .header("Accept-Language", lang) @@ -154,23 +116,15 @@ public Response sendRequest(Request locRequest, boolean needsAuth, int retryCoun Timber.d("timber: sendRequest: the content is gzip, unzipping"); byte[] decompressed = gZipExtract(data); postReqBody = ResponseBody.create(null, decompressed); - try { - if (response.code() != 200) { - Timber.d("timber: sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), - request.url(), response.code(), response.message(), new String(decompressed, "utf-8")); - } - } catch (UnsupportedEncodingException e) { - Timber.e(e); + if (response.code() != 200) { + Timber.d("timber: sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), + request.url(), response.code(), response.message(), new String(decompressed, StandardCharsets.UTF_8)); } return response.newBuilder().body(postReqBody).build(); } else { - try { - if (response.code() != 200) { - Timber.d("timber: sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), - request.url(), response.code(), response.message(), new String(data, "utf-8")); - } - } catch (UnsupportedEncodingException e) { - Timber.e(e); + if (response.code() != 200) { + Timber.d("timber: sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), + request.url(), response.code(), response.message(), new String(data, StandardCharsets.UTF_8)); } } @@ -178,27 +132,4 @@ public Response sendRequest(Request locRequest, boolean needsAuth, int retryCoun return response.newBuilder().body(postReqBody).build(); } - - public String buildUrl(String path) { - return BASE_URL + path; - } - - private void itemFinished() { - int items = itemsLeftToUpdate.incrementAndGet(); - if (items >= 4) { - Timber.d("timber: PLATFORM ALL UPDATED: %s", items); - platformUpdating = false; - itemsLeftToUpdate.set(0); - } - } - - @TargetApi(Build.VERSION_CODES.N) - public String getCurrentLocale(Context ctx) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return ctx.getResources().getConfiguration().getLocales().get(0).getLanguage(); - } else { - //noinspection deprecation - return ctx.getResources().getConfiguration().locale.getLanguage(); - } - } } From 0cc29cbcd9ec8ffca56d5c6bb4da98dd8a0882a7 Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Mon, 14 Apr 2025 15:41:13 +0700 Subject: [PATCH 15/65] feat: wip new peer discovery --- .../repository/SelectedPeersRepository.kt | 81 +++++++++++++++++++ .../data/source/RemoteConfigSource.kt | 4 +- .../main/java/com/brainwallet/di/Module.kt | 2 + .../com/brainwallet/wallet/BRPeerManager.java | 37 ++++++++- .../brainwallet/wallet/BRWalletManager.java | 2 +- .../main/res/xml/remote_config_defaults.xml | 10 +-- 6 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt diff --git a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt new file mode 100644 index 00000000..766cfb7d --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt @@ -0,0 +1,81 @@ +package com.brainwallet.data.repository + +import android.content.SharedPreferences +import androidx.core.content.edit +import com.brainwallet.di.json +import kotlinx.serialization.json.jsonObject +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Response +import okio.IOException +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +interface SelectedPeersRepository { + + suspend fun fetchSelectedPeers(): Set + + class Impl( + private val okHttpClient: OkHttpClient, + private val sharedPreferences: SharedPreferences, + ) : SelectedPeersRepository { + + private companion object { + const val PREF_KEY_SELECTED_PEERS = "selected_peers" + const val PREF_KEY_SELECTED_PEERS_CACHED_AT = "${PREF_KEY_SELECTED_PEERS}_cached_at" + } + + override suspend fun fetchSelectedPeers(): Set { + val lastUpdateTime = sharedPreferences.getLong(PREF_KEY_SELECTED_PEERS_CACHED_AT, 0) + val currentTime = System.currentTimeMillis() + val cachedPeers = sharedPreferences.getStringSet(PREF_KEY_SELECTED_PEERS, null) + + // Check if cache exists and is less than 6 hours old + if (!cachedPeers.isNullOrEmpty() && (currentTime - lastUpdateTime) < 6 * 60 * 60 * 1000) { + return cachedPeers + } + + val request = okhttp3.Request.Builder() + .url(LITECOIN_NODES_URL) + .build() + + return suspendCoroutine { continuation -> + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + continuation.resume(emptySet()) //just return empty if failed or need hardcoded? + } + + override fun onResponse(call: Call, response: Response) { + val jsonString = response.body?.string() + + val parsedResult = jsonString?.let { + val jsonElement = json.parseToJsonElement(it) + val dataObject = jsonElement.jsonObject["data"]?.jsonObject + val nodesObject = dataObject?.get("nodes")?.jsonObject + + //TODO: need filter criteria here? + nodesObject?.keys + ?.filter { it.endsWith(":9333") } + ?.map { it.replace(":9333", "") } + ?.toSet() + ?: emptySet() + } ?: emptySet() + + sharedPreferences.edit { + putStringSet(PREF_KEY_SELECTED_PEERS, parsedResult) + putLong(PREF_KEY_SELECTED_PEERS_CACHED_AT, currentTime) + } + + continuation.resume(parsedResult) + } + }) + } + } + + } + + companion object { + const val LITECOIN_NODES_URL = "https://api.blockchair.com/litecoin/nodes" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt b/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt index 058d8dc9..dc5c7ff4 100644 --- a/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt +++ b/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt @@ -13,9 +13,7 @@ interface RemoteConfigSource { companion object { const val KEY_FEATURE_MENU_HIDDEN_EXAMPLE = "feature_menu_hidden_example" - const val KEY_API_BASEURL_PROD_NEW_ENABLED = "key_api_baseurl_prod_new_enabled" - const val KEY_API_BASEURL_DEV_NEW_ENABLED = "key_api_baseurl_dev_new_enabled" - const val KEY_KEYSTORE_MANAGER_ENABLED = "key_keystore_manager_enabled" + const val KEY_FEATURE_SELECTED_PEERS_ENABLED = "feature_selected_peers_enabled" } fun initialize() diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 2da6b071..e64e071a 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -7,6 +7,7 @@ import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.data.source.RemoteConfigSource +import com.brainwallet.data.repository.SelectedPeersRepository import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.screens.home.SettingsViewModel @@ -52,6 +53,7 @@ val dataModule = module { it.initialize() } } + single { SelectedPeersRepository.Impl(get(), get()) } single { CurrencyDataSource.getInstance(get()) } single { provideSharedPreferences(context = androidApplication()) } single { SettingRepository.Impl(get(), get()) } diff --git a/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java b/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java index 0cc46e61..a27938b8 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java @@ -1,8 +1,12 @@ package com.brainwallet.wallet; +import static com.brainwallet.data.source.RemoteConfigSource.KEY_FEATURE_SELECTED_PEERS_ENABLED; + import android.content.Context; import com.brainwallet.BrainwalletApp; +import com.brainwallet.data.repository.SelectedPeersRepository; +import com.brainwallet.data.source.RemoteConfigSource; import com.brainwallet.presenter.entities.BlockEntity; import com.brainwallet.presenter.entities.PeerEntity; import com.brainwallet.tools.manager.BRSharedPrefs; @@ -12,10 +16,18 @@ import com.brainwallet.tools.threads.BRExecutor; import com.brainwallet.tools.util.TrustedNode; +import org.koin.java.KoinJavaComponent; + import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import kotlin.coroutines.EmptyCoroutineContext; +import kotlinx.coroutines.CoroutineScopeKt; +import kotlinx.coroutines.CoroutineStart; +import kotlinx.coroutines.future.FutureKt; import timber.log.Timber; public class BRPeerManager { @@ -164,7 +176,7 @@ public void updateFixedPeer(Context ctx) { } else { Timber.d("timber: updateFixedPeer: succeeded"); } - connect(); + wrapConnectV2(); } public void networkChanged(boolean isOnline) { @@ -172,11 +184,21 @@ public void networkChanged(boolean isOnline) { BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { - BRPeerManager.getInstance().connect(); + wrapConnectV2(); } }); } + //wrap logic enable/disable connect with new flow + public void wrapConnectV2() { + RemoteConfigSource remoteConfigSource = KoinJavaComponent.get(RemoteConfigSource.class); + if (remoteConfigSource.getBoolean(KEY_FEATURE_SELECTED_PEERS_ENABLED)) { + fetchSelectedPeers().whenComplete((strings, throwable) -> connect()); + } else { + connect(); + } + } + public void addStatusUpdateListener(OnTxStatusUpdate listener) { if (statusUpdateListeners.contains(listener)) return; statusUpdateListeners.add(listener); @@ -186,6 +208,17 @@ public void removeListener(OnTxStatusUpdate listener) { statusUpdateListeners.remove(listener); } + public CompletableFuture> fetchSelectedPeers() { + SelectedPeersRepository selectedPeersRepository = KoinJavaComponent.get(SelectedPeersRepository.class); + + return FutureKt.future( + CoroutineScopeKt.CoroutineScope(EmptyCoroutineContext.INSTANCE), + EmptyCoroutineContext.INSTANCE, + CoroutineStart.DEFAULT, + (coroutineScope, continuation) -> selectedPeersRepository.fetchSelectedPeers(continuation) + ); + } + public static void setOnSyncFinished(OnSyncSucceeded listener) { onSyncFinished = listener; } diff --git a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java index 792fad8e..d5aee0d2 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java @@ -547,7 +547,7 @@ public void initWallet(final Context ctx) { BRPeerManager.getInstance().updateFixedPeer(ctx); } - pm.connect(); + pm.wrapConnectV2(); if (BRSharedPrefs.getStartHeight(ctx) == 0) { BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override diff --git a/app/src/main/res/xml/remote_config_defaults.xml b/app/src/main/res/xml/remote_config_defaults.xml index e9f361c4..6852653a 100644 --- a/app/src/main/res/xml/remote_config_defaults.xml +++ b/app/src/main/res/xml/remote_config_defaults.xml @@ -1,15 +1,7 @@ - key_api_baseurl_prod_new_enabled - false - - - key_api_baseurl_dev_new_enabled - false - - - key_keystore_manager_enabled + feature_selected_peers_enabled true From 54d2d9ef348caf53948423c9da73ccd617504541 Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Tue, 15 Apr 2025 04:51:09 +0700 Subject: [PATCH 16/65] feat: implement selected peer ip address from cache (fetched from API) --- .../com/brainwallet/wallet/BRPeerManager.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java b/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java index a27938b8..209814e7 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import kotlin.coroutines.EmptyCoroutineContext; import kotlinx.coroutines.CoroutineScopeKt; @@ -191,14 +192,18 @@ public void run() { //wrap logic enable/disable connect with new flow public void wrapConnectV2() { - RemoteConfigSource remoteConfigSource = KoinJavaComponent.get(RemoteConfigSource.class); - if (remoteConfigSource.getBoolean(KEY_FEATURE_SELECTED_PEERS_ENABLED)) { + if (featureSelectedPeersEnabled()) { fetchSelectedPeers().whenComplete((strings, throwable) -> connect()); } else { connect(); } } + public static boolean featureSelectedPeersEnabled() { + RemoteConfigSource remoteConfigSource = KoinJavaComponent.get(RemoteConfigSource.class); + return remoteConfigSource.getBoolean(KEY_FEATURE_SELECTED_PEERS_ENABLED); + } + public void addStatusUpdateListener(OnTxStatusUpdate listener) { if (statusUpdateListeners.contains(listener)) return; statusUpdateListeners.add(listener); @@ -219,6 +224,14 @@ public CompletableFuture> fetchSelectedPeers() { ); } + public static Set fetchSelectedPeersBlocking() { + try { + return BRPeerManager.getInstance().fetchSelectedPeers().get(); + } catch (ExecutionException | InterruptedException e) { + return java.util.Collections.emptySet(); + } + } + public static void setOnSyncFinished(OnSyncSucceeded listener) { onSyncFinished = listener; } From c6923b11b89de4ee4ed48ec0b4f69aa3f01b0334 Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Tue, 15 Apr 2025 04:52:02 +0700 Subject: [PATCH 17/65] feat: implement selected peer ip address from cache (fetched from API) --- app/src/main/jni/transition/PeerManager.c | 106 +++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/app/src/main/jni/transition/PeerManager.c b/app/src/main/jni/transition/PeerManager.c index 48e50f92..4c2ce73e 100644 --- a/app/src/main/jni/transition/PeerManager.c +++ b/app/src/main/jni/transition/PeerManager.c @@ -226,6 +226,109 @@ static int networkIsReachable(void *info) { return (isNetworkOn == JNI_TRUE) ? 1 : 0; } +/** + * communicate with java to check if featureSelectedPeersEnabled is on + */ +static int featureSelectedPeersEnabled(void *info) { + __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "featureSelectedPeersEnabled"); + + JNIEnv *env = getEnv(); + jmethodID mid; + jboolean isFeatureSelectedPeersOn; + + if (!env) return 0; + + //call java methods + mid = (*env)->GetStaticMethodID(env, _peerManagerClass, "featureSelectedPeersEnabled", "()Z"); + isFeatureSelectedPeersOn = (*env)->CallStaticBooleanMethod(env, _peerManagerClass, mid); + return (isFeatureSelectedPeersOn == JNI_TRUE) ? 1 : 0; +} + +/** + * obtain selected peers from BRPeerManager.fetchSelectedPeersBlocking + */ +static char **fetchSelectedPeers(void *info) { + __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "fetchSelectedPeers"); + + JNIEnv *env = getEnv(); + if (!env) return NULL; + + jclass peerManagerClass = (*env)->FindClass(env, "com/brainwallet/wallet/BRPeerManager"); + if (!peerManagerClass) return NULL; + + jmethodID fetchSelectedPeersBlockingMethod = (*env)->GetStaticMethodID( + env, peerManagerClass, "fetchSelectedPeersBlocking", "()Ljava/util/Set;"); + if (!fetchSelectedPeersBlockingMethod) { + (*env)->DeleteLocalRef(env, peerManagerClass); + return NULL; + } + + jobject set = (*env)->CallStaticObjectMethod(env, peerManagerClass, fetchSelectedPeersBlockingMethod); + (*env)->DeleteLocalRef(env, peerManagerClass); + if (!set) return NULL; + + jclass setClass = (*env)->GetObjectClass(env, set); + jmethodID sizeMethod = (*env)->GetMethodID(env, setClass, "size", "()I"); + jmethodID iteratorMethod = (*env)->GetMethodID(env, setClass, "iterator", "()Ljava/util/Iterator;"); + if (!sizeMethod || !iteratorMethod) { + (*env)->DeleteLocalRef(env, setClass); + (*env)->DeleteLocalRef(env, set); + return NULL; + } + + jint size = (*env)->CallIntMethod(env, set, sizeMethod); + jobject iterator = (*env)->CallObjectMethod(env, set, iteratorMethod); + (*env)->DeleteLocalRef(env, setClass); + + if (!iterator) { + (*env)->DeleteLocalRef(env, set); + return NULL; + } + + jclass iteratorClass = (*env)->GetObjectClass(env, iterator); + jmethodID hasNextMethod = (*env)->GetMethodID(env, iteratorClass, "hasNext", "()Z"); + jmethodID nextMethod = (*env)->GetMethodID(env, iteratorClass, "next", "()Ljava/lang/Object;"); + if (!hasNextMethod || !nextMethod) { + (*env)->DeleteLocalRef(env, iteratorClass); + (*env)->DeleteLocalRef(env, iterator); + (*env)->DeleteLocalRef(env, set); + return NULL; + } + + char **ipAddresses = NULL; + if (size > 0) { + ipAddresses = (char **)calloc(size + 1, sizeof(char *)); // +1 for NULL-termination + if (!ipAddresses) { + (*env)->DeleteLocalRef(env, iteratorClass); + (*env)->DeleteLocalRef(env, iterator); + (*env)->DeleteLocalRef(env, set); + return NULL; + } + } + + size_t index = 0; + while ((*env)->CallBooleanMethod(env, iterator, hasNextMethod)) { + jstring element = (jstring)(*env)->CallObjectMethod(env, iterator, nextMethod); + if (!element) break; + const char *peerStr = (*env)->GetStringUTFChars(env, element, NULL); + if (peerStr) { + ipAddresses[index] = strdup(peerStr); + (*env)->ReleaseStringUTFChars(env, element, peerStr); + index++; + } + (*env)->DeleteLocalRef(env, element); + } + + if (ipAddresses) + ipAddresses[index] = NULL; // NULL-terminate + + (*env)->DeleteLocalRef(env, iteratorClass); + (*env)->DeleteLocalRef(env, iterator); + (*env)->DeleteLocalRef(env, set); + + return ipAddresses; +} + static void threadCleanup(void *info) { if (_jvmPM) (*_jvmPM)->DetachCurrentThread(_jvmPM); @@ -279,9 +382,10 @@ Java_com_brainwallet_wallet_BRPeerManager_create(JNIEnv *env, jobject thiz, _peerManager = BRPeerManagerNew(&BR_CHAIN_PARAMS, _wallet, (uint32_t) earliestKeyTime, _blocks, (size_t) blocksCount, _peers, (size_t) peersCount, (double) fpRate); + BRPeerManagerSetCallbacks(_peerManager, NULL, syncStarted, syncStopped, txStatusUpdate, - saveBlocks, savePeers, networkIsReachable, threadCleanup); + saveBlocks, savePeers, networkIsReachable, threadCleanup, featureSelectedPeersEnabled, fetchSelectedPeers); } if (_peerManager == NULL) { From ef4e6d2744eb29851db792604e22656477bd9bb2 Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Wed, 16 Apr 2025 05:30:37 +0700 Subject: [PATCH 18/65] feat: filter out peers with NODE_NETWORK, NODE_BLOOM --- .../data/repository/SelectedPeersRepository.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt index 766cfb7d..008453a0 100644 --- a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt @@ -9,6 +9,7 @@ import okhttp3.Callback import okhttp3.OkHttpClient import okhttp3.Response import okio.IOException +import timber.log.Timber import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -54,12 +55,19 @@ interface SelectedPeersRepository { val dataObject = jsonElement.jsonObject["data"]?.jsonObject val nodesObject = dataObject?.get("nodes")?.jsonObject - //TODO: need filter criteria here? - nodesObject?.keys - ?.filter { it.endsWith(":9333") } - ?.map { it.replace(":9333", "") } - ?.toSet() + //filter criteria + val requiredServices = 0x01 or 0x04 // NODE_NETWORK | NODE_BLOOM + + nodesObject?.entries + ?.filter { entry -> + val flags = + entry.value.jsonObject["flags"]?.toString()?.toIntOrNull() + flags != null && (flags and requiredServices) == requiredServices + } + ?.map { it.key.replace(":9333", "") } + ?.toSet().also { Timber.d("Total Selected Peers ${it?.size}") } ?: emptySet() + } ?: emptySet() sharedPreferences.edit { From 23369394c110dc5c310efa3d01645b24c2c1ead5 Mon Sep 17 00:00:00 2001 From: andhikayuana Date: Wed, 16 Apr 2025 12:19:12 +0700 Subject: [PATCH 19/65] fix: race condition when clear shared prefs values after wipeAll --- app/src/main/java/com/brainwallet/wallet/BRWalletManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java index 792fad8e..42d460d9 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java @@ -232,12 +232,12 @@ public void wipeWalletButKeystore(final Context ctx) { @Override public void run() { Timber.d("timber: Running peerManagerFreeEverything"); + BRSharedPrefs.clearAllPrefs(ctx); BRPeerManager.getInstance().peerManagerFreeEverything(); walletFreeEverything(); TransactionDataSource.getInstance(ctx).deleteAllTransactions(); MerkleBlockDataSource.getInstance(ctx).deleteAllBlocks(); PeerDataSource.getInstance(ctx).deleteAllPeers(); - BRSharedPrefs.clearAllPrefs(ctx); } }); } From 391e319fa920ea79bf4ddf00e2f4b4a89b16d241 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Wed, 16 Apr 2025 08:21:49 +0100 Subject: [PATCH 20/65] Updating the core library from the new peer discovery (v4.2.0) --- app/src/main/jni/core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/jni/core b/app/src/main/jni/core index 86649c2d..55b43a86 160000 --- a/app/src/main/jni/core +++ b/app/src/main/jni/core @@ -1 +1 @@ -Subproject commit 86649c2dd89d4c1e13fb58de4aa07567f3ac11bd +Subproject commit 55b43a869300dfc82ead7faa87e71626d580b464 From 836b6f097d8953701140c3e231cc66a22e46923f Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Fri, 25 Apr 2025 16:02:14 +0700 Subject: [PATCH 21/65] Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington --- app/build.gradle.kts | 4 +- .../brainwallet/data/model/CurrencyEntity.kt | 27 +----- .../java/com/brainwallet/data/model/Fee.kt | 37 +++++++++ .../data/repository/LtcRepository.kt | 47 +++++++---- .../repository/SelectedPeersRepository.kt | 5 ++ .../data/source/RemoteApiSource.kt | 5 +- .../main/java/com/brainwallet/di/Module.kt | 23 +++-- .../brainwallet/presenter/entities/Fee.java | 15 ---- .../tools/manager/BRSharedPrefs.java | 83 ++++++++++++------- .../brainwallet/tools/manager/FeeManager.java | 51 +++++++----- .../tools/manager/SyncManager.java | 51 ++++-------- .../brainwallet/tools/threads/BRExecutor.java | 16 ++++ .../brainwallet/tools/util/BRConstants.java | 4 +- .../com/brainwallet/ui/BrainwalletActivity.kt | 5 -- .../ui/screens/home/SettingsEvent.kt | 5 +- .../ui/screens/home/SettingsState.kt | 1 + .../ui/screens/home/SettingsViewModel.kt | 7 +- .../home/composable/HomeSettingDrawerSheet.kt | 14 +++- .../yourseedproveit/YourSeedProveItEvent.kt | 1 + .../yourseedproveit/YourSeedProveItScreen.kt | 3 +- .../yourseedproveit/YourSeedProveItState.kt | 7 +- .../YourSeedProveItViewModel.kt | 18 ++-- .../yourseedwords/YourSeedWordsEvent.kt | 2 +- .../yourseedwords/YourSeedWordsScreen.kt | 12 ++- .../yourseedwords/YourSeedWordsViewModel.kt | 11 +-- .../com/brainwallet/wallet/BRPeerManager.java | 21 +++-- app/src/main/jni/core | 2 +- app/src/main/jni/transition/PeerManager.c | 2 +- app/src/main/res/values/strings.xml | 1 + 29 files changed, 292 insertions(+), 188 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/model/Fee.kt delete mode 100644 app/src/main/java/com/brainwallet/presenter/entities/Fee.java diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b8f91239..3d4cb0e2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202503312 - versionName = "v4.4.3" + versionCode = 202504251 + versionName = "v4.4.7" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt index 1ccba70c..a46406bc 100644 --- a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt +++ b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.kt @@ -14,29 +14,4 @@ data class CurrencyEntity( var rate: Float = 0F, @JvmField var symbol: String = "" -) : Serializable { -// @JvmField -// var code: String? = null -// @JvmField -// var name: String? = null -// @JvmField -// var rate: Float = 0f -// @JvmField -// var symbol: String? = null -// -// constructor(code: String?, name: String?, rate: Float, symbol: String?) { -// this.code = code -// this.name = name -// this.rate = rate -// this.symbol = symbol -// } -// -// constructor() -// -// companion object { -// //Change this after modifying the class -// private const val serialVersionUID = 7526472295622776147L -// -// val TAG: String = CurrencyEntity::class.java.name -// } -} +) : Serializable \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/model/Fee.kt b/app/src/main/java/com/brainwallet/data/model/Fee.kt new file mode 100644 index 00000000..246100a4 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/model/Fee.kt @@ -0,0 +1,37 @@ +package com.brainwallet.data.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Fee( + @JvmField + @SerialName("fee_per_kb") + var luxury: Long, + @JvmField + @SerialName("fee_per_kb_economy") + var regular: Long, + @JvmField + @SerialName("fee_per_kb_luxury") + var economy: Long, + var timestamp: Long +) { + companion object { + //from legacy + // this is the default that matches the mobile-api if the server is unavailable + private const val defaultEconomyFeePerKB: Long = + 2500L // From legacy minimum. default min is 1000 as Litecoin Core version v0.17.1 + private const val defaultRegularFeePerKB: Long = 25000L + private const val defaultLuxuryFeePerKB: Long = 66746L + private const val defaultTimestamp: Long = 1583015199122L + + @JvmStatic + val Default = Fee( + defaultLuxuryFeePerKB, + defaultRegularFeePerKB, + defaultEconomyFeePerKB, + defaultTimestamp + ) + + } +} diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index 02358b34..31c05e30 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -2,6 +2,7 @@ package com.brainwallet.data.repository import android.content.Context import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Fee import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.tools.manager.BRSharedPrefs import com.brainwallet.tools.manager.FeeManager @@ -9,7 +10,8 @@ import com.brainwallet.tools.sqlite.CurrencyDataSource interface LtcRepository { suspend fun fetchRates(): List - //todo + + suspend fun fetchFeePerKb(): Fee class Impl( private val context: Context, @@ -19,22 +21,39 @@ interface LtcRepository { //todo: make it offline first here later, currently just using CurrencyDataSource.getAllCurrencies override suspend fun fetchRates(): List { - val rates = remoteApiSource.getRates() - - //legacy logic - FeeManager.updateFeePerKb(context) - val selectedISO = BRSharedPrefs.getIsoSymbol(context) - rates.forEachIndexed { index, currencyEntity -> - if (currencyEntity.code.equals(selectedISO, ignoreCase = true)) { - BRSharedPrefs.putIso(context, currencyEntity.code) - BRSharedPrefs.putCurrencyListPosition(context, index - 1) + return runCatching { + val rates = remoteApiSource.getRates() + + //legacy logic + FeeManager.updateFeePerKb(context) + val selectedISO = BRSharedPrefs.getIsoSymbol(context) + rates.forEachIndexed { index, currencyEntity -> + if (currencyEntity.code.equals(selectedISO, ignoreCase = true)) { + BRSharedPrefs.putIso(context, currencyEntity.code) + BRSharedPrefs.putCurrencyListPosition(context, index - 1) + } } - } - //save to local - currencyDataSource.putCurrencies(rates) - return rates + //save to local + currencyDataSource.putCurrencies(rates) + return rates + }.getOrElse { currencyDataSource.getAllCurrencies(true) } + + } + + override suspend fun fetchFeePerKb(): Fee { + return runCatching { + val fee = remoteApiSource.getFeePerKb() + + //todo: cache + + return fee + }.getOrElse { Fee.Default } } } + + companion object { + + } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt index 008453a0..0275d542 100644 --- a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt @@ -50,6 +50,11 @@ interface SelectedPeersRepository { override fun onResponse(call: Call, response: Response) { val jsonString = response.body?.string() + if (response.isSuccessful.not()) { + continuation.resume(cachedPeers ?: emptySet()) + return + } + val parsedResult = jsonString?.let { val jsonElement = json.parseToJsonElement(it) val dataObject = jsonElement.jsonObject["data"]?.jsonObject diff --git a/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt b/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt index 0ce3bdc8..60c865e2 100644 --- a/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt +++ b/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt @@ -1,16 +1,17 @@ package com.brainwallet.data.source import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Fee import retrofit2.http.GET //TODO interface RemoteApiSource { - @GET("api/v1/rates") + @GET("v1/rates") suspend fun getRates(): List @GET("v1/fee-per-kb") - suspend fun getFeePerKb() + suspend fun getFeePerKb(): Fee // https://prod.apigsltd.net/moonpay/buy?address=ltc1qjnsg3p9rt4r4vy7ncgvrywdykl0zwhkhcp8ue0&code=USD&idate=1742331930290&uid=ec51fa950b271ff3 // suspend fun getMoonPayBuy() diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index e64e071a..4dce30f1 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -4,10 +4,10 @@ import android.content.Context import android.content.SharedPreferences import com.brainwallet.BuildConfig import com.brainwallet.data.repository.LtcRepository +import com.brainwallet.data.repository.SelectedPeersRepository import com.brainwallet.data.repository.SettingRepository import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.data.repository.SelectedPeersRepository import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.screens.home.SettingsViewModel @@ -31,6 +31,7 @@ import org.koin.android.ext.koin.androidApplication import org.koin.core.module.dsl.viewModel import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module +import retrofit2.HttpException import retrofit2.Retrofit import retrofit2.converter.kotlinx.serialization.asConverterFactory @@ -46,7 +47,7 @@ val dataModule = module { factory { provideOkHttpClient() } single { provideRetrofit(get(), BRConstants.BW_API_PROD_HOST) } - single { provideApi(get()) } + single { provideApi(get()) } single { RemoteConfigSource.FirebaseImpl(Firebase.remoteConfig).also { @@ -91,17 +92,25 @@ private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() .addHeader("Content-Type", "application/json") .addHeader("X-Litecoin-Testnet", "false") .addHeader("Accept-Language", "en") -// .addHeader("User-agent",) chain.proceed(requestBuilder.build()) } .addInterceptor { chain -> val request = chain.request() runCatching { - chain.proceed(request) + val result = chain.proceed(request) + if (result.isSuccessful.not()) { + throw HttpException( + retrofit2.Response.error( + result.code, + result.body ?: result.peekBody(Long.MAX_VALUE) + ) + ) + } + result }.getOrElse { //retry using dev host val newRequest = request.newBuilder() - .url(BRConstants.BW_API_DEV_HOST + request.url.encodedPath) + .url("${BRConstants.LEGACY_BW_API_DEV_HOST}/api${request.url.encodedPath}") //legacy dev api need prefix path /api .build() chain.proceed(newRequest) } @@ -129,5 +138,5 @@ internal fun provideRetrofit( ) .build() -internal fun provideApi(retrofit: Retrofit): RemoteApiSource = - retrofit.create(RemoteApiSource::class.java) \ No newline at end of file +internal inline fun provideApi(retrofit: Retrofit): T = + retrofit.create(T::class.java) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/entities/Fee.java b/app/src/main/java/com/brainwallet/presenter/entities/Fee.java deleted file mode 100644 index bbe80465..00000000 --- a/app/src/main/java/com/brainwallet/presenter/entities/Fee.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.brainwallet.presenter.entities; - -public class Fee { - public final long luxury; - public final long regular; - public final long economy; - public final long timestamp; - - public Fee(long luxury, long regular, long economy, long timestamp) { - this.luxury = luxury; - this.regular = regular; - this.economy = economy; - this.timestamp = timestamp; - } -} diff --git a/app/src/main/java/com/brainwallet/tools/manager/BRSharedPrefs.java b/app/src/main/java/com/brainwallet/tools/manager/BRSharedPrefs.java index a3edc499..6fd054b9 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/BRSharedPrefs.java +++ b/app/src/main/java/com/brainwallet/tools/manager/BRSharedPrefs.java @@ -3,15 +3,17 @@ import android.content.Context; import android.content.SharedPreferences; -import com.brainwallet.BrainwalletApp; +import android.util.Log; + import com.brainwallet.data.repository.SettingRepository; import com.brainwallet.tools.util.BRConstants; import org.koin.java.KoinJavaComponent; -import org.koin.mp.KoinPlatformTools_jvmKt; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Currency; +import java.util.Date; import java.util.List; import java.util.Locale; @@ -45,16 +47,14 @@ public static String getIsoSymbol(Context context) { try { if (defaultLanguage == "ru") { defIso = Currency.getInstance(new Locale("ru", "RU")).getCurrencyCode(); - } - else if (defaultLanguage == "en") { + } else if (defaultLanguage == "en") { defIso = Currency.getInstance(Locale.US).getCurrencyCode(); - } - else { + } else { defIso = Currency.getInstance(Locale.getDefault()).getCurrencyCode(); } } catch (IllegalArgumentException e) { Timber.e(e); - defIso = Currency.getInstance(Locale.US).getCurrencyCode(); + defIso = Currency.getInstance(Locale.US).getCurrencyCode(); } return settingsToGet.getString(SettingRepository.KEY_FIAT_CURRENCY_CODE, defIso); //using new shared prefs used by setting repository } @@ -74,38 +74,64 @@ public static void notifyIsoChanged(String iso) { } } - ////////////////////////////////////////////////////////////////////////////// - //////////////////// Active Shared Preferences /////////////////////////////// - public static void putLastSyncTimestamp(Context activity, long time) { - SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + /// /////////////////////////////////////////////////////////////////////////// + /// ///////////////// Active Shared Preferences /////////////////////////////// + + public static void putStartSyncTimestamp(Context context, long time) { + if (context == null) { + Log.e("BRSharedPrefs", "Context is null in putStartSyncTimestamp!"); + return; + } + SharedPreferences prefs = context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); - editor.putLong("lastSyncTime", time); + editor.putLong("startSyncTime", time); editor.apply(); } - public static long getLastSyncTimestamp(Context activity) { - SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); - return prefs.getLong("lastSyncTime", 0L); + + public static long getStartSyncTimestamp(Context context) { + if (context == null) { + Log.e("BRSharedPrefs", "Context is null in getStartSyncTimestamp!"); + } + SharedPreferences startSyncTime = context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + return startSyncTime.getLong("startSyncTime", System.currentTimeMillis()); } - public static void putStartSyncTimestamp(Context activity, long time) { - SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + + public static void putEndSyncTimestamp(Context context, long time) { + + if (context == null) { + Log.e("BRSharedPrefs", "Context is null in putEndSyncTimestamp!"); + return; + } + + SharedPreferences prefs = context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); - editor.putLong("startSyncTime", time); + editor.putLong("endSyncTime", time); editor.apply(); } - public static long getStartSyncTimestamp(Context activity) { - SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); - return prefs.getLong("startSyncTime", 0L); + + public static String getSyncMetadata(Context context) { + SharedPreferences syncMetadata = context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + return syncMetadata.getString("syncMetadata", " No Sync Duration metadata"); } - public static void putSyncTimeElapsed(Context activity, long time) { - SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + public static void putSyncMetadata(Context activity, long startSyncTime, long endSyncTime) { + SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, 0); SharedPreferences.Editor editor = prefs.edit(); - editor.putLong("syncTimeElapsed", time); + + double syncDuration = (double) (endSyncTime - startSyncTime) / 1_000.0 / 60.0; + + SimpleDateFormat sdf = new SimpleDateFormat("MMM dd HH:mm"); + Date startDate = new Date(startSyncTime); + Date endDate = new Date(endSyncTime); + + String formattedMetadata = String.format("Duration: %3.2f mins\nStarted: %d (%s)\nEnded: %d (%s)", syncDuration, startSyncTime, sdf.format(startDate), endSyncTime, sdf.format(endDate)); + editor.putString("syncMetadata", formattedMetadata); editor.apply(); } - public static long getSyncTimeElapsed(Context activity) { - SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); - return prefs.getLong("syncTimeElapsed", 0L); + + public static long getEndSyncTimestamp(Context context) { + SharedPreferences endSyncTime = context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + return endSyncTime.getLong("endSyncTime", System.currentTimeMillis()); } public static boolean getPhraseWroteDown(Context context) { @@ -232,9 +258,10 @@ public static void putUseFingerprint(Context activity, boolean use) { editor.putBoolean("useFingerprint", use); editor.apply(); } + public static int getStartHeight(Context context) { SharedPreferences settingsToGet = context.getSharedPreferences(BRConstants.PREFS_NAME, 0); - return settingsToGet.getInt(BRConstants.START_HEIGHT, 0); + return settingsToGet.getInt(BRConstants.START_HEIGHT, 0); } public static void putStartHeight(Context context, int startHeight) { diff --git a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java index 91e12a9e..963a56af 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java @@ -4,13 +4,14 @@ import androidx.annotation.StringDef; +import com.brainwallet.data.repository.LtcRepository; import com.brainwallet.presenter.entities.ServiceItems; +import com.brainwallet.tools.threads.BRExecutor; import com.brainwallet.tools.util.Utils; -import com.brainwallet.presenter.entities.Fee; +import com.brainwallet.data.model.Fee; import com.platform.APIClient; -import org.json.JSONException; -import org.json.JSONObject; +import org.koin.java.KoinJavaComponent; import java.io.IOException; import java.lang.annotation.Retention; @@ -24,16 +25,9 @@ import okhttp3.Response; import timber.log.Timber; - +//we are still using this, maybe in the future will deprecate? public final class FeeManager { - // this is the default that matches the mobile-api if the server is unavailable - private static final long defaultEconomyFeePerKB = 2_500L; // From legacy minimum. default min is 1000 as Litecoin Core version v0.17.1 - private static final long defaultRegularFeePerKB = 2_5000L; - private static final long defaultLuxuryFeePerKB = 66_746L; - private static final long defaultTimestamp = 1583015199122L; - - private Fee defaultValues = new Fee(defaultLuxuryFeePerKB, defaultRegularFeePerKB, defaultEconomyFeePerKB, defaultTimestamp); private static final FeeManager instance; @@ -50,7 +44,7 @@ public static FeeManager getInstance() { } private void initWithDefaultValues() { - currentFees = defaultValues; + currentFees = Fee.getDefault(); feeType = REGULAR; } @@ -75,22 +69,33 @@ public boolean isRegularFee() { public void setFees(long luxuryFee, long regularFee, long economyFee) { // TODO: to be implemented when feePerKB API will be ready + currentFees = new Fee(luxuryFee, regularFee, economyFee, System.currentTimeMillis()); } public static void updateFeePerKb(Context app) { - String jsonString = "{'fee_per_kb': 10000, 'fee_per_kb_economy': 2500, 'fee_per_kb_luxury': 66746}"; - try { - JSONObject obj = new JSONObject(jsonString); - // TODO: Refactor when mobile-api v0.4.0 is in prod - long regularFee = obj.optLong("fee_per_kb"); - long economyFee = obj.optLong("fee_per_kb_economy"); - long luxuryFee = obj.optLong("fee_per_kb_luxury"); - FeeManager.getInstance().setFees(luxuryFee, regularFee, economyFee); +// String jsonString = "{'fee_per_kb': 10000, 'fee_per_kb_economy': 2500, 'fee_per_kb_luxury': 66746}"; +// try { +// JSONObject obj = new JSONObject(jsonString); +// // TODO: Refactor when mobile-api v0.4.0 is in prod +// long regularFee = obj.optLong("fee_per_kb"); +// long economyFee = obj.optLong("fee_per_kb_economy"); +// long luxuryFee = obj.optLong("fee_per_kb_luxury"); +// FeeManager.getInstance().setFees(luxuryFee, regularFee, economyFee); +// BRSharedPrefs.putFeeTime(app, System.currentTimeMillis()); //store the time of the last successful fee fetch +// } catch (JSONException e) { +// Timber.e(new IllegalArgumentException("updateFeePerKb: FAILED: " + jsonString, e)); +// } + + LtcRepository ltcRepository = KoinJavaComponent.get(LtcRepository.class); + BRExecutor.getInstance().executeSuspend( + (coroutineScope, continuation) -> ltcRepository.fetchFeePerKb(continuation) + ).whenComplete((fee, throwable) -> { + + //legacy logic + FeeManager.getInstance().setFees(fee.luxury, fee.regular, fee.economy); BRSharedPrefs.putFeeTime(app, System.currentTimeMillis()); //store the time of the last successful fee fetch - } catch (JSONException e) { - Timber.e(new IllegalArgumentException("updateFeePerKb: FAILED: " + jsonString, e)); - } + }); } // createGETRequestURL diff --git a/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java b/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java index 42e195f5..ace9dcc1 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java @@ -1,5 +1,7 @@ package com.brainwallet.tools.manager; +import static com.brainwallet.tools.manager.BRSharedPrefs.putSyncMetadata; + import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; @@ -44,8 +46,6 @@ public synchronized void startSyncingProgressThread(Context app) { } syncTask = new SyncProgressTask(); syncTask.start(); - BRSharedPrefs.putStartSyncTimestamp(app, System.currentTimeMillis()); - BRSharedPrefs.putSyncTimeElapsed(app, 0L); updateStartSyncData(app); } catch (IllegalThreadStateException ex) { Timber.e(ex); @@ -54,41 +54,11 @@ public synchronized void startSyncingProgressThread(Context app) { private synchronized void updateStartSyncData(Context app) { final double progress = BRPeerManager.syncProgress(BRSharedPrefs.getStartHeight(app)); - long startSync = BRSharedPrefs.getStartSyncTimestamp(app); - long lastSync = BRSharedPrefs.getLastSyncTimestamp(app); - long elapsed = BRSharedPrefs.getSyncTimeElapsed(app); - - if (elapsed > 0L) { - elapsed = (System.currentTimeMillis() - lastSync) + elapsed; - } - else { - elapsed = 1L; - } - BRSharedPrefs.putLastSyncTimestamp(app, System.currentTimeMillis()); - BRSharedPrefs.putSyncTimeElapsed(app, elapsed); - double minutesValue = ((double) elapsed / 1_000.0 / 60.0); - String minutesString = String.format( "%3.2f mins", minutesValue); - String millisecString = String.format( "%5d msec", elapsed); - Timber.d("timber: ||\nprogress: %s\nThread: %s\nrunning lastSyncingTime: %s\nelapsed: %s | %s", String.format( "%.2f", progress * 100.00),Thread.currentThread().getName(),String.valueOf(BRSharedPrefs.getLastSyncTimestamp(app)), millisecString, minutesString); - } private synchronized void markFinishedSyncData(Context app) { - Timber.d("timber: || markFinish threadname:%s", Thread.currentThread().getName()); + Timber.d("timber: || SYNC ELAPSE markFinish threadname:%s", Thread.currentThread().getName()); final double progress = BRPeerManager.syncProgress(BRSharedPrefs.getStartHeight(app)); - long startSync = BRSharedPrefs.getStartSyncTimestamp(app); - long lastSync = BRSharedPrefs.getLastSyncTimestamp(app); - long elapsed = BRSharedPrefs.getSyncTimeElapsed(app); - double minutesValue = ((double) elapsed / 1_000.0 / 60.0); - String minutesString = String.format( "%3.2f mins", minutesValue); - String millisecString = String.format( "%5d msec", elapsed); - Timber.d("timber: ||\ncompletedprogress: %s\nstartSyncTime: %s\nlastSyncingTime: %s\ntotalTimeelapsed: %s | %s", String.format( "%.2f", progress * 100.00),String.valueOf(startSync),String.valueOf(lastSync), millisecString, minutesString); - - Bundle params = new Bundle(); - params.putDouble("sync_time_elapsed", minutesValue); - params.putLong("sync_start_timestamp", startSync); - params.putLong("sync_last_timestamp", lastSync); - AnalyticsManager.logCustomEventWithParams(BRConstants._20230407_DCS, params); } public synchronized void stopSyncingProgressThread(Context app) { @@ -139,7 +109,10 @@ public void run() { app = BreadActivity.getApp(); progressStatus = 0; running = true; - Timber.d("timber: run: starting: %s", progressStatus); + long runTimeStamp = System.currentTimeMillis(); + Timber.d("timber: run: starting: %s date: %d", progressStatus, runTimeStamp); + ///Set StartSync + BRSharedPrefs.putStartSyncTimestamp(app, runTimeStamp); if (app != null) { final long lastBlockTimeStamp = BRPeerManager.getInstance().getLastBlockTimestamp() * 1000; @@ -162,6 +135,16 @@ public void run() { progressStatus = BRPeerManager.syncProgress(startHeight); if (progressStatus == 1) { running = false; + /// Record sync time + long startTimeStamp = BRSharedPrefs.getStartSyncTimestamp(app); + long endSyncTimeStamp = System.currentTimeMillis(); + BRSharedPrefs.putEndSyncTimestamp(app, endSyncTimeStamp); + + double syncDuration = (double) (endSyncTimeStamp - startTimeStamp) / 1_000.0 / 60.0; + /// only update if the sync duration is longer than 2 mins + if (syncDuration > 2.0) { + putSyncMetadata(app, startTimeStamp, endSyncTimeStamp); + } continue; } final long lastBlockTimeStamp = BRPeerManager.getInstance().getLastBlockTimestamp() * 1000; diff --git a/app/src/main/java/com/brainwallet/tools/threads/BRExecutor.java b/app/src/main/java/com/brainwallet/tools/threads/BRExecutor.java index ec127999..b1b21255 100644 --- a/app/src/main/java/com/brainwallet/tools/threads/BRExecutor.java +++ b/app/src/main/java/com/brainwallet/tools/threads/BRExecutor.java @@ -1,5 +1,6 @@ package com.brainwallet.tools.threads; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; @@ -7,6 +8,12 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import kotlin.coroutines.Continuation; +import kotlin.coroutines.EmptyCoroutineContext; +import kotlinx.coroutines.CoroutineScope; +import kotlinx.coroutines.CoroutineScopeKt; +import kotlinx.coroutines.CoroutineStart; +import kotlinx.coroutines.future.FutureKt; import timber.log.Timber; /* @@ -130,4 +137,13 @@ public Executor forMainThreadTasks() { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { Timber.d("timber: rejectedExecution: "); } + + public CompletableFuture executeSuspend(kotlin.jvm.functions.Function2, ? extends Object> paramToExec) { + return FutureKt.future( + CoroutineScopeKt.CoroutineScope(EmptyCoroutineContext.INSTANCE), + EmptyCoroutineContext.INSTANCE, + CoroutineStart.DEFAULT, + paramToExec + ); + } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/tools/util/BRConstants.java b/app/src/main/java/com/brainwallet/tools/util/BRConstants.java index 5788f6de..1c4d4a53 100644 --- a/app/src/main/java/com/brainwallet/tools/util/BRConstants.java +++ b/app/src/main/java/com/brainwallet/tools/util/BRConstants.java @@ -106,8 +106,8 @@ private BRConstants() { /** * API Hosts */ - public static final String BW_API_PROD_HOST = "https://prod.apigsltd.net"; - public static final String BW_API_DEV_HOST = "https://dev.apigsltd.net"; + public static final String BW_API_PROD_HOST = "https://api.grunt.ltd"; + public static final String LEGACY_BW_API_DEV_HOST = "https://dev.apigsltd.net"; public static final String BLOCK_EXPLORER_BASE_URL = "https://blockchair.com/litecoin/transaction/"; diff --git a/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt b/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt index 34608ffd..8ef9dfda 100644 --- a/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt +++ b/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt @@ -32,7 +32,6 @@ import com.brainwallet.ui.screens.inputwords.InputWordsViewModel.Companion.LEGAC import com.brainwallet.ui.screens.inputwords.InputWordsViewModel.Companion.LEGACY_DIALOG_WIPE_ALERT import com.brainwallet.ui.screens.inputwords.InputWordsViewModel.Companion.LEGACY_EFFECT_RESET_PIN import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItViewModel.Companion.LEGACY_EFFECT_ON_PAPERKEY_PROVED -import com.brainwallet.ui.screens.yourseedwords.YourSeedWordsViewModel.Companion.LEGACY_EFFECT_ON_SAVED_PAPERKEY import com.brainwallet.ui.theme.BrainwalletAppTheme import com.brainwallet.util.EventBus import com.brainwallet.wallet.BRWalletManager @@ -114,10 +113,6 @@ class BrainwalletActivity : BRActivity() { } } - LEGACY_EFFECT_ON_SAVED_PAPERKEY -> { - PostAuth.getInstance().onPhraseProveAuth(this, false) - } - LEGACY_EFFECT_ON_PAPERKEY_PROVED -> { BRSharedPrefs.putPhraseWroteDown(this@BrainwalletActivity, true) LegacyNavigation.startBreadActivity( diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt index 531305b6..48e0750a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt @@ -4,7 +4,10 @@ import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Language sealed class SettingsEvent { - data class OnLoad(val shareAnalyticsDataEnabled: Boolean = false) : SettingsEvent() + data class OnLoad( + val shareAnalyticsDataEnabled: Boolean = false, + val lastSyncMetadata: String? = null, + ) : SettingsEvent() object OnSecurityUpdatePinClick : SettingsEvent() object OnSecuritySeedPhraseClick : SettingsEvent() object OnSecurityShareAnalyticsDataClick : SettingsEvent() diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt index 3efe10a7..9f924c3c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt @@ -14,4 +14,5 @@ data class SettingsState( val languageSelectorBottomSheetVisible: Boolean = false, val fiatSelectorBottomSheetVisible: Boolean = false, val shareAnalyticsDataEnabled: Boolean = false, + val lastSyncMetadata: String? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt index 7ec71f98..e9515ce8 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt @@ -47,7 +47,12 @@ class SettingsViewModel( override fun onEvent(event: SettingsEvent) { when (event) { is SettingsEvent.OnLoad -> viewModelScope.launch { - _state.update { it.copy(shareAnalyticsDataEnabled = event.shareAnalyticsDataEnabled) } + _state.update { + it.copy( + shareAnalyticsDataEnabled = event.shareAnalyticsDataEnabled, + lastSyncMetadata = event.lastSyncMetadata + ) + } } SettingsEvent.OnToggleDarkMode -> viewModelScope.launch { diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt index 497770f8..42b370a8 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -6,6 +6,7 @@ import android.util.AttributeSet import androidx.browser.customtabs.CustomTabsIntent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn @@ -57,7 +58,10 @@ fun HomeSettingDrawerSheet( val context = LocalContext.current LaunchedEffect(Unit) { - viewModel.onEvent(SettingsEvent.OnLoad(BRSharedPrefs.getShareData(context))) //currently just load analytics share data here + viewModel.onEvent(SettingsEvent.OnLoad( + shareAnalyticsDataEnabled = BRSharedPrefs.getShareData(context), //currently just load analytics share data here + lastSyncMetadata = BRSharedPrefs.getSyncMetadata(context) //currently just load sync metadata here + )) } /// Layout values @@ -173,6 +177,14 @@ fun HomeSettingDrawerSheet( ) } + item { + SettingRowItem( + modifier = Modifier.height(100.dp), + title = stringResource(R.string.settings_title_sync_metadata), + description = state.lastSyncMetadata ?: "No sync metadata" + ) + } + item { SettingRowItem( title = stringResource(R.string.settings_title_app_version), diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt index d9f530b0..68816d6a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt @@ -6,6 +6,7 @@ sealed class YourSeedProveItEvent { ) : YourSeedProveItEvent() data class OnDropSeedWordItem( + val index: Int, val expectedWord: String, val actualWord: String ) : YourSeedProveItEvent() diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt index 3e793c6a..171186ab 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt @@ -147,7 +147,7 @@ fun YourSeedProveItScreen( verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), maxItemsInEachRow = maxItemsPerRow ) { - state.correctSeedWords.entries.forEachIndexed { index, (expectedWord, actualWord) -> + state.correctSeedWords.values.forEachIndexed { index, (expectedWord, actualWord) -> val label = if (expectedWord != actualWord && actualWord.isEmpty()) { "${index + 1}" @@ -173,6 +173,7 @@ fun YourSeedProveItScreen( viewModel.onEvent( YourSeedProveItEvent.OnDropSeedWordItem( + index = index, expectedWord = expectedWord, actualWord = text.toString() ) diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt index 991763a2..1da5cc92 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt @@ -1,7 +1,12 @@ package com.brainwallet.ui.screens.yourseedproveit data class YourSeedProveItState( - val correctSeedWords: Map = mapOf(), + val correctSeedWords: Map = emptyMap(), val shuffledSeedWords: List = emptyList(), val orderCorrected: Boolean = false, ) + +data class SeedWordItem( + val expected: String, + val actual: String = "" +) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt index 99af1398..6f4d19c4 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt @@ -18,25 +18,31 @@ class YourSeedProveItViewModel : BrainwalletViewModel() { when (event) { is YourSeedProveItEvent.OnLoad -> _state.update { it.copy( - correctSeedWords = event.seedWords.associateWith { "" }, + correctSeedWords = event.seedWords.mapIndexed { index, word -> + index to SeedWordItem(expected = word) + }.toMap(), shuffledSeedWords = event.seedWords.shuffled() ) } is YourSeedProveItEvent.OnDropSeedWordItem -> _state.update { - val correctSeedWords = it.correctSeedWords.toMutableMap().apply { - this[event.expectedWord] = event.actualWord - } + val correctSeedWords = it.correctSeedWords.map { (index, seedWordItem) -> + if (index == event.index && seedWordItem.expected == event.expectedWord) { + index to seedWordItem.copy(actual = event.actualWord) + } else { + index to seedWordItem + } + }.toMap() it.copy( correctSeedWords = correctSeedWords, - orderCorrected = correctSeedWords.all { (expectedWord, actualWord) -> expectedWord == actualWord } + orderCorrected = correctSeedWords.all { (_, seedWordItem) -> seedWordItem.expected == seedWordItem.actual } ) } YourSeedProveItEvent.OnClear -> _state.update { it.copy( - correctSeedWords = it.correctSeedWords.mapValues { "" } + correctSeedWords = it.correctSeedWords.mapValues { SeedWordItem(expected = it.value.expected) } ) } diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsEvent.kt index 9f9db09b..ba2cbde0 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsEvent.kt @@ -1,5 +1,5 @@ package com.brainwallet.ui.screens.yourseedwords sealed class YourSeedWordsEvent { - object OnSavedItClick : YourSeedWordsEvent() + data class OnSavedItClick(val seedWords: List) : YourSeedWordsEvent() } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt index bd2e5119..c541f588 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -51,6 +52,15 @@ fun YourSeedWordsScreen( val leadingCopyPadding = 16 val detailLineHeight = 28 + LaunchedEffect(Unit) { + viewModel.uiEffect.collect { effect -> + when (effect) { + is UiEffect.Navigate -> onNavigate.invoke(effect) + else -> Unit + } + } + } + BrainwalletScaffold( topBar = { BrainwalletTopAppBar( @@ -122,7 +132,7 @@ fun YourSeedWordsScreen( LargeButton( onClick = { - viewModel.onEvent(YourSeedWordsEvent.OnSavedItClick) + viewModel.onEvent(YourSeedWordsEvent.OnSavedItClick(seedWords)) }, ) { Text( diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt index 650a4381..562b8b97 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt @@ -1,21 +1,18 @@ package com.brainwallet.ui.screens.yourseedwords import androidx.lifecycle.viewModelScope +import com.brainwallet.navigation.Route +import com.brainwallet.navigation.UiEffect import com.brainwallet.ui.BrainwalletViewModel -import com.brainwallet.util.EventBus import kotlinx.coroutines.launch class YourSeedWordsViewModel : BrainwalletViewModel() { override fun onEvent(event: YourSeedWordsEvent) { when (event) { - YourSeedWordsEvent.OnSavedItClick -> viewModelScope.launch { - EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_SAVED_PAPERKEY)) + is YourSeedWordsEvent.OnSavedItClick -> viewModelScope.launch { + sendUiEffect(UiEffect.Navigate(destinationRoute = Route.YourSeedProveIt(event.seedWords))) } } } - - companion object { - const val LEGACY_EFFECT_ON_SAVED_PAPERKEY = "onSavedPaperKey" - } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java b/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java index 209814e7..6f591402 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRPeerManager.java @@ -72,7 +72,6 @@ public static void syncStarted() { public static void syncSucceeded() { Context ctx = BrainwalletApp.getBreadContext(); if (ctx == null) return; - BRSharedPrefs.putLastSyncTimestamp(ctx, System.currentTimeMillis()); SyncManager.getInstance().updateAlarms(ctx); BRSharedPrefs.putAllowSpend(ctx, true); SyncManager.getInstance().stopSyncingProgressThread(ctx); @@ -99,9 +98,12 @@ public static void syncFailed() { public static void txStatusUpdate() { Timber.d("timber: txStatusUpdate"); - for (OnTxStatusUpdate listener : statusUpdateListeners) { - if (listener != null) listener.onStatusUpdate(); + synchronized (statusUpdateListeners) { + for (OnTxStatusUpdate listener : statusUpdateListeners) { + if (listener != null) listener.onStatusUpdate(); + } } + BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { @@ -192,11 +194,14 @@ public void run() { //wrap logic enable/disable connect with new flow public void wrapConnectV2() { - if (featureSelectedPeersEnabled()) { - fetchSelectedPeers().whenComplete((strings, throwable) -> connect()); - } else { - connect(); - } +// if (featureSelectedPeersEnabled()) { +// fetchSelectedPeers().whenComplete((strings, throwable) -> connect()); +// } else { +// connect(); +// } + //currently we are just using connect(), since the core using hardcoded peers + //https://github.com/gruntsoftware/core/commit/0b7f85feac840c7667338c340c808dfccde4251a + connect(); } public static boolean featureSelectedPeersEnabled() { diff --git a/app/src/main/jni/core b/app/src/main/jni/core index 55b43a86..28d7d31a 160000 --- a/app/src/main/jni/core +++ b/app/src/main/jni/core @@ -1 +1 @@ -Subproject commit 55b43a869300dfc82ead7faa87e71626d580b464 +Subproject commit 28d7d31ae057bdde33b1d19e6b7af3ba07710c89 diff --git a/app/src/main/jni/transition/PeerManager.c b/app/src/main/jni/transition/PeerManager.c index 4c2ce73e..8d249725 100644 --- a/app/src/main/jni/transition/PeerManager.c +++ b/app/src/main/jni/transition/PeerManager.c @@ -385,7 +385,7 @@ Java_com_brainwallet_wallet_BRPeerManager_create(JNIEnv *env, jobject thiz, BRPeerManagerSetCallbacks(_peerManager, NULL, syncStarted, syncStopped, txStatusUpdate, - saveBlocks, savePeers, networkIsReachable, threadCleanup, featureSelectedPeersEnabled, fetchSelectedPeers); + saveBlocks, savePeers, networkIsReachable, threadCleanup); } if (_peerManager == NULL) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4d2d53f..1b2f4e52 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -825,6 +825,7 @@ Unlock Theme App version: + Sync metadata: Sync Sync duration: >20 minutes Game %1$d: From 3caa1a7702878a54fa87f326523197797a5fbdb0 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Tue, 29 Apr 2025 12:33:29 +0700 Subject: [PATCH 22/65] feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) --- app/src/main/AndroidManifest.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ffbd7a0e..dd68f40a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -96,11 +96,6 @@ android:exported="true" android:launchMode="singleTask" android:screenOrientation="portrait" /> - Date: Fri, 2 May 2025 13:23:05 +0700 Subject: [PATCH 23/65] fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) --- app/src/main/java/com/brainwallet/di/Module.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 4dce30f1..3b666d1f 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -97,16 +97,17 @@ private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() .addInterceptor { chain -> val request = chain.request() runCatching { - val result = chain.proceed(request) - if (result.isSuccessful.not()) { - throw HttpException( - retrofit2.Response.error( - result.code, - result.body ?: result.peekBody(Long.MAX_VALUE) + chain.proceed(request).use { response -> + if (response.isSuccessful.not()) { + throw HttpException( + retrofit2.Response.error( + response.code, + response.body ?: response.peekBody(Long.MAX_VALUE) + ) ) - ) + } + response } - result }.getOrElse { //retry using dev host val newRequest = request.newBuilder() From 1f9c5d03496b86e16e90db38fc88ee376040f357 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Fri, 2 May 2025 08:05:53 +0100 Subject: [PATCH 24/65] code bump --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3d4cb0e2..80cc7aec 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,7 +20,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202504251 + versionCode = 202505021 versionName = "v4.4.7" multiDexEnabled = true From 7ca17d3615b80a71d0d004dc2e5eb45377e67196 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Mon, 5 May 2025 20:52:16 +0700 Subject: [PATCH 25/65] Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code --- .../java/com/brainwallet/data/model/Fee.kt | 58 +++- .../data/repository/LtcRepository.kt | 30 +- .../main/java/com/brainwallet/di/Module.kt | 2 +- .../presenter/fragments/FragmentSend.kt | 296 +++++++++++------- .../brainwallet/tools/manager/FeeManager.java | 85 +---- .../ui/screens/home/SettingsState.kt | 5 + .../ui/screens/home/SettingsViewModel.kt | 8 +- .../home/composable/HomeSettingDrawerSheet.kt | 4 +- .../settingsrows/LitecoinBlockchainDetail.kt | 112 ++++++- .../brainwallet/wallet/BRWalletManager.java | 6 +- app/src/main/res/layout/fragment_send.xml | 94 +----- app/src/main/res/values-ar/strings.xml | 4 + app/src/main/res/values-de/strings.xml | 4 + app/src/main/res/values-es/strings.xml | 8 +- app/src/main/res/values-fr/strings.xml | 4 + app/src/main/res/values-hi/strings.xml | 4 + app/src/main/res/values-in/strings.xml | 4 + app/src/main/res/values-it/strings.xml | 4 + app/src/main/res/values-ja/strings.xml | 4 + app/src/main/res/values-ko/strings.xml | 4 + app/src/main/res/values-pt/strings.xml | 4 + app/src/main/res/values-ru/strings.xml | 4 + app/src/main/res/values-sv/strings.xml | 4 + app/src/main/res/values-tr/strings.xml | 4 + app/src/main/res/values-uk/strings.xml | 4 + app/src/main/res/values-zh-rCN/strings.xml | 6 +- app/src/main/res/values-zh-rTW/strings.xml | 4 + app/src/main/res/values/strings.xml | 7 +- 28 files changed, 462 insertions(+), 315 deletions(-) diff --git a/app/src/main/java/com/brainwallet/data/model/Fee.kt b/app/src/main/java/com/brainwallet/data/model/Fee.kt index 246100a4..0ea99667 100644 --- a/app/src/main/java/com/brainwallet/data/model/Fee.kt +++ b/app/src/main/java/com/brainwallet/data/model/Fee.kt @@ -1,20 +1,27 @@ package com.brainwallet.data.model +import android.annotation.SuppressLint +import com.brainwallet.R +import com.brainwallet.tools.manager.FeeManager.ECONOMY +import com.brainwallet.tools.manager.FeeManager.FeeType +import com.brainwallet.tools.manager.FeeManager.LUXURY +import com.brainwallet.tools.manager.FeeManager.REGULAR import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlin.math.ceil +import kotlin.math.round @Serializable data class Fee( @JvmField - @SerialName("fee_per_kb") + @SerialName("fee_per_kb_luxury") var luxury: Long, @JvmField - @SerialName("fee_per_kb_economy") + @SerialName("fee_per_kb") var regular: Long, @JvmField - @SerialName("fee_per_kb_luxury") + @SerialName("fee_per_kb_economy") var economy: Long, - var timestamp: Long ) { companion object { //from legacy @@ -25,13 +32,52 @@ data class Fee( private const val defaultLuxuryFeePerKB: Long = 66746L private const val defaultTimestamp: Long = 1583015199122L +// {"fee_per_kb":5289,"fee_per_kb_economy":2645,"fee_per_kb_luxury":10578} + @JvmStatic val Default = Fee( defaultLuxuryFeePerKB, defaultRegularFeePerKB, defaultEconomyFeePerKB, - defaultTimestamp ) - } } + + +data class FeeOption( + @FeeType + val type: String, + val feePerKb: Long, + val labelStringId: Int, +) + +fun Fee.toFeeOptions(): List = listOf( + FeeOption( + type = ECONOMY, + feePerKb = economy, + labelStringId = R.string.network_fee_options_low + ), + FeeOption( + type = REGULAR, + feePerKb = regular, + labelStringId = R.string.network_fee_options_medium + ), + FeeOption( + type = LUXURY, + feePerKb = luxury, + labelStringId = R.string.network_fee_options_top + ), +) + +fun FeeOption.getFiat(currencyEntity: CurrencyEntity): Float { + val satoshisPerLtc = 100_000_000.0 + val feeInLtc = feePerKb / satoshisPerLtc + return (feeInLtc * currencyEntity.rate).toFloat() +} + +@SuppressLint("DefaultLocale") +fun FeeOption.getFiatFormatted(currencyEntity: CurrencyEntity): String { + val fiatValue = getFiat(currencyEntity) + val formatted = String.format("%.3f", fiatValue) + return "${currencyEntity.symbol}$formatted" +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index 31c05e30..38b325fd 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -1,12 +1,16 @@ package com.brainwallet.data.repository import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Fee import com.brainwallet.data.source.RemoteApiSource +import com.brainwallet.di.json import com.brainwallet.tools.manager.BRSharedPrefs import com.brainwallet.tools.manager.FeeManager import com.brainwallet.tools.sqlite.CurrencyDataSource +import kotlinx.serialization.encodeToString interface LtcRepository { suspend fun fetchRates(): List @@ -16,7 +20,8 @@ interface LtcRepository { class Impl( private val context: Context, private val remoteApiSource: RemoteApiSource, - private val currencyDataSource: CurrencyDataSource + private val currencyDataSource: CurrencyDataSource, + private val sharedPreferences: SharedPreferences, ) : LtcRepository { //todo: make it offline first here later, currently just using CurrencyDataSource.getAllCurrencies @@ -42,18 +47,33 @@ interface LtcRepository { } override suspend fun fetchFeePerKb(): Fee { + val lastUpdateTime = sharedPreferences.getLong(PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT, 0) + val currentTime = System.currentTimeMillis() + val cachedFee = sharedPreferences.getString(PREF_KEY_NETWORK_FEE_PER_KB, null) + ?.let { json.decodeFromString(it) } + return runCatching { - val fee = remoteApiSource.getFeePerKb() + // Check if cache exists and is less than 6 hours old + if (cachedFee != null && (currentTime - lastUpdateTime) < 6 * 60 * 60 * 1000) { + return cachedFee + } - //todo: cache + val fee = remoteApiSource.getFeePerKb() + sharedPreferences.edit { + putString(PREF_KEY_NETWORK_FEE_PER_KB, json.encodeToString(fee)) + putLong(PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT, currentTime) + } return fee - }.getOrElse { Fee.Default } + }.getOrElse { + cachedFee ?: Fee.Default + } } } companion object { - + const val PREF_KEY_NETWORK_FEE_PER_KB = "network_fee_per_kb" + const val PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT = "${PREF_KEY_NETWORK_FEE_PER_KB}_cached_at" } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 3b666d1f..8dcfb909 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -58,7 +58,7 @@ val dataModule = module { single { CurrencyDataSource.getInstance(get()) } single { provideSharedPreferences(context = androidApplication()) } single { SettingRepository.Impl(get(), get()) } - single { LtcRepository.Impl(get(), get(), get()) } + single { LtcRepository.Impl(get(), get(), get(), get()) } } val viewModelModule = module { diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt index 1f4af687..9b47690e 100644 --- a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt +++ b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt @@ -11,9 +11,12 @@ import android.view.ViewGroup import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.animation.OvershootInterpolator import android.view.inputmethod.EditorInfo -import android.widget.* -import androidx.annotation.ColorRes -import androidx.annotation.StringRes +import android.widget.Button +import android.widget.EditText +import android.widget.ImageButton +import android.widget.LinearLayout +import android.widget.ScrollView +import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.fragment.app.Fragment @@ -22,38 +25,53 @@ import androidx.transition.Transition import androidx.transition.TransitionManager import com.brainwallet.R import com.brainwallet.presenter.customviews.BRKeyboard -import com.brainwallet.presenter.customviews.BRLinearLayoutWithCaret import com.brainwallet.presenter.entities.ServiceItems import com.brainwallet.presenter.entities.TransactionItem import com.brainwallet.tools.animation.BRAnimator import com.brainwallet.tools.animation.BRDialog import com.brainwallet.tools.animation.SlideDetector import com.brainwallet.tools.animation.SpringAnimator -import com.brainwallet.tools.manager.* +import com.brainwallet.tools.manager.AnalyticsManager +import com.brainwallet.tools.manager.BRClipboardManager +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.tools.manager.FeeManager import com.brainwallet.tools.security.BRSender import com.brainwallet.tools.security.BitcoinUrlHandler import com.brainwallet.tools.threads.BRExecutor -import com.brainwallet.tools.util.* +import com.brainwallet.tools.util.BRConstants +import com.brainwallet.tools.util.BRCurrency +import com.brainwallet.tools.util.BRExchange +import com.brainwallet.tools.util.Utils import com.brainwallet.wallet.BRWalletManager -import com.google.common.math.Quantiles.scale import timber.log.Timber import java.math.BigDecimal import java.math.RoundingMode import java.util.regex.Pattern +//TODO: make sure remove unused after refactor network fee move to HomeSettingDrawerSheet class FragmentSend : Fragment() { - private lateinit var signalLayout: LinearLayout; private lateinit var keyboardLayout: LinearLayout - private lateinit var scanButton: Button; private lateinit var pasteButton: Button; private lateinit var sendButton: Button; private lateinit var isoCurrencySymbolButton: Button - private lateinit var commentEdit: EditText; private lateinit var addressEdit: EditText;private lateinit var amountEdit: EditText - private lateinit var isoCurrencySymbolText: TextView; private lateinit var balanceText: TextView; private lateinit var feeText: TextView; private lateinit var feeDescription: TextView; private lateinit var warningText: TextView - private var amountLabelOn = true; private var ignoreCleanup = false; private var feeButtonsShown = false - private lateinit var edit: ImageView + private lateinit var signalLayout: LinearLayout; + private lateinit var keyboardLayout: LinearLayout + private lateinit var scanButton: Button; + private lateinit var pasteButton: Button; + private lateinit var sendButton: Button; + private lateinit var isoCurrencySymbolButton: Button + private lateinit var commentEdit: EditText; + private lateinit var addressEdit: EditText; + private lateinit var amountEdit: EditText + private lateinit var isoCurrencySymbolText: TextView; + private lateinit var balanceText: TextView; + private lateinit var feeText: TextView; + private lateinit var feeDescription: TextView; + private lateinit var warningText: TextView + private var amountLabelOn = true; + private var ignoreCleanup = false; + private var feeButtonsShown = false private var currentBalance: Long = 0 private var keyboardIndex = 0 private lateinit var keyboard: BRKeyboard private lateinit var closeButton: ImageButton private lateinit var amountLayout: ConstraintLayout - private lateinit var feeLayout: BRLinearLayoutWithCaret private var selectedIsoCurrencySymbol: String? = null private lateinit var backgroundLayout: ScrollView private lateinit var amountBuilder: StringBuilder @@ -78,16 +96,17 @@ class FragmentSend : Fragment() { amountEdit = rootView.findViewById(R.id.amount_edit) as EditText balanceText = rootView.findViewById(R.id.balance_text) as TextView feeText = rootView.findViewById(R.id.fee_text) as TextView - edit = rootView.findViewById(R.id.edit) as ImageView isoCurrencySymbolButton = rootView.findViewById(R.id.iso_button) as Button keyboardLayout = rootView.findViewById(R.id.keyboard_layout) as LinearLayout amountLayout = rootView.findViewById(R.id.amount_layout) as ConstraintLayout - feeLayout = rootView.findViewById(R.id.fee_buttons_layout) as BRLinearLayoutWithCaret - feeDescription = rootView.findViewById(R.id.fee_description) as TextView - warningText = rootView.findViewById(R.id.warning_text) as TextView +// feeLayout = rootView.findViewById(R.id.fee_buttons_layout) as BRLinearLayoutWithCaret +// feeDescription = rootView.findViewById(R.id.fee_description) as TextView +// warningText = rootView.findViewById(R.id.warning_text) as TextView closeButton = rootView.findViewById(R.id.close_button) as ImageButton selectedIsoCurrencySymbol = - if (BRSharedPrefs.getPreferredLTC(context)) "LTC" else BRSharedPrefs.getIsoSymbol(context) + if (BRSharedPrefs.getPreferredLTC(context)) "LTC" else BRSharedPrefs.getIsoSymbol( + context + ) amountBuilder = StringBuilder(0) setListeners() @@ -102,18 +121,20 @@ class FragmentSend : Fragment() { signalLayout.setOnTouchListener(SlideDetector(signalLayout) { animateClose() }) AnalyticsManager.logCustomEvent(BRConstants._20191105_VSC) - setupFeesSelector(rootView) - showFeeSelectionButtons(feeButtonsShown) - edit.setOnClickListener { - feeButtonsShown = !feeButtonsShown - showFeeSelectionButtons(feeButtonsShown) - } +// setupFeesSelector(rootView) +// showFeeSelectionButtons(feeButtonsShown) +// edit.setOnClickListener { +// feeButtonsShown = !feeButtonsShown +// showFeeSelectionButtons(feeButtonsShown) +// } keyboardIndex = signalLayout.indexOfChild(keyboardLayout) // TODO: all views are using the layout of this button. Views should be refactored without it // Hiding until layouts are built. showKeyboard(false) signalLayout.layoutTransition = BRAnimator.getDefaultTransition() - + + updateText() + return rootView } @@ -121,62 +142,62 @@ class FragmentSend : Fragment() { super.onActivityCreated(savedInstanceState) } - private fun setupFeesSelector(rootView: View) { - val feesSegment = rootView.findViewById(R.id.fees_segment) - feesSegment.setOnCheckedChangeListener { _, checkedTypeId -> onFeeTypeSelected(checkedTypeId) } - onFeeTypeSelected(R.id.regular_fee_but) - } - - private fun onFeeTypeSelected(checkedTypeId: Int) { - val feeManager = FeeManager.getInstance() - when (checkedTypeId) { - R.id.regular_fee_but -> { - feeManager.setFeeType(FeeManager.REGULAR) - BRWalletManager.getInstance().setFeePerKb(feeManager.currentFees.regular) - setFeeInformation(R.string.FeeSelector_regularTime, 0, 0, View.GONE) - } - R.id.economy_fee_but -> { - feeManager.setFeeType(FeeManager.ECONOMY) - BRWalletManager.getInstance().setFeePerKb(feeManager.currentFees.economy) - setFeeInformation( - R.string.FeeSelector_economyTime, - R.string.FeeSelector_economyWarning, - R.color.chili, - View.VISIBLE, - ) - } - R.id.luxury_fee_but -> { - feeManager.setFeeType(FeeManager.LUXURY) - BRWalletManager.getInstance().setFeePerKb(feeManager.currentFees.luxury) - setFeeInformation( - R.string.FeeSelector_luxuryTime, - R.string.FeeSelector_luxuryMessage, - R.color.cheddar, - View.VISIBLE, - ) - } - else -> { - } - } - updateText() - } - - private fun setFeeInformation( - @StringRes deliveryTime: Int, - @StringRes warningStringId: Int, - @ColorRes warningColorId: Int, - visibility: Int, - ) { - feeDescription.text = - getString(R.string.FeeSelector_estimatedDeliver, getString(deliveryTime)) - if (warningStringId != 0) { - warningText.setText(warningStringId) - } - if (warningColorId != 0) { - warningText.setTextColor(resources.getColor(warningColorId, null)) - } - warningText.visibility = visibility - } +// private fun setupFeesSelector(rootView: View) { +// val feesSegment = rootView.findViewById(R.id.fees_segment) +// feesSegment.setOnCheckedChangeListener { _, checkedTypeId -> onFeeTypeSelected(checkedTypeId) } +// onFeeTypeSelected(R.id.regular_fee_but) +// } + +// private fun onFeeTypeSelected(checkedTypeId: Int) { +// val feeManager = FeeManager.getInstance() +// when (checkedTypeId) { +// R.id.regular_fee_but -> { +// feeManager.setFeeType(FeeManager.REGULAR) +// BRWalletManager.getInstance().setFeePerKb(feeManager.currentFeeOptions.regular) +// setFeeInformation(R.string.FeeSelector_regularTime, 0, 0, View.GONE) +// } +// R.id.economy_fee_but -> { +// feeManager.setFeeType(FeeManager.ECONOMY) +// BRWalletManager.getInstance().setFeePerKb(feeManager.currentFeeOptions.economy) +// setFeeInformation( +// R.string.FeeSelector_economyTime, +// R.string.FeeSelector_economyWarning, +// R.color.chili, +// View.VISIBLE, +// ) +// } +// R.id.luxury_fee_but -> { +// feeManager.setFeeType(FeeManager.LUXURY) +// BRWalletManager.getInstance().setFeePerKb(feeManager.currentFeeOptions.luxury) +// setFeeInformation( +// R.string.FeeSelector_luxuryTime, +// R.string.FeeSelector_luxuryMessage, +// R.color.cheddar, +// View.VISIBLE, +// ) +// } +// else -> { +// } +// } +// updateText() +// } + +// private fun setFeeInformation( +// @StringRes deliveryTime: Int, +// @StringRes warningStringId: Int, +// @ColorRes warningColorId: Int, +// visibility: Int, +// ) { +// feeDescription.text = +// getString(R.string.FeeSelector_estimatedDeliver, getString(deliveryTime)) +// if (warningStringId != 0) { +// warningText.setText(warningStringId) +// } +// if (warningColorId != 0) { +// warningText.setTextColor(resources.getColor(warningColorId, null)) +// } +// warningText.visibility = visibility +// } private fun setListeners() { amountEdit.setOnClickListener { @@ -187,8 +208,9 @@ class FragmentSend : Fragment() { amountEdit.textSize = 24f balanceText.visibility = View.VISIBLE feeText.visibility = View.VISIBLE - edit.visibility = View.VISIBLE - isoCurrencySymbolText.text = BRCurrency.getSymbolByIso(activity, selectedIsoCurrencySymbol) +// edit.visibility = View.VISIBLE + isoCurrencySymbolText.text = + BRCurrency.getSymbolByIso(activity, selectedIsoCurrencySymbol) isoCurrencySymbolText.textSize = 28f val scaleX = amountEdit.scaleX amountEdit.scaleX = 0f @@ -242,7 +264,13 @@ class FragmentSend : Fragment() { ConstraintSet.TOP, px4, ) - set.connect(isoCurrencySymbolText.id, ConstraintSet.BOTTOM, -1, ConstraintSet.TOP, -1) + set.connect( + isoCurrencySymbolText.id, + ConstraintSet.BOTTOM, + -1, + ConstraintSet.TOP, + -1 + ) set.applyTo(amountLayout) } } @@ -328,7 +356,11 @@ class FragmentSend : Fragment() { ) isoCurrencySymbolButton.setOnClickListener { selectedIsoCurrencySymbol = - if (selectedIsoCurrencySymbol.equals(BRSharedPrefs.getIsoSymbol(context), ignoreCase = true)) { + if (selectedIsoCurrencySymbol.equals( + BRSharedPrefs.getIsoSymbol(context), + ignoreCase = true + ) + ) { "LTC" } else { BRSharedPrefs.getIsoSymbol(context) @@ -372,7 +404,8 @@ class FragmentSend : Fragment() { if (allFilled) { BRSender.getInstance().sendTransaction( context, - TransactionItem(sendAddress, + TransactionItem( + sendAddress, Utils.fetchServiceItem(context, ServiceItems.WALLETOPS), null, litoshiAmount.toLong(), @@ -490,9 +523,11 @@ class FragmentSend : Fragment() { key.isEmpty() -> { handleDeleteClick() } + Character.isDigit(key[0]) -> { handleDigitClick(key.substring(0, 1).toInt()) } + key[0] == '.' -> { handleSeparatorClick() } @@ -537,7 +572,7 @@ class FragmentSend : Fragment() { private fun updateText() { if (activity == null) return var tempDoubleAmountValue = 0.0 - if (amountBuilder.toString() != "" && amountBuilder.toString() != "." ) { + if (amountBuilder.toString() != "" && amountBuilder.toString() != ".") { tempDoubleAmountValue = amountBuilder.toString().toDouble() } val scaleValue = 4 @@ -547,42 +582,68 @@ class FragmentSend : Fragment() { val selectedISOSymbol = selectedIsoCurrencySymbol val currencySymbol = BRCurrency.getSymbolByIso(activity, selectedIsoCurrencySymbol) if (!amountLabelOn) isoCurrencySymbolText.text = currencySymbol - isoCurrencySymbolButton.text = String.format("%s(%s)", - BRCurrency.getCurrencyName(activity, selectedIsoCurrencySymbol), - currencySymbol) + isoCurrencySymbolButton.text = String.format( + "%s(%s)", + BRCurrency.getCurrencyName(activity, selectedIsoCurrencySymbol), + currencySymbol + ) // Balance depending on ISOSymbol currentBalance = BRWalletManager.getInstance().getBalance(activity) - val balanceForISOSymbol = BRExchange.getAmountFromLitoshis(activity, selectedISOSymbol, BigDecimal(currentBalance)) - val formattedBalance = BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, balanceForISOSymbol) + val balanceForISOSymbol = BRExchange.getAmountFromLitoshis( + activity, + selectedISOSymbol, + BigDecimal(currentBalance) + ) + val formattedBalance = + BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, balanceForISOSymbol) // Current amount depending on ISOSymbol val currentAmountInLitoshis = if (selectedIsoCurrencySymbol.equals("LTC", ignoreCase = true)) { BRExchange.convertltcsToLitoshis(tempDoubleAmountValue).toLong() } else { - BRExchange.getLitoshisFromAmount(activity,selectedIsoCurrencySymbol,BigDecimal(tempDoubleAmountValue)).toLong() + BRExchange.getLitoshisFromAmount( + activity, + selectedIsoCurrencySymbol, + BigDecimal(tempDoubleAmountValue) + ).toLong() } - Timber.d("timber: updateText: currentAmountInLitoshis %d",currentAmountInLitoshis) + Timber.d("timber: updateText: currentAmountInLitoshis %d", currentAmountInLitoshis) // Network Fee depending on ISOSymbol - var networkFee = if(currentAmountInLitoshis > 0) { BRWalletManager.getInstance().feeForTransactionAmount(currentAmountInLitoshis) } - else { 0 } //Amount is zero so network fee is also zero + var networkFee = if (currentAmountInLitoshis > 0) { + BRWalletManager.getInstance().feeForTransactionAmount(currentAmountInLitoshis) + } else { + 0 + } //Amount is zero so network fee is also zero val networkFeeForISOSymbol = - BRExchange.getAmountFromLitoshis(activity,selectedISOSymbol, BigDecimal(networkFee)).setScale(scaleValue, RoundingMode.HALF_UP) - val formattedNetworkFee = BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, networkFeeForISOSymbol) + BRExchange.getAmountFromLitoshis(activity, selectedISOSymbol, BigDecimal(networkFee)) + .setScale(scaleValue, RoundingMode.HALF_UP) + val formattedNetworkFee = BRCurrency.getFormattedCurrencyString( + activity, + selectedISOSymbol, + networkFeeForISOSymbol + ) // Service Fee depending on ISOSymbol var serviceFee = Utils.tieredOpsFee(activity, currentAmountInLitoshis) val serviceFeeForISOSymbol = - BRExchange.getAmountFromLitoshis(activity,selectedISOSymbol,BigDecimal(serviceFee)).setScale(scaleValue, RoundingMode.HALF_UP) - val formattedServiceFee = BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, serviceFeeForISOSymbol) + BRExchange.getAmountFromLitoshis(activity, selectedISOSymbol, BigDecimal(serviceFee)) + .setScale(scaleValue, RoundingMode.HALF_UP) + val formattedServiceFee = BRCurrency.getFormattedCurrencyString( + activity, + selectedISOSymbol, + serviceFeeForISOSymbol + ) // Total Fees depending on ISOSymbol val totalFees = networkFee + serviceFee val totalFeeForISOSymbol = - BRExchange.getAmountFromLitoshis( activity,selectedISOSymbol,BigDecimal(totalFees)).setScale(scaleValue, RoundingMode.HALF_UP) - val formattedTotalFees = BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, totalFeeForISOSymbol) + BRExchange.getAmountFromLitoshis(activity, selectedISOSymbol, BigDecimal(totalFees)) + .setScale(scaleValue, RoundingMode.HALF_UP) + val formattedTotalFees = + BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, totalFeeForISOSymbol) // Update UI with alert red when over balance if (BigDecimal(currentAmountInLitoshis).toDouble() > currentBalance.toDouble()) { @@ -590,8 +651,7 @@ class FragmentSend : Fragment() { feeText.setTextColor(requireContext().getColor(R.color.chili)) amountEdit.setTextColor(requireContext().getColor(R.color.chili)) if (!amountLabelOn) isoCurrencySymbolText.setTextColor(requireContext().getColor(R.color.chili)) - } - else { + } else { balanceText.setTextColor(requireContext().getColor(R.color.cheddar)) feeText.setTextColor(requireContext().getColor(R.color.cheddar)) amountEdit.setTextColor(requireContext().getColor(R.color.cheddar)) @@ -599,12 +659,14 @@ class FragmentSend : Fragment() { } balanceText.text = getString(R.string.Send_balance, formattedBalance) - feeText.text = String.format("(%s + %s): %s + %s = %s", + feeText.text = String.format( + "(%s + %s): %s + %s = %s", getString(R.string.Network_feeLabel), getString(R.string.Fees_Service), formattedNetworkFee, formattedServiceFee, - formattedTotalFees) + formattedTotalFees + ) amountLayout.requestLayout() } @@ -627,13 +689,13 @@ class FragmentSend : Fragment() { } } - private fun showFeeSelectionButtons(b: Boolean) { - if (!b) { - signalLayout.removeView(feeLayout) - } else { - signalLayout.addView(feeLayout, signalLayout.indexOfChild(amountLayout) + 1) - } - } +// private fun showFeeSelectionButtons(b: Boolean) { +// if (!b) { +// signalLayout.removeView(feeLayout) +// } else { +// signalLayout.addView(feeLayout, signalLayout.indexOfChild(amountLayout) + 1) +// } +// } private fun setAmount() { val tmpAmount = amountBuilder.toString() @@ -648,7 +710,7 @@ class FragmentSend : Fragment() { newAmount.append(",") } } - + amountEdit.setText(newAmount.toString()) } @@ -680,7 +742,8 @@ class FragmentSend : Fragment() { private fun loadMetaData() { ignoreCleanup = false if (!Utils.isNullOrEmpty(savedMemo)) commentEdit.setText(savedMemo) - if (!Utils.isNullOrEmpty(savedIsoCurrencySymbol)) selectedIsoCurrencySymbol = savedIsoCurrencySymbol + if (!Utils.isNullOrEmpty(savedIsoCurrencySymbol)) selectedIsoCurrencySymbol = + savedIsoCurrencySymbol if (!Utils.isNullOrEmpty(savedAmount)) { amountBuilder = StringBuilder(savedAmount!!) Handler().postDelayed({ @@ -709,7 +772,6 @@ class FragmentSend : Fragment() { } - ///DEV WIP // val approximateNetworkFee = BRCurrency.getFormattedCurrencyString(activity, selectedISOSymbol, feeForISOSymbol) diff --git a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java index 963a56af..f9457baa 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java @@ -5,34 +5,23 @@ import androidx.annotation.StringDef; import com.brainwallet.data.repository.LtcRepository; -import com.brainwallet.presenter.entities.ServiceItems; import com.brainwallet.tools.threads.BRExecutor; -import com.brainwallet.tools.util.Utils; import com.brainwallet.data.model.Fee; -import com.platform.APIClient; import org.koin.java.KoinJavaComponent; -import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -import okhttp3.Request; -import okhttp3.Response; -import timber.log.Timber; //we are still using this, maybe in the future will deprecate? +@Deprecated public final class FeeManager { private static final FeeManager instance; private String feeType; - public Fee currentFees; + public Fee currentFeeOptions; public static FeeManager getInstance() { return instance; @@ -44,8 +33,8 @@ public static FeeManager getInstance() { } private void initWithDefaultValues() { - currentFees = Fee.getDefault(); - feeType = REGULAR; + currentFeeOptions = Fee.getDefault(); + feeType = LUXURY; } private FeeManager() { @@ -56,37 +45,22 @@ public void setFeeType(@FeeType String feeType) { } public void resetFeeType() { - this.feeType = REGULAR; + this.feeType = LUXURY; } - public boolean isRegularFee() { - return feeType.equals(REGULAR); + public boolean isLuxuryFee() { + return feeType.equals(LUXURY); } - public static final String LUXURY = "luxury"; - public static final String REGULAR = "regular"; - public static final String ECONOMY = "economy"; + public static final String LUXURY = "luxury";//top + public static final String REGULAR = "regular";//medium + public static final String ECONOMY = "economy";//low public void setFees(long luxuryFee, long regularFee, long economyFee) { - // TODO: to be implemented when feePerKB API will be ready - currentFees = new Fee(luxuryFee, regularFee, economyFee, System.currentTimeMillis()); + currentFeeOptions = new Fee(luxuryFee, regularFee, economyFee); } public static void updateFeePerKb(Context app) { - -// String jsonString = "{'fee_per_kb': 10000, 'fee_per_kb_economy': 2500, 'fee_per_kb_luxury': 66746}"; -// try { -// JSONObject obj = new JSONObject(jsonString); -// // TODO: Refactor when mobile-api v0.4.0 is in prod -// long regularFee = obj.optLong("fee_per_kb"); -// long economyFee = obj.optLong("fee_per_kb_economy"); -// long luxuryFee = obj.optLong("fee_per_kb_luxury"); -// FeeManager.getInstance().setFees(luxuryFee, regularFee, economyFee); -// BRSharedPrefs.putFeeTime(app, System.currentTimeMillis()); //store the time of the last successful fee fetch -// } catch (JSONException e) { -// Timber.e(new IllegalArgumentException("updateFeePerKb: FAILED: " + jsonString, e)); -// } - LtcRepository ltcRepository = KoinJavaComponent.get(LtcRepository.class); BRExecutor.getInstance().executeSuspend( (coroutineScope, continuation) -> ltcRepository.fetchFeePerKb(continuation) @@ -98,43 +72,6 @@ public static void updateFeePerKb(Context app) { }); } - // createGETRequestURL - // Creates the params and headers to make a GET Request - @Deprecated - private static String createGETRequestURL(Context app, String myURL) { - Request request = new Request.Builder() - .url(myURL) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("User-agent", Utils.getAgentString(app, "android/HttpURLConnection")) - .header("BW-client-code", Utils.fetchServiceItem(app, ServiceItems.CLIENTCODE)) - .get().build(); - String response = null; - Response resp = APIClient.getInstance(app).sendRequest(request, false, 0); - - try { - if (resp == null) { - Timber.i("timber: urlGET: %s resp is null", myURL); - return null; - } - response = resp.body().string(); - String strDate = resp.header("date"); - if (strDate == null) { - Timber.i("timber: urlGET: strDate is null!"); - return response; - } - SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); - Date date = formatter.parse(strDate); - long timeStamp = date.getTime(); - BRSharedPrefs.putSecureTime(app, timeStamp); - } catch (ParseException | IOException e) { - Timber.e(e); - } finally { - if (resp != null) resp.close(); - } - return response; - } - @Retention(RetentionPolicy.SOURCE) @StringDef({LUXURY, REGULAR, ECONOMY}) public @interface FeeType { diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt index 9f924c3c..60a209bd 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt @@ -1,6 +1,10 @@ package com.brainwallet.ui.screens.home + import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Fee +import com.brainwallet.data.model.FeeOption import com.brainwallet.data.model.Language +import com.brainwallet.data.model.toFeeOptions data class SettingsState( val darkMode: Boolean = true, @@ -15,4 +19,5 @@ data class SettingsState( val fiatSelectorBottomSheetVisible: Boolean = false, val shareAnalyticsDataEnabled: Boolean = false, val lastSyncMetadata: String? = null, + val currentFeeOptions: List = Fee.Default.toFeeOptions(), ) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt index e9515ce8..8859d395 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt @@ -5,6 +5,8 @@ import androidx.core.os.LocaleListCompat import androidx.lifecycle.viewModelScope import com.brainwallet.data.model.AppSetting import com.brainwallet.data.model.Language +import com.brainwallet.data.model.toFeeOptions +import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository import com.brainwallet.ui.BrainwalletViewModel import com.brainwallet.util.EventBus @@ -21,7 +23,8 @@ import kotlinx.coroutines.launch class SettingsViewModel( - private val settingRepository: SettingRepository + private val settingRepository: SettingRepository, + private val ltcRepository: LtcRepository ) : BrainwalletViewModel() { private val _state = MutableStateFlow(SettingsState()) @@ -50,7 +53,8 @@ class SettingsViewModel( _state.update { it.copy( shareAnalyticsDataEnabled = event.shareAnalyticsDataEnabled, - lastSyncMetadata = event.lastSyncMetadata + lastSyncMetadata = event.lastSyncMetadata, + currentFeeOptions = ltcRepository.fetchFeePerKb().toFeeOptions() ) } } diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt index 42b370a8..5c0c6a9c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -60,7 +60,7 @@ fun HomeSettingDrawerSheet( LaunchedEffect(Unit) { viewModel.onEvent(SettingsEvent.OnLoad( shareAnalyticsDataEnabled = BRSharedPrefs.getShareData(context), //currently just load analytics share data here - lastSyncMetadata = BRSharedPrefs.getSyncMetadata(context) //currently just load sync metadata here + lastSyncMetadata = BRSharedPrefs.getSyncMetadata(context), //currently just load sync metadata here )) } @@ -134,6 +134,8 @@ fun HomeSettingDrawerSheet( modifier = Modifier .fillMaxSize() .wrapContentHeight(), + selectedCurrency = state.selectedCurrency, + feeOptions = state.currentFeeOptions, onEvent = { viewModel.onEvent(it) } diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt index 339584cd..138ab31c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt @@ -1,26 +1,50 @@ package com.brainwallet.ui.screens.home.composable.settingsrows +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SegmentedButtonDefaults +import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.brainwallet.R +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Fee +import com.brainwallet.data.model.FeeOption +import com.brainwallet.data.model.getFiatFormatted +import com.brainwallet.data.model.toFeeOptions +import com.brainwallet.tools.manager.FeeManager import com.brainwallet.ui.screens.home.SettingsEvent +import com.brainwallet.ui.theme.BrainwalletTheme +import com.brainwallet.wallet.BRWalletManager //TODO @Composable fun LitecoinBlockchainDetail( modifier: Modifier = Modifier, + selectedCurrency: CurrencyEntity, + feeOptions: List, onEvent: (SettingsEvent) -> Unit, ) { + var feeOptionsState by remember { mutableIntStateOf(2) } //2 -> index of top, since we have [low,medium,top] + /// Layout values val contentHeight = 60 val horizontalPadding = 14 @@ -35,19 +59,89 @@ fun LitecoinBlockchainDetail( ) { Row( - modifier = Modifier - .height(contentHeight.dp), + modifier = Modifier.height(contentHeight.dp), verticalAlignment = Alignment.CenterVertically ) { - Text(stringResource(R.string.settings_blockchain_litecoin_description)) - Spacer(modifier = Modifier.weight(1f)) - Button(onClick = { - onEvent.invoke(SettingsEvent.OnBlockchainSyncClick) - }) { + Text( + text = stringResource(R.string.settings_blockchain_litecoin_description), + modifier = Modifier.weight(1.3f) + ) + Button( + modifier = Modifier.weight(.7f), + onClick = { + onEvent.invoke(SettingsEvent.OnBlockchainSyncClick) + } + ) { Text(stringResource(R.string.settings_blockchain_litecoin_button)) } } + HorizontalDivider(color = BrainwalletTheme.colors.content) + + NetworkFeeSelector( + selectedCurrency = selectedCurrency, + feeOptions = feeOptions, + selectedIndex = feeOptionsState + ) { newSelectedIndex -> + feeOptionsState = newSelectedIndex + + //just update inside BRWalletManager.setFeePerKb + BRWalletManager.getInstance().setFeePerKb(feeOptions[newSelectedIndex].feePerKb) + } + + } + } +} + +@Composable +private fun NetworkFeeSelector( + selectedCurrency: CurrencyEntity, + feeOptions: List, + selectedIndex: Int, + onSelectedChange: (Int) -> Unit +) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = stringResource(R.string.network_fee_options_desc), + fontSize = 12.sp, + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + feeOptions.forEachIndexed { index, feeOption -> + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = "${feeOption.feePerKb}", + fontWeight = FontWeight.Bold + ) + Text( + text = feeOptions[index].getFiatFormatted(selectedCurrency), //fiat? + fontSize = 12.sp + ) + } + } + } + + SingleChoiceSegmentedButtonRow { + feeOptions.forEachIndexed { index, feeOption -> + SegmentedButton( + shape = SegmentedButtonDefaults.itemShape( + index = index, + count = feeOptions.size, + baseShape = MaterialTheme.shapes.extraLarge + ), + onClick = { onSelectedChange.invoke(index) }, + selected = index == selectedIndex, + label = { Text(stringResource(feeOption.labelStringId)) } + ) + } } + + } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java index 7a37d9cd..507a5125 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java @@ -514,9 +514,9 @@ public void initWallet(final Context ctx) { String firstAddress = BRWalletManager.getFirstAddress(pubkeyEncoded); BRSharedPrefs.putFirstAddress(ctx, firstAddress); FeeManager feeManager = FeeManager.getInstance(); - if (feeManager.isRegularFee()) { - feeManager.updateFeePerKb(ctx); - BRWalletManager.getInstance().setFeePerKb(feeManager.currentFees.regular); + if (feeManager.isLuxuryFee()) { + FeeManager.updateFeePerKb(ctx); + BRWalletManager.getInstance().setFeePerKb(feeManager.currentFeeOptions.luxury); } } diff --git a/app/src/main/res/layout/fragment_send.xml b/app/src/main/res/layout/fragment_send.xml index c60707bd..742ea48f 100644 --- a/app/src/main/res/layout/fragment_send.xml +++ b/app/src/main/res/layout/fragment_send.xml @@ -216,105 +216,15 @@ android:textSize="18sp" app:buttonType="2" app:isBreadButton="true" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.0" /> - - - - - - - - - - - - - - - - - - - - + - مشاركة بيانات التحليلات تحديث الرقم السري عرض + رسوم الشبكة (لكل كيلو بايت): القيمة الأعلى تعني اكتمال المعاملة في وقت أقرب + قمة + واسطة + قليل diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 4d0e68ac..6d272928 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -796,4 +796,8 @@ Analyse-Daten teilen PIN aktualisieren Anzeigen + Netzwerkgebühr (pro KB): Ein höherer Wert bedeutet, dass die Transaktion früher abgeschlossen wird + Spitze + Medium + Niedrig diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9f12f07d..24bf3fc0 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -169,9 +169,9 @@ Ignorar - SEGURIDAD DEL DISPOSITIVO COMPROMETIDA\nCualquier aplicación \"jailbreak\" puede acceder a los datos del llavero de Loaf y robar tus Litecoins. Borra esta cartera de inmediato y restáurala en un dispositivo seguro. + SEGURIDAD DEL DISPOSITIVO COMPROMETIDA\nCualquier aplicación "jailbreak" puede acceder a los datos del llavero de Loaf y robar tus Litecoins. Borra esta cartera de inmediato y restáurala en un dispositivo seguro. - SEGURIDAD DEL DISPOSITIVO COMPROMETIDA\nCualquier aplicación \"jailbreak\" puede acceder a los datos del llavero de Loaf y robar tus Litecoins. Usa Loaf únicamente en un dispositivo sin jailbreak. + SEGURIDAD DEL DISPOSITIVO COMPROMETIDA\nCualquier aplicación "jailbreak" puede acceder a los datos del llavero de Loaf y robar tus Litecoins. Usa Loaf únicamente en un dispositivo sin jailbreak. AVISO @@ -795,4 +795,8 @@ Compartir datos analíticos Actualizar PIN Mostrar + Tarifa de red (por kb): un valor más alto significa que la transacción se completa antes + Arriba + Medio + Bajo diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 93928b67..1571dd93 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -796,4 +796,8 @@ Partager les données analytiques Mettre à jour le code PIN Afficher + Frais de réseau (par Ko): une valeur plus élevée signifie que la transaction se termine plus tôt + Haut + Moyen + Faible diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 8a0158a5..a03d849c 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -434,4 +434,8 @@ विश्लेषण डेटा साझा करें पिन अपडेट करें दिखाएं + नेटवर्क शुल्क (प्रति केबी): उच्च मूल्य का मतलब है कि लेनदेन जल्दी पूरा हो जाएगा + शीर्ष + मध्यम + कम diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 7899cb2d..d3bb43e0 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -798,4 +798,8 @@ Bagikan data analitik Perbarui PIN Tampilkan + Biaya Jaringan (per kb): Nilai yang lebih tinggi berarti transaksi selesai lebih cepat + Atas + Sedang + Rendah diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 6641145b..592ebba1 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -796,4 +796,8 @@ Condividere i dati analitici Aggiorna PIN Mostra + Tariffa di rete (per kb): un valore più elevato significa che la transazione viene completata prima + Superiore + Medio + Basso diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 523cd7f2..c6ffb20c 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -796,4 +796,8 @@ 分析データを共有 PIN を更新 表示 + ネットワーク料金 (kb あたり): 値が高いほど、トランザクションが早く完了することを意味します + トップ + 中くらい + 低い diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 3deda254..8ec4b384 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -796,4 +796,8 @@ 분석 데이터 공유 PIN 업데이트 표시 + 네트워크 수수료(kb당): 값이 높을수록 거래가 더 빨리 완료됨을 의미합니다. + 맨 위 + 중간 + 낮은 diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 48a2dc0b..27b64935 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -795,4 +795,8 @@ Compartilhar dados analíticos Atualizar PIN Mostrar + Taxa de rede (por kb): valor mais alto significa que a transação é concluída mais cedo + Principal + Médio + Baixo diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 22df2082..4df74670 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -796,4 +796,8 @@ Делиться аналитическими данными Обновить PIN Показать + Сетевая плата (за КБ): более высокое значение означает, что транзакция завершится раньше. + Вершина + Середина + Низкий diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 12d62935..78b503fd 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -434,4 +434,8 @@ Dela analysdata Uppdatera PIN Visa + Nätverksavgift (per kb): Högre värde innebär att transaktionen slutförs tidigare + Bästa + Medium + Låg diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d1e3c107..a526c60c 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -819,4 +819,8 @@ Analitik verileri paylaş PIN güncelle Göster + Ağ Ücreti (kb başına): Daha yüksek değer, işlemin daha erken tamamlanacağı anlamına gelir + Tepe + Orta + Düşük diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 3f7aca4a..b5d20546 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -802,4 +802,8 @@ Ділитися аналітичними даними Оновити PIN Показати + Плата за мережу (за кб): вищий показник означає, що транзакція завершується швидше + Топ + Середній + Низький diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b25903f6..b1517637 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -764,7 +764,7 @@ 你可以从开始的地方返回 恢复我的脑钱包 清除 - 不要猜测。\n\n这将需要你 \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000 次尝试 + 不要猜测。\n\n这将需要你 \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000,000 次尝试 确认 你没有忘记吧?再次输入。或者,返回重新开始。 准备好 @@ -796,4 +796,8 @@ 分享分析数据 更新 PIN 显示 + 网络费用(每 kb):值越高意味着交易完成得越快 + 顶部 + 中等的 + 低的 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 13e6b9cc..69514c55 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -796,4 +796,8 @@ 分享分析數據 更新 PIN 顯示 + 網路費用(每 kb):數值越高代表交易完成越快 + 頂部 + 中等的 + 低的 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1b2f4e52..3e6f5bbe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -805,7 +805,7 @@ You can get back from where you started Restore my Brainwallet Clear - Don’t guess.\n\nIt would take you \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000 tries + Don’t guess.\n\nIt would take you \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000,000 tries Confirm You didn’t forget did you? Enter it again. Or, go back to start over. Ready @@ -839,5 +839,8 @@ Share analytics data Update PIN Show - + Network Fee (per kb): Higher value mean the transaction completes sooner + Top + Medium + Low From e7fb2b7873f4ddb5a9c511a0c0b91efe9041b77a Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Wed, 7 May 2025 12:45:38 +0700 Subject: [PATCH 26/65] fix: fix dismiss allow state loss (#76) --- .../com/brainwallet/presenter/fragments/FragmentSignal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java index 4c136b41..5757a798 100644 --- a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java +++ b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSignal.java @@ -31,7 +31,7 @@ public class FragmentSignal extends DialogFragment { private final Runnable popBackStackRunnable = new Runnable() { @Override public void run() { - dismiss(); + dismissAllowingStateLoss(); handler.postDelayed(completionRunnable, 300); } }; From 3d8ef981879bbcab1d1fa8cab54c2b08edfd29e0 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Wed, 7 May 2025 12:46:41 +0700 Subject: [PATCH 27/65] fix: fix typo at strings.xml (#75) --- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b1517637..53cd941f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -764,7 +764,7 @@ 你可以从开始的地方返回 恢复我的脑钱包 清除 - 不要猜测。\n\n这将需要你 \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000,000 次尝试 + 不要猜测。\n\n这将需要你 \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000 次尝试 确认 你没有忘记吧?再次输入。或者,返回重新开始。 准备好 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e6f5bbe..d107536c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -805,7 +805,7 @@ You can get back from where you started Restore my Brainwallet Clear - Don’t guess.\n\nIt would take you \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000,000 tries + Don’t guess.\n\nIt would take you \n5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000 tries Confirm You didn’t forget did you? Enter it again. Or, go back to start over. Ready From 25be1a85f036e502811c3e093398feee996dfe77 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Mon, 12 May 2025 18:59:29 +0700 Subject: [PATCH 28/65] feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent --- .../data/model/MoonpayCurrencyLimit.kt | 24 + .../data/model/QuickFiatAmountOption.kt | 11 + .../data/repository/LtcRepository.kt | 65 +- .../data/source/LocalCacheSource.kt | 45 ++ .../data/source/RemoteApiSource.kt | 22 +- .../response/GetMoonpayBuyQuoteResponse.kt | 17 + .../response/GetMoonpaySignUrlResponse.kt | 8 + .../main/java/com/brainwallet/di/Module.kt | 36 +- .../navigation/LegacyNavigation.kt | 61 ++ .../com/brainwallet/navigation/MainNav.kt | 5 + .../java/com/brainwallet/navigation/Route.kt | 3 + .../presenter/activities/BreadActivity.java | 23 +- .../com/brainwallet/tools/qrcode/QRUtils.java | 15 + .../tools/sqlite/CurrencyDataSource.java | 51 +- .../brainwallet/ui/BrainwalletViewModel.kt | 19 + .../brainwallet/ui/composable/Foundation.kt | 18 +- .../brainwallet/ui/composable/LargeButton.kt | 5 +- .../ui/composable/LoadingDialog.kt | 55 ++ .../ui/composable/MoonpayBuyButton.kt | 66 ++ .../ui/composable/MoonpayBuyWidget.kt | 56 ++ .../brainwallet/ui/composable/WheelPicker.kt | 634 ++++++++++++++++++ .../screens/buylitecoin/BuyLitecoinEvent.kt | 11 + .../screens/buylitecoin/BuyLitecoinScreen.kt | 167 +++++ .../screens/buylitecoin/BuyLitecoinState.kt | 19 + .../buylitecoin/BuyLitecoinViewModel.kt | 128 ++++ .../ui/screens/home/buy/BuyScreen.kt | 10 - .../ui/screens/home/receive/ReceiveDialog.kt | 452 +++++++++++++ .../home/receive/ReceiveDialogEvent.kt | 21 + .../home/receive/ReceiveDialogState.kt | 61 ++ .../home/receive/ReceiveDialogViewModel.kt | 179 +++++ .../ui/screens/topup/TopUpScreen.kt | 182 ++--- .../YourSeedProveItViewModel.kt | 4 +- .../java/com/brainwallet/ui/theme/Theme.kt | 4 + app/src/main/res/drawable/ic_copy.xml | 9 + app/src/main/res/drawable/ic_import.xml | 19 + app/src/main/res/menu/bottom_nav_menu.xml | 10 +- app/src/main/res/menu/bottom_nav_menu_us.xml | 23 +- app/src/main/res/values-ar/strings.xml | 11 + app/src/main/res/values-de/strings.xml | 11 + app/src/main/res/values-es/strings.xml | 11 + app/src/main/res/values-fr/strings.xml | 11 + app/src/main/res/values-hi/strings.xml | 11 + app/src/main/res/values-in/strings.xml | 11 + app/src/main/res/values-it/strings.xml | 11 + app/src/main/res/values-ja/strings.xml | 11 + app/src/main/res/values-ko/strings.xml | 11 + app/src/main/res/values-pt/strings.xml | 11 + app/src/main/res/values-ru/strings.xml | 11 + app/src/main/res/values-sv/strings.xml | 11 + app/src/main/res/values-tr/strings.xml | 12 + app/src/main/res/values-uk/strings.xml | 12 + app/src/main/res/values-zh-rCN/strings.xml | 11 + app/src/main/res/values-zh-rTW/strings.xml | 11 + app/src/main/res/values/strings.xml | 14 +- 54 files changed, 2479 insertions(+), 251 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/model/MoonpayCurrencyLimit.kt create mode 100644 app/src/main/java/com/brainwallet/data/model/QuickFiatAmountOption.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/response/GetMoonpayBuyQuoteResponse.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/response/GetMoonpaySignUrlResponse.kt create mode 100644 app/src/main/java/com/brainwallet/ui/composable/LoadingDialog.kt create mode 100644 app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyButton.kt create mode 100644 app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyWidget.kt create mode 100644 app/src/main/java/com/brainwallet/ui/composable/WheelPicker.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinEvent.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinState.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt delete mode 100644 app/src/main/java/com/brainwallet/ui/screens/home/buy/BuyScreen.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogEvent.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogState.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt create mode 100644 app/src/main/res/drawable/ic_copy.xml create mode 100644 app/src/main/res/drawable/ic_import.xml diff --git a/app/src/main/java/com/brainwallet/data/model/MoonpayCurrencyLimit.kt b/app/src/main/java/com/brainwallet/data/model/MoonpayCurrencyLimit.kt new file mode 100644 index 00000000..d8344438 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/model/MoonpayCurrencyLimit.kt @@ -0,0 +1,24 @@ +package com.brainwallet.data.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class MoonpayCurrencyLimit( + @SerialName("data") val data: Data = Data() +) { + @Serializable + data class Data( + @SerialName("paymentMethod") val paymentMethod: String = "", + @SerialName("quoteCurrency") val quoteCurrency: CurrencyLimit = CurrencyLimit(), + @SerialName("baseCurrency") val baseCurrency: CurrencyLimit = CurrencyLimit(), + @SerialName("areFeesIncluded") val areFeesIncluded: Boolean = false + ) + + @Serializable + data class CurrencyLimit( + val code: String = "usd", + @SerialName("minBuyAmount") val min: Float = 21f, + @SerialName("maxBuyAmount") val max: Float = 29849f + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/model/QuickFiatAmountOption.kt b/app/src/main/java/com/brainwallet/data/model/QuickFiatAmountOption.kt new file mode 100644 index 00000000..20dc3368 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/model/QuickFiatAmountOption.kt @@ -0,0 +1,11 @@ +package com.brainwallet.data.model + + +data class QuickFiatAmountOption( + val symbol: String = "custom", + val value: Float = -1f +) + +fun QuickFiatAmountOption.isCustom(): Boolean = symbol == "custom" && value == -1f + +fun QuickFiatAmountOption.getFormattedText(): String = "${symbol}${value.toInt()}" \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index 38b325fd..365bbc0d 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -2,21 +2,29 @@ package com.brainwallet.data.repository import android.content.Context import android.content.SharedPreferences -import androidx.core.content.edit +import androidx.core.net.toUri +import com.brainwallet.BuildConfig import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Fee +import com.brainwallet.data.model.MoonpayCurrencyLimit import com.brainwallet.data.source.RemoteApiSource -import com.brainwallet.di.json +import com.brainwallet.data.source.fetchWithCache +import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse import com.brainwallet.tools.manager.BRSharedPrefs import com.brainwallet.tools.manager.FeeManager import com.brainwallet.tools.sqlite.CurrencyDataSource -import kotlinx.serialization.encodeToString interface LtcRepository { suspend fun fetchRates(): List suspend fun fetchFeePerKb(): Fee + suspend fun fetchLimits(baseCurrencyCode: String): MoonpayCurrencyLimit + + suspend fun fetchBuyQuote(params: Map): GetMoonpayBuyQuoteResponse + + suspend fun fetchMoonpaySignedUrl(params: Map): String + class Impl( private val context: Context, private val remoteApiSource: RemoteApiSource, @@ -47,27 +55,42 @@ interface LtcRepository { } override suspend fun fetchFeePerKb(): Fee { - val lastUpdateTime = sharedPreferences.getLong(PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT, 0) - val currentTime = System.currentTimeMillis() - val cachedFee = sharedPreferences.getString(PREF_KEY_NETWORK_FEE_PER_KB, null) - ?.let { json.decodeFromString(it) } + return sharedPreferences.fetchWithCache( + key = PREF_KEY_NETWORK_FEE_PER_KB, + cachedAtKey = PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT, + cacheTimeMs = 6 * 60 * 60 * 1000, + fetchData = { + remoteApiSource.getFeePerKb() + }, + defaultValue = Fee.Default + ) + } - return runCatching { - // Check if cache exists and is less than 6 hours old - if (cachedFee != null && (currentTime - lastUpdateTime) < 6 * 60 * 60 * 1000) { - return cachedFee + override suspend fun fetchLimits(baseCurrencyCode: String): MoonpayCurrencyLimit { + return sharedPreferences.fetchWithCache( + key = "${PREF_KEY_BUY_LIMITS_PREFIX}${baseCurrencyCode.lowercase()}", + cachedAtKey = "${PREF_KEY_BUY_LIMITS_PREFIX_CACHED_AT}${baseCurrencyCode.lowercase()}", + cacheTimeMs = 5 * 60 * 1000, //5 minutes + fetchData = { + remoteApiSource.getMoonpayCurrencyLimit(baseCurrencyCode) } + ) + } - val fee = remoteApiSource.getFeePerKb() - sharedPreferences.edit { - putString(PREF_KEY_NETWORK_FEE_PER_KB, json.encodeToString(fee)) - putLong(PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT, currentTime) - } + override suspend fun fetchBuyQuote(params: Map): GetMoonpayBuyQuoteResponse = + remoteApiSource.getBuyQuote(params) - return fee - }.getOrElse { - cachedFee ?: Fee.Default - } + override suspend fun fetchMoonpaySignedUrl(params: Map): String { + return remoteApiSource.getMoonpaySignedUrl(params) + .signedUrl.toUri() + .buildUpon() + .apply { + if (BuildConfig.DEBUG) { + authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com + } + } + .build() + .toString() } } @@ -75,5 +98,7 @@ interface LtcRepository { companion object { const val PREF_KEY_NETWORK_FEE_PER_KB = "network_fee_per_kb" const val PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT = "${PREF_KEY_NETWORK_FEE_PER_KB}_cached_at" + const val PREF_KEY_BUY_LIMITS_PREFIX = "buy_limits:" //e.g. buy_limits:usd + const val PREF_KEY_BUY_LIMITS_PREFIX_CACHED_AT = "buy_limits_cached_at:" } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt b/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt new file mode 100644 index 00000000..d86d312d --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt @@ -0,0 +1,45 @@ +package com.brainwallet.data.source + +import android.content.SharedPreferences +import androidx.core.content.edit +import com.brainwallet.di.json +import kotlinx.serialization.encodeToString + +/** + * Generic function to handle caching data in shared preferences + * @param key The key to store the data under + * @param cachedAtKey The key to store the timestamp under + * @param cacheTimeMs How long the cache should be valid in milliseconds + * @param fetchData Suspending function to fetch new data + * @return The data, either from cache or freshly fetched + */ +suspend inline fun SharedPreferences.fetchWithCache( + key: String, + cachedAtKey: String, + cacheTimeMs: Long, + crossinline fetchData: suspend () -> T, + defaultValue: T? = null +): T { + val lastUpdateTime = getLong(cachedAtKey, 0) + val currentTime = System.currentTimeMillis() + val cached = getString(key, null) + ?.let { runCatching { json.decodeFromString(it) }.getOrNull() } + + // Return cached value if it exists and is not expired + if (cached != null && (currentTime - lastUpdateTime) < cacheTimeMs) { + return cached + } + + return runCatching { + // Fetch fresh data + val result = fetchData() + // Save to cache + edit { + putString(key, json.encodeToString(result)) + putLong(cachedAtKey, currentTime) + } + result + }.getOrElse { + cached ?: (defaultValue ?: throw it) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt b/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt index 60c865e2..4e0a1c02 100644 --- a/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt +++ b/app/src/main/java/com/brainwallet/data/source/RemoteApiSource.kt @@ -2,7 +2,12 @@ package com.brainwallet.data.source import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Fee +import com.brainwallet.data.model.MoonpayCurrencyLimit +import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse +import com.brainwallet.data.source.response.GetMoonpaySignUrlResponse import retrofit2.http.GET +import retrofit2.http.Query +import retrofit2.http.QueryMap //TODO interface RemoteApiSource { @@ -13,6 +18,19 @@ interface RemoteApiSource { @GET("v1/fee-per-kb") suspend fun getFeePerKb(): Fee -// https://prod.apigsltd.net/moonpay/buy?address=ltc1qjnsg3p9rt4r4vy7ncgvrywdykl0zwhkhcp8ue0&code=USD&idate=1742331930290&uid=ec51fa950b271ff3 -// suspend fun getMoonPayBuy() + @GET("v1/moonpay/ltc-to-fiat-limits") + suspend fun getMoonpayCurrencyLimit( + @Query("baseCurrencyCode") baseCurrencyCode: String + ): MoonpayCurrencyLimit + + @GET("v1/moonpay/sign-url") + suspend fun getMoonpaySignedUrl( + @QueryMap params: Map + ): GetMoonpaySignUrlResponse + + @GET("v1/moonpay/buy-quote") + suspend fun getBuyQuote( + @QueryMap params: Map + ): GetMoonpayBuyQuoteResponse + } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/source/response/GetMoonpayBuyQuoteResponse.kt b/app/src/main/java/com/brainwallet/data/source/response/GetMoonpayBuyQuoteResponse.kt new file mode 100644 index 00000000..848732a9 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/response/GetMoonpayBuyQuoteResponse.kt @@ -0,0 +1,17 @@ +package com.brainwallet.data.source.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GetMoonpayBuyQuoteResponse( + @SerialName("data") val data: Data = Data() + +) { + @Serializable + data class Data( + val totalAmount: Float = 0f, + val baseCurrencyCode: String = "usd", + val quoteCurrencyAmount: Float = 0f, + ) +} diff --git a/app/src/main/java/com/brainwallet/data/source/response/GetMoonpaySignUrlResponse.kt b/app/src/main/java/com/brainwallet/data/source/response/GetMoonpaySignUrlResponse.kt new file mode 100644 index 00000000..51e316cc --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/response/GetMoonpaySignUrlResponse.kt @@ -0,0 +1,8 @@ +package com.brainwallet.data.source.response + +import kotlinx.serialization.Serializable + +@Serializable +data class GetMoonpaySignUrlResponse( + val signedUrl: String +) diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 8dcfb909..b95bbeec 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -10,7 +10,9 @@ import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.tools.util.BRConstants +import com.brainwallet.ui.screens.buylitecoin.BuyLitecoinViewModel import com.brainwallet.ui.screens.home.SettingsViewModel +import com.brainwallet.ui.screens.home.receive.ReceiveDialogViewModel import com.brainwallet.ui.screens.inputwords.InputWordsViewModel import com.brainwallet.ui.screens.ready.ReadyViewModel import com.brainwallet.ui.screens.setpasscode.SetPasscodeViewModel @@ -28,6 +30,8 @@ import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import org.koin.android.ext.koin.androidApplication +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject import org.koin.core.module.dsl.viewModel import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module @@ -70,6 +74,8 @@ val viewModelModule = module { viewModel { UnLockViewModel() } viewModel { YourSeedProveItViewModel() } viewModel { YourSeedWordsViewModel() } + viewModel { ReceiveDialogViewModel(get(), get()) } + viewModel { BuyLitecoinViewModel(get(), get()) } } val appModule = module { @@ -94,28 +100,6 @@ private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() .addHeader("Accept-Language", "en") chain.proceed(requestBuilder.build()) } - .addInterceptor { chain -> - val request = chain.request() - runCatching { - chain.proceed(request).use { response -> - if (response.isSuccessful.not()) { - throw HttpException( - retrofit2.Response.error( - response.code, - response.body ?: response.peekBody(Long.MAX_VALUE) - ) - ) - } - response - } - }.getOrElse { - //retry using dev host - val newRequest = request.newBuilder() - .url("${BRConstants.LEGACY_BW_API_DEV_HOST}/api${request.url.encodedPath}") //legacy dev api need prefix path /api - .build() - chain.proceed(newRequest) - } - } .addInterceptor(HttpLoggingInterceptor().apply { setLevel( when { @@ -140,4 +124,10 @@ internal fun provideRetrofit( .build() internal inline fun provideApi(retrofit: Retrofit): T = - retrofit.create(T::class.java) \ No newline at end of file + retrofit.create(T::class.java) + +inline fun getKoinInstance(): T { + return object : KoinComponent { + val value: T by inject() + }.value +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index b50bef17..d38eaeb9 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -1,11 +1,22 @@ package com.brainwallet.navigation import android.app.Activity +import android.app.ProgressDialog import android.content.Context import android.content.Intent +import android.widget.Toast +import androidx.browser.customtabs.CustomTabsIntent +import androidx.core.net.toUri +import com.brainwallet.BuildConfig import com.brainwallet.R +import com.brainwallet.data.source.RemoteApiSource +import com.brainwallet.di.getKoinInstance import com.brainwallet.presenter.activities.BreadActivity import com.brainwallet.ui.BrainwalletActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import timber.log.Timber @@ -55,4 +66,54 @@ object LegacyNavigation { context.startActivity(it) } + @JvmStatic + fun showMoonPayWidget( + context: Context, + params: Map = mapOf(), + isDarkMode: Boolean = true, + ) { + val remoteApiSource: RemoteApiSource = getKoinInstance() + + val progressDialog = ProgressDialog(context).apply { + setMessage(context.getString(R.string.loading)) + setCancelable(false) + show() + } + + CoroutineScope(Dispatchers.Main).launch { + try { + val result = withContext(Dispatchers.IO) { + remoteApiSource.getMoonpaySignedUrl( + params = params.toMutableMap().apply { + put("defaultCurrencyCode", "ltc") + put("currencyCode", "ltc") + put("themeId", "main-v1.0.0") + put("theme", if (isDarkMode) "dark" else "light") + } + ) + } + + val widgetUri = result.signedUrl.toUri().buildUpon() + .apply { + if (BuildConfig.DEBUG) { + authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com + } + } + .build() + val intent = CustomTabsIntent.Builder() + .setColorScheme(if (isDarkMode) CustomTabsIntent.COLOR_SCHEME_DARK else CustomTabsIntent.COLOR_SCHEME_LIGHT) + .build() + intent.launchUrl(context, widgetUri) + } catch (e: Exception) { + Toast.makeText( + context, + "Failed to load: ${e.message}, please try again later", + Toast.LENGTH_LONG + ).show() + } finally { + progressDialog.dismiss() + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/navigation/MainNav.kt b/app/src/main/java/com/brainwallet/navigation/MainNav.kt index f6e2e091..ec2a8a06 100644 --- a/app/src/main/java/com/brainwallet/navigation/MainNav.kt +++ b/app/src/main/java/com/brainwallet/navigation/MainNav.kt @@ -7,6 +7,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute +import com.brainwallet.ui.screens.buylitecoin.BuyLitecoinScreen import com.brainwallet.ui.screens.inputwords.InputWordsScreen import com.brainwallet.ui.screens.ready.ReadyScreen import com.brainwallet.ui.screens.setpasscode.SetPasscodeScreen @@ -113,6 +114,10 @@ fun NavGraphBuilder.mainNavGraph( UnLockScreen(onNavigate = onNavigate, isUpdatePin = route.isUpdatePin) } + composable { navBackStackEntry -> + BuyLitecoinScreen(onNavigate = onNavigate) + } + //todo add more composable screens } diff --git a/app/src/main/java/com/brainwallet/navigation/Route.kt b/app/src/main/java/com/brainwallet/navigation/Route.kt index 2e0e71a8..16f16dcf 100644 --- a/app/src/main/java/com/brainwallet/navigation/Route.kt +++ b/app/src/main/java/com/brainwallet/navigation/Route.kt @@ -45,4 +45,7 @@ sealed class Route : JavaSerializable { @Serializable data class UnLock(val isUpdatePin: Boolean = false) : Route() + @Serializable + object BuyLitecoin : Route() + } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java index aec322e1..b210395c 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java @@ -25,6 +25,7 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.browser.customtabs.CustomTabsIntent; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.core.app.ActivityCompat; @@ -61,6 +62,8 @@ import com.brainwallet.ui.BrainwalletActivity; import com.brainwallet.ui.screens.home.SettingsViewModel; import com.brainwallet.ui.screens.home.composable.HomeSettingDrawerComposeView; +import com.brainwallet.ui.screens.home.receive.ReceiveDialogFragment; +import com.brainwallet.ui.screens.home.receive.ReceiveDialogKt; import com.brainwallet.util.PermissionUtil; import com.brainwallet.wallet.BRPeerManager; import com.brainwallet.wallet.BRWalletManager; @@ -252,16 +255,22 @@ public boolean handleNavigationItemSelected(int menuItemId) { mSelectedBottomNavItem = 0; } else if (menuItemId == R.id.nav_receive) { if (BRAnimator.isClickAllowed()) { - BRAnimator.showReceiveFragment(BreadActivity.this, true); - } - mSelectedBottomNavItem = 0; - } - else if (menuItemId == R.id.nav_buy) { - if (BRAnimator.isClickAllowed()) { - BRAnimator.showMoonpayFragment(BreadActivity.this); +// BRAnimator.showReceiveFragment(BreadActivity.this, true); + //todo + ReceiveDialogFragment.show(getSupportFragmentManager()); } mSelectedBottomNavItem = 0; } +// else if (menuItemId == R.id.nav_buy) { +// if (BRAnimator.isClickAllowed()) { +//// BRAnimator.showMoonpayFragment(BreadActivity.this); +// } +// +// +// +// +// mSelectedBottomNavItem = 0; +// } return true; } diff --git a/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java b/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java index 5728657c..a0e9fd5f 100644 --- a/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java +++ b/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java @@ -83,6 +83,21 @@ public static boolean generateQR(Context ctx, String bitcoinURL, ImageView qrcod return true; } + public static Bitmap generateQR(Context ctx, String litecoinUrl) { + if (litecoinUrl == null || litecoinUrl.isEmpty()) return null; + WindowManager manager = (WindowManager) ctx.getSystemService(Activity.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + Point point = new Point(); + display.getSize(point); + int width = point.x; + int height = point.y; + int smallerDimension = Math.min(width, height); + smallerDimension = (int) (smallerDimension * 0.45f); + Bitmap bitmap = null; + bitmap = QRUtils.encodeAsBitmap(litecoinUrl, smallerDimension); + return bitmap; + } + private static String guessAppropriateEncoding(CharSequence contents) { // Very crude at the moment for (int i = 0; i < contents.length(); i++) { diff --git a/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java b/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java index 40ad36b1..7c15df6d 100644 --- a/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java +++ b/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java @@ -16,6 +16,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import timber.log.Timber; @@ -31,6 +32,27 @@ public class CurrencyDataSource implements BRDataSourceInterface { BRSQLiteHelper.CURRENCY_RATE }; + /// Set the most popular fiats + /// Hack: Database needs a symbol column. This is injected here. + private final HashMap codeSymbolsMap = new HashMap() {{ + put("USD","$"); + put("EUR","€"); + put("GBP","£"); + put("SGD","$"); + put("CAD","$"); + put("AUD","$"); + put("RUB","₽"); + put("KRW","₩"); + put("MXN","$"); + put("SAR","﷼"); + put("UAH","₴"); + put("NGN","₦"); + put("JPY","¥"); + put("CNY","¥"); + put("IDR","Rp"); + put("TRY","₺"); + }}; + private static CurrencyDataSource instance; public static CurrencyDataSource getInstance(Context context) { @@ -71,26 +93,6 @@ public List getAllCurrencies(Boolean shouldBeFiltered) { List currencies = new ArrayList<>(); - /// Set the most popular fiats - /// Hack: Database needs a symbol column. This is injected here. - HashMap codeSymbolsMap = new HashMap(); - codeSymbolsMap.put("USD","$"); - codeSymbolsMap.put("EUR","€"); - codeSymbolsMap.put("GBP","£"); - codeSymbolsMap.put("SGD","$"); - codeSymbolsMap.put("CAD","$"); - codeSymbolsMap.put("AUD","$"); - codeSymbolsMap.put("RUB","₽"); - codeSymbolsMap.put("KRW","₩"); - codeSymbolsMap.put("MXN","$"); - codeSymbolsMap.put("SAR","﷼"); - codeSymbolsMap.put("UAH","₴"); - codeSymbolsMap.put("NGN","₦"); - codeSymbolsMap.put("JPY","¥"); - codeSymbolsMap.put("CNY","¥"); - codeSymbolsMap.put("IDR","Rp"); - codeSymbolsMap.put("TRY","₺"); - /// Set the most popular fiats List filteredFiatCodes = Arrays.asList("USD","EUR","GBP", "SGD","CAD","AUD","RUB","KRW","MXN","SAR","UAH","NGN","JPY","CNY","IDR","TRY"); @@ -125,7 +127,7 @@ public List getAllCurrencies(Boolean shouldBeFiltered) { List completeCurrencyEntities = new ArrayList<>(); for(int i=0;i : ViewModel() { protected fun handleError(t: Throwable) { val errorMessage = t.message ?: "Oops, something went wrong" //todo more error handler + + if (t is retrofit2.HttpException) { + val message = t.response()?.errorBody()?.string()?.let { + runCatching { + json.decodeFromString(it)["message"]?.toString() + }.getOrNull() + } ?: "Oops, something went wrong" + + sendUiEffect( + UiEffect.ShowMessage( + type = UiEffect.ShowMessage.Type.Error, + message = message + ) + ) + return + } + sendUiEffect( UiEffect.ShowMessage( type = UiEffect.ShowMessage.Type.Error, diff --git a/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt b/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt index 2fabe5ae..f72137f5 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet @@ -18,6 +19,7 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.dp import com.brainwallet.ui.theme.BrainwalletTheme @@ -75,17 +77,21 @@ fun BrainwalletBottomSheet( fun BrainwalletButton( onClick: () -> Unit, modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = CircleShape, + colors: ButtonColors = ButtonDefaults.buttonColors( + containerColor = BrainwalletTheme.colors.surface, + contentColor = BrainwalletTheme.colors.content + ), content: @Composable RowScope.() -> Unit ) { Button( onClick = onClick, - shape = CircleShape, - colors = ButtonDefaults.buttonColors( - containerColor = BrainwalletTheme.colors.surface, - contentColor = BrainwalletTheme.colors.content - ), + enabled = enabled, + shape = shape, + colors = colors, modifier = modifier - .border(1.dp, BrainwalletTheme.colors.border, CircleShape) + .border(1.dp, BrainwalletTheme.colors.border, shape) .height(50.dp), content = content ) diff --git a/app/src/main/java/com/brainwallet/ui/composable/LargeButton.kt b/app/src/main/java/com/brainwallet/ui/composable/LargeButton.kt index a6f63965..48721758 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/LargeButton.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/LargeButton.kt @@ -10,16 +10,14 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.FilledTonalButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.graphics.drawscope.ContentDrawScope import androidx.compose.ui.unit.dp -import com.brainwallet.ui.theme.BrainwalletColors import com.brainwallet.ui.theme.BrainwalletTheme @Composable fun LargeButton( modifier: Modifier = Modifier, + enabled: Boolean = true, onClick: () -> Unit, colors: ButtonColors = ButtonDefaults.buttonColors( containerColor = BrainwalletTheme.colors.background, @@ -32,6 +30,7 @@ fun LargeButton( modifier = modifier .fillMaxWidth() .height(56.dp), + enabled = enabled, onClick = onClick, colors = colors, shape = shape, diff --git a/app/src/main/java/com/brainwallet/ui/composable/LoadingDialog.kt b/app/src/main/java/com/brainwallet/ui/composable/LoadingDialog.kt new file mode 100644 index 00000000..8c6270ad --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/LoadingDialog.kt @@ -0,0 +1,55 @@ +package com.brainwallet.ui.composable + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.brainwallet.R +import com.brainwallet.ui.theme.BrainwalletTheme + +@Composable +fun LoadingDialog( + text: String = stringResource(R.string.loading), + onDismissRequest: () -> Unit = {}, +) { + Dialog( + onDismissRequest = onDismissRequest, + properties = DialogProperties( + dismissOnClickOutside = false, + dismissOnBackPress = false + ) + ) { + Card( + shape = BrainwalletTheme.shapes.medium, + modifier = Modifier + .fillMaxWidth(0.8f) + .wrapContentHeight(), + ) { + Column( + modifier = Modifier + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + text = text, + style = BrainwalletTheme.typography.bodyLarge + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyButton.kt b/app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyButton.kt new file mode 100644 index 00000000..e3513194 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyButton.kt @@ -0,0 +1,66 @@ +package com.brainwallet.ui.composable + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.brainwallet.R +import com.brainwallet.ui.theme.BrainwalletTheme +import com.brainwallet.ui.theme.lavender +import com.brainwallet.ui.theme.nearBlack + +@Composable +fun MoonpayBuyButton( + modifier: Modifier = Modifier, + enabled: Boolean = true, + onClick: () -> Unit, +) { + Button( + modifier = modifier, + shape = BrainwalletTheme.shapes.large, + colors = ButtonDefaults.buttonColors( + containerColor = lavender, + contentColor = nearBlack + ), + enabled = enabled, + onClick = onClick, + ) { + Column( + verticalArrangement = Arrangement.spacedBy(4.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.buy_ltc).uppercase(), + style = BrainwalletTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold) + ) + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.powered_by_moonpay).uppercase(), + style = BrainwalletTheme.typography.labelSmall.copy(fontSize = 8.sp) + ) + Image( + modifier = Modifier.size(16.dp), + painter = painterResource(R.drawable.ic_moonpay_logo), + contentDescription = "moonpay" + ) + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyWidget.kt b/app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyWidget.kt new file mode 100644 index 00000000..006e45bf --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/MoonpayBuyWidget.kt @@ -0,0 +1,56 @@ +package com.brainwallet.ui.composable + + +import android.annotation.SuppressLint +import android.graphics.Bitmap +import android.view.ViewGroup +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.viewinterop.AndroidView + +//TODO: wip here + +@SuppressLint("SetJavaScriptEnabled") +@Composable +fun MoonpayBuyWidget( + modifier: Modifier = Modifier, + signedUrl: String = "https://buy.moonpay.com", +) { + AndroidView( + modifier = modifier.clip(MaterialTheme.shapes.large), + factory = { ctx -> + WebView(ctx).apply { + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + + setBackgroundColor(0) + + settings.javaScriptEnabled = true + settings.domStorageEnabled = true + settings.useWideViewPort = true + + webViewClient = object : WebViewClient() { + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + } + + override fun onPageFinished(view: WebView?, url: String?) { + super.onPageFinished(view, url) + } + } + + } + }, + update = { + it.loadUrl(signedUrl) + } + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/composable/WheelPicker.kt b/app/src/main/java/com/brainwallet/ui/composable/WheelPicker.kt new file mode 100644 index 00000000..27e9ce40 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/WheelPicker.kt @@ -0,0 +1,634 @@ +package com.brainwallet.ui.composable + +import android.util.Log +import androidx.compose.animation.core.DecayAnimationSpec +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.calculateTargetValue +import androidx.compose.animation.core.exponentialDecay +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.InteractionSource +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListItemInfo +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.saveable.listSaver +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.Velocity +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume +import kotlin.math.absoluteValue + +interface WheelPickerContentScope { + val state: WheelPickerState +} + +interface WheelPickerDisplayScope : WheelPickerContentScope { + @Composable + fun Content(index: Int) +} + +@Composable +fun VerticalWheelPicker( + modifier: Modifier = Modifier, + count: Int, + state: WheelPickerState = rememberWheelPickerState(), + key: ((index: Int) -> Any)? = null, + itemHeight: Dp = 35.dp, + unfocusedCount: Int = 2, + userScrollEnabled: Boolean = true, + reverseLayout: Boolean = false, + debug: Boolean = false, + focus: @Composable () -> Unit = { WheelPickerFocusVertical() }, + display: @Composable WheelPickerDisplayScope.(index: Int) -> Unit = { + DefaultWheelPickerDisplay( + it + ) + }, + content: @Composable WheelPickerContentScope.(index: Int) -> Unit, +) { + WheelPicker( + modifier = modifier, + isVertical = true, + count = count, + state = state, + key = key, + itemSize = itemHeight, + unfocusedCount = unfocusedCount, + userScrollEnabled = userScrollEnabled, + reverseLayout = reverseLayout, + debug = debug, + focus = focus, + display = display, + content = content, + ) +} + + +@Composable +private fun WheelPicker( + modifier: Modifier, + isVertical: Boolean, + count: Int, + state: WheelPickerState, + key: ((index: Int) -> Any)?, + itemSize: Dp, + unfocusedCount: Int, + userScrollEnabled: Boolean, + reverseLayout: Boolean, + debug: Boolean, + focus: @Composable () -> Unit, + display: @Composable WheelPickerDisplayScope.(index: Int) -> Unit, + content: @Composable WheelPickerContentScope.(index: Int) -> Unit, +) { + require(count >= 0) { "Require count >= 0" } + require(unfocusedCount >= 0) { "Require unfocusedCount >= 0" } + require(itemSize > 0.dp) { "Require itemSize > 0.dp" } + + SafeBox( + modifier = modifier, + isVertical = isVertical, + itemSize = itemSize, + unfocusedCount = unfocusedCount, + ) { safeUnfocusedCount -> + InternalWheelPicker( + isVertical = isVertical, + count = count, + state = state, + key = key, + itemSize = itemSize, + unfocusedCount = safeUnfocusedCount, + userScrollEnabled = userScrollEnabled, + reverseLayout = reverseLayout, + debug = debug, + focus = focus, + display = display, + content = content, + ) + + if (debug && unfocusedCount != safeUnfocusedCount) { + LaunchedEffect(unfocusedCount, safeUnfocusedCount) { + logMsg(true) { "unfocusedCount $unfocusedCount -> $safeUnfocusedCount" } + } + } + } +} + +@Composable +private fun InternalWheelPicker( + isVertical: Boolean, + count: Int, + state: WheelPickerState, + key: ((index: Int) -> Any)?, + itemSize: Dp, + unfocusedCount: Int, + userScrollEnabled: Boolean, + reverseLayout: Boolean, + debug: Boolean, + focus: @Composable () -> Unit, + display: @Composable WheelPickerDisplayScope.(index: Int) -> Unit, + content: @Composable WheelPickerContentScope.(index: Int) -> Unit, +) { + state.debug = debug + LaunchedEffect(state, count) { + state.updateCount(count) + } + + val nestedScrollConnection = remember(state) { + WheelPickerNestedScrollConnection(state) + }.apply { + this.isVertical = isVertical + this.itemSizePx = with(LocalDensity.current) { itemSize.roundToPx() } + this.reverseLayout = reverseLayout + } + + val totalSize = remember(itemSize, unfocusedCount) { + itemSize * (unfocusedCount * 2 + 1) + } + + val displayScope = remember(state) { + WheelPickerDisplayScopeImpl(state) + }.apply { + this.content = content + } + + Box( + modifier = Modifier + .nestedScroll(nestedScrollConnection) + .graphicsLayer { + this.alpha = if (state.isReady) 1f else 0f + } + .run { + if (totalSize > 0.dp) { + if (isVertical) { + height(totalSize).widthIn(40.dp) + } else { + width(totalSize).heightIn(40.dp) + } + } else { + this + } + }, + contentAlignment = Alignment.Center, + ) { + + val lazyListScope: LazyListScope.() -> Unit = { + + repeat(unfocusedCount) { + item(contentType = "placeholder") { + ItemSizeBox( + isVertical = isVertical, + itemSize = itemSize, + ) + } + } + + items( + count = count, + key = key, + ) { index -> + ItemSizeBox( + isVertical = isVertical, + itemSize = itemSize, + ) { + displayScope.display(index) + } + } + + repeat(unfocusedCount) { + item(contentType = "placeholder") { + ItemSizeBox( + isVertical = isVertical, + itemSize = itemSize, + ) + } + } + } + + if (isVertical) { + LazyColumn( + state = state.lazyListState, + horizontalAlignment = Alignment.CenterHorizontally, + reverseLayout = reverseLayout, + userScrollEnabled = userScrollEnabled && state.isReady, + modifier = Modifier.matchParentSize(), + content = lazyListScope, + ) + } else { + LazyRow( + state = state.lazyListState, + verticalAlignment = Alignment.CenterVertically, + reverseLayout = reverseLayout, + userScrollEnabled = userScrollEnabled && state.isReady, + modifier = Modifier.matchParentSize(), + content = lazyListScope, + ) + } + + ItemSizeBox( + modifier = Modifier.align(Alignment.Center), + isVertical = isVertical, + itemSize = itemSize, + ) { + focus() + } + } +} + +@Composable +private fun SafeBox( + modifier: Modifier = Modifier, + isVertical: Boolean, + itemSize: Dp, + unfocusedCount: Int, + content: @Composable (safeUnfocusedCount: Int) -> Unit, +) { + BoxWithConstraints( + modifier = modifier, + contentAlignment = Alignment.Center, + ) { + val maxSize = if (isVertical) maxHeight else maxWidth + val result = remember(maxSize, itemSize, unfocusedCount) { + val totalSize = itemSize * (unfocusedCount * 2 + 1) + if (totalSize <= maxSize) { + unfocusedCount + } else { + (((maxSize - itemSize) / 2f) / itemSize).toInt().coerceAtLeast(0) + } + } + content(result) + } +} + +@Composable +private fun ItemSizeBox( + modifier: Modifier = Modifier, + isVertical: Boolean, + itemSize: Dp, + content: @Composable () -> Unit = { }, +) { + Box( + modifier + .run { + if (isVertical) { + height(itemSize) + } else { + width(itemSize) + } + }, + contentAlignment = Alignment.Center, + ) { + content() + } +} + +private class WheelPickerNestedScrollConnection( + private val state: WheelPickerState, +) : NestedScrollConnection { + var isVertical: Boolean = true + var itemSizePx: Int = 0 + var reverseLayout: Boolean = false + + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource + ): Offset { + state.synchronizeCurrentIndexSnapshot() + return super.onPostScroll(consumed, available, source) + } + + override suspend fun onPreFling(available: Velocity): Velocity { + val currentIndex = state.synchronizeCurrentIndexSnapshot() + return if (currentIndex >= 0) { + available.flingItemCount( + isVertical = isVertical, + itemSize = itemSizePx, + decay = exponentialDecay(2f), + reverseLayout = reverseLayout, + ).let { flingItemCount -> + if (flingItemCount == 0) { + state.animateScrollToIndex(currentIndex) + } else { + state.animateScrollToIndex(currentIndex - flingItemCount) + } + } + available + } else { + super.onPreFling(available) + } + } +} + +private fun Velocity.flingItemCount( + isVertical: Boolean, + itemSize: Int, + decay: DecayAnimationSpec, + reverseLayout: Boolean, +): Int { + if (itemSize <= 0) return 0 + val velocity = if (isVertical) y else x + val targetValue = decay.calculateTargetValue(0f, velocity) + val flingItemCount = (targetValue / itemSize).toInt() + return if (reverseLayout) -flingItemCount else flingItemCount +} + +private class WheelPickerDisplayScopeImpl( + override val state: WheelPickerState, +) : WheelPickerDisplayScope { + + var content: @Composable WheelPickerContentScope.(index: Int) -> Unit by mutableStateOf({}) + + @Composable + override fun Content(index: Int) { + content(index) + } +} + +internal inline fun logMsg(debug: Boolean, block: () -> String) { + if (debug) { + Log.i("WheelPicker", block()) + } +} + +//default +/** + * The default implementation of focus view in vertical. + */ +@Composable +fun WheelPickerFocusVertical( + modifier: Modifier = Modifier, + dividerSize: Dp = 1.dp, + dividerColor: Color = DefaultDividerColor, +) { + Box( + modifier = modifier.fillMaxSize() + ) { + Box( + modifier = Modifier + .background(dividerColor) + .height(dividerSize) + .fillMaxWidth() + .align(Alignment.TopCenter), + ) + Box( + modifier = Modifier + .background(dividerColor) + .height(dividerSize) + .fillMaxWidth() + .align(Alignment.BottomCenter), + ) + } +} + +/** + * Default divider color. + */ +private val DefaultDividerColor: Color + @Composable + get() { + val color = if (isSystemInDarkTheme()) Color.White else Color.Black + return color.copy(alpha = 0.2f) + } + +/** + * Default display. + */ +@Composable +fun WheelPickerDisplayScope.DefaultWheelPickerDisplay( + index: Int, +) { + val focused = index == state.currentIndexSnapshot + val animateScale by animateFloatAsState( + targetValue = if (focused) 1.0f else 0.8f, + label = "Wheel picker item scale", + ) + Box( + modifier = Modifier.graphicsLayer { + this.alpha = if (focused) 1.0f else 0.3f + this.scaleX = animateScale + this.scaleY = animateScale + } + ) { + Content(index) + } +} + +//state +@Composable +fun rememberWheelPickerState( + initialIndex: Int = 0, +): WheelPickerState { + return rememberSaveable(saver = WheelPickerState.Saver) { + WheelPickerState( + initialIndex = initialIndex, + ) + } +} + +@Composable +fun WheelPickerState.CurrentIndex( + block: suspend (Int) -> Unit, +) { + val blockUpdated by rememberUpdatedState(block) + LaunchedEffect(this) { + snapshotFlow { currentIndex } + .collect { blockUpdated(it) } + } +} + +class WheelPickerState internal constructor( + initialIndex: Int, +) { + internal var debug = false + internal val lazyListState = LazyListState() + internal var isReady by mutableStateOf(false) + + private var _count = 0 + private var _currentIndex by mutableIntStateOf(-1) + private var _currentIndexSnapshot by mutableIntStateOf(-1) + + private var _pendingIndex: Int? = initialIndex.coerceAtLeast(0) + private var _pendingIndexContinuation: CancellableContinuation? = null + set(value) { + field = value + if (value == null) _pendingIndex = null + } + + /** + * Index of picker when it is idle, -1 means that there is no data. + * + * Note that this property is observable and if you use it in the composable function + * it will be recomposed on every change. + */ + val currentIndex: Int get() = _currentIndex + + /** + * Index of picker when it is idle or drag but not fling, -1 means that there is no data. + * + * Note that this property is observable and if you use it in the composable function + * it will be recomposed on every change. + */ + val currentIndexSnapshot: Int get() = _currentIndexSnapshot + + /** + * [LazyListState.interactionSource] + */ + val interactionSource: InteractionSource get() = lazyListState.interactionSource + + /** + * [LazyListState.isScrollInProgress] + */ + val isScrollInProgress: Boolean get() = lazyListState.isScrollInProgress + + suspend fun animateScrollToIndex(index: Int) { + logMsg(debug) { "animateScrollToIndex index:$index count:$_count" } + @Suppress("NAME_SHADOWING") + val index = index.coerceAtLeast(0) + lazyListState.animateScrollToItem(index) + synchronizeCurrentIndex() + } + + suspend fun scrollToIndex(index: Int) { + logMsg(debug) { "scrollToIndex index:$index count:$_count" } + @Suppress("NAME_SHADOWING") + val index = index.coerceAtLeast(0) + + // Always cancel last continuation. + _pendingIndexContinuation?.let { + logMsg(debug) { "cancelAwaitIndex" } + _pendingIndexContinuation = null + it.cancel() + } + + awaitIndex(index) + + lazyListState.scrollToItem(index) + synchronizeCurrentIndex() + } + + private suspend fun awaitIndex(index: Int) { + if (_count > 0) return + logMsg(debug) { "awaitIndex:$index start" } + suspendCancellableCoroutine { cont -> + _pendingIndex = index + _pendingIndexContinuation = cont + cont.invokeOnCancellation { + logMsg(debug) { "awaitIndex:$index canceled" } + _pendingIndexContinuation = null + } + } + logMsg(debug) { "awaitIndex:$index finish" } + } + + internal suspend fun updateCount(count: Int) { + logMsg(debug) { "updateCount count:$count currentIndex:$_currentIndex" } + + // Update count + _count = count + + val maxIndex = count - 1 + if (maxIndex < _currentIndex) { + if (count > 0) { + scrollToIndex(maxIndex) + } else { + synchronizeCurrentIndex() + } + } + + if (count > 0) { + val pendingIndex = _pendingIndex + if (pendingIndex != null) { + logMsg(debug) { "Found pendingIndex:$pendingIndex pendingIndexContinuation:$_pendingIndexContinuation" } + val continuation = _pendingIndexContinuation + _pendingIndexContinuation = null + + if (continuation?.isActive == true) { + logMsg(debug) { "resume pendingIndexContinuation" } + continuation.resume(Unit) + } else { + scrollToIndex(pendingIndex) + } + } else { + if (_currentIndex < 0) { + synchronizeCurrentIndex() + } + } + } + + isReady = count > 0 + } + + private fun synchronizeCurrentIndex() { + val index = synchronizeCurrentIndexSnapshot() + if (_currentIndex != index) { + logMsg(debug) { "setCurrentIndex:$index" } + _currentIndex = index + _currentIndexSnapshot = index + } + } + + internal fun synchronizeCurrentIndexSnapshot(): Int { + return (mostStartItemInfo()?.index ?: -1).also { + _currentIndexSnapshot = it + } + } + + /** + * The item closest to the viewport start. + */ + private fun mostStartItemInfo(): LazyListItemInfo? { + if (_count <= 0) return null + + val layoutInfo = lazyListState.layoutInfo + val listInfo = layoutInfo.visibleItemsInfo + + if (listInfo.isEmpty()) return null + if (listInfo.size == 1) return listInfo.first() + + val firstItem = listInfo.first() + val firstOffsetDelta = (firstItem.offset - layoutInfo.viewportStartOffset).absoluteValue + return if (firstOffsetDelta < firstItem.size / 2) { + firstItem + } else { + listInfo[1] + } + } + + companion object { + val Saver = listSaver( + save = { listOf(it.currentIndex) }, + restore = { WheelPickerState(initialIndex = it[0]) }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinEvent.kt new file mode 100644 index 00000000..31e528fe --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinEvent.kt @@ -0,0 +1,11 @@ +package com.brainwallet.ui.screens.buylitecoin + +import android.content.Context + +sealed class BuyLitecoinEvent { + data class OnLoad(val context: Context) : BuyLitecoinEvent() + data class OnFiatAmountChange( + val fiatAmount: Float, + val needFetch: Boolean = true + ) : BuyLitecoinEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt new file mode 100644 index 00000000..97260328 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt @@ -0,0 +1,167 @@ +package com.brainwallet.ui.screens.buylitecoin + +import android.widget.Toast +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Done +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.navigation.LegacyNavigation +import com.brainwallet.navigation.OnNavigate +import com.brainwallet.navigation.UiEffect +import com.brainwallet.ui.composable.BrainwalletScaffold +import com.brainwallet.ui.composable.BrainwalletTopAppBar +import com.brainwallet.ui.composable.LargeButton +import com.brainwallet.ui.composable.LoadingDialog +import com.brainwallet.ui.screens.home.receive.ReceiveDialogEvent +import com.brainwallet.ui.theme.BrainwalletTheme +import org.koin.compose.koinInject + +//TODO: wip +@Composable +fun BuyLitecoinScreen( + onNavigate: OnNavigate, + viewModel: BuyLitecoinViewModel = koinInject() +) { + val state by viewModel.state.collectAsState() + val loadingState by viewModel.loadingState.collectAsState() + val appSetting by viewModel.appSetting.collectAsState() + val context = LocalContext.current + + LaunchedEffect(Unit) { + viewModel.onEvent(BuyLitecoinEvent.OnLoad(context)) + viewModel.uiEffect.collect { effect -> + when (effect) { + is UiEffect.ShowMessage -> + Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() + + else -> Unit + } + } + } + + BrainwalletScaffold( + topBar = { + BrainwalletTopAppBar( + navigationIcon = { + IconButton( + onClick = { onNavigate.invoke(UiEffect.Navigate.Back()) }, + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.back), + ) + } + } + ) + } + ) { paddingValues -> + + Box( + modifier = Modifier + .padding(paddingValues) + .padding(16.dp) + .fillMaxSize(), + contentAlignment = Alignment.TopCenter + ) { + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + Text( + text = stringResource(R.string.buy_litecoin_title), + style = MaterialTheme.typography.titleLarge, + ) + + OutlinedTextField( + enabled = loadingState.visible.not(), + prefix = { + Text( + text = appSetting.currency.symbol, + style = BrainwalletTheme.typography.titleLarge.copy(color = BrainwalletTheme.colors.content) + ) + }, + textStyle = BrainwalletTheme.typography.titleLarge.copy(color = BrainwalletTheme.colors.content), + value = "${if (state.fiatAmount < 1) "" else state.fiatAmount.toInt()}", + singleLine = true, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + onValueChange = { input -> + val amount = input.toFloatOrNull() ?: 0f + viewModel.onEvent(BuyLitecoinEvent.OnFiatAmountChange(amount, false)) + }, + shape = BrainwalletTheme.shapes.extraLarge, + isError = state.isValid().not(), + supportingText = { + state.errorFiatAmountStringId?.let { + Text(stringResource(it, state.fiatAmount)) + } + } + ) + + Text( + text = state.getLtcAmountFormatted(loadingState.visible), + style = MaterialTheme.typography.titleLarge.copy( + color = BrainwalletTheme.colors.content.copy( + 0.7f + ) + ), + ) + + Text( + text = stringResource(R.string.buy_litecoin_desc), + style = MaterialTheme.typography.titleMedium + ) + + Text( + text = state.address, + style = MaterialTheme.typography.titleMedium.copy( + color = BrainwalletTheme.colors.content.copy( + 0.7f + ) + ) + ) + + } + + + LargeButton( + modifier = Modifier.align(Alignment.BottomCenter), + enabled = loadingState.visible.not(), + onClick = { + LegacyNavigation.showMoonPayWidget( + context = context, + params = mapOf( + "baseCurrencyCode" to appSetting.currency.code, + "baseCurrencyAmount" to state.fiatAmount.toString(), + "language" to appSetting.languageCode, + "walletAddress" to state.address + ) + ) + } + ) { + Text(stringResource(R.string.buy_litecoin_button_moonpay)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinState.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinState.kt new file mode 100644 index 00000000..628d6f0c --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinState.kt @@ -0,0 +1,19 @@ +package com.brainwallet.ui.screens.buylitecoin + +import com.brainwallet.data.model.MoonpayCurrencyLimit +import timber.log.Timber + +data class BuyLitecoinState( + val moonpayCurrencyLimit: MoonpayCurrencyLimit = MoonpayCurrencyLimit(), + val fiatAmount: Float = moonpayCurrencyLimit.data.baseCurrency.min, + val ltcAmount: Float = 0f, + val address: String = "", + val errorFiatAmountStringId: Int? = null +) + +fun BuyLitecoinState.isValid(): Boolean = errorFiatAmountStringId == null + +fun BuyLitecoinState.getLtcAmountFormatted(isLoading: Boolean): String = + (if (isLoading || ltcAmount < 0f) "x.xxxŁ" else "%.3fŁ".format(ltcAmount)).also { + Timber.d("TImber: ltcamount $ltcAmount") + } diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt new file mode 100644 index 00000000..5e6e6316 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt @@ -0,0 +1,128 @@ +package com.brainwallet.ui.screens.buylitecoin + +import android.util.Log +import androidx.lifecycle.viewModelScope +import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.data.repository.LtcRepository +import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.ui.BrainwalletViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.getAndUpdate +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class BuyLitecoinViewModel( + private val settingRepository: SettingRepository, + private val ltcRepository: LtcRepository +) : BrainwalletViewModel() { + + private val _state = MutableStateFlow(BuyLitecoinState()) + val state: StateFlow = _state.asStateFlow() + + val appSetting = settingRepository.settings + .distinctUntilChanged() + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + AppSetting() + ) + + init { + viewModelScope.launch { + state.map { it.fiatAmount } + .debounce(1000) + .distinctUntilChanged() + .filter { + val (_, min, max) = state.value.moonpayCurrencyLimit.data.baseCurrency + it in min..max + } + .collect { + onEvent(BuyLitecoinEvent.OnFiatAmountChange(it)) + } + } + + } + + override fun onEvent(event: BuyLitecoinEvent) { + when (event) { + is BuyLitecoinEvent.OnLoad -> viewModelScope.launch { + delay(500) + _state.update { it.copy(address = BRSharedPrefs.getReceiveAddress(event.context)) } + try { + onLoading(true) + + _state.getAndUpdate { + val limitResult = ltcRepository.fetchLimits( + baseCurrencyCode = appSetting.value.currency.code + ) + + it.copy( + moonpayCurrencyLimit = limitResult, + fiatAmount = limitResult.data.baseCurrency.min, + ) + } + } catch (e: Exception) { + handleError(e) + } finally { + onLoading(false) + } + + } + + is BuyLitecoinEvent.OnFiatAmountChange -> viewModelScope.launch { + //do validation + val (_, min, max) = state.value.moonpayCurrencyLimit.data.baseCurrency + val errorStringId = when { + event.fiatAmount < min -> R.string.buy_litecoin_fiat_amount_validation_min + event.fiatAmount > max -> R.string.buy_litecoin_fiat_amount_validation_max + else -> null + } + _state.update { + it.copy( + errorFiatAmountStringId = errorStringId, + fiatAmount = event.fiatAmount + ) + } + + if (event.needFetch.not()) { + return@launch + } + + try { + onLoading(true) + + _state.update { + val result = ltcRepository.fetchBuyQuote( + mapOf( + "currencyCode" to "ltc", + "baseCurrencyCode" to appSetting.value.currency.code, + "baseCurrencyAmount" to event.fiatAmount.toString(), + ) + ) + + it.copy( + ltcAmount = result.data.quoteCurrencyAmount, + ) + } + + } catch (e: Exception) { + handleError(e) + } finally { + onLoading(false) + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/buy/BuyScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/home/buy/BuyScreen.kt deleted file mode 100644 index 2e974ad2..00000000 --- a/app/src/main/java/com/brainwallet/ui/screens/home/buy/BuyScreen.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.brainwallet.ui.screens.home.buy - -import androidx.compose.foundation.layout.Box -import androidx.compose.runtime.Composable - -//TODO: wip -@Composable -fun BuyScreen() { - Box {} -} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt new file mode 100644 index 00000000..291015e2 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt @@ -0,0 +1,452 @@ +@file:OptIn(ExperimentalMaterial3Api::class, FlowPreview::class) + +package com.brainwallet.ui.screens.home.receive + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Done +import androidx.compose.material3.AssistChip +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.OutlinedIconButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager +import com.brainwallet.R +import com.brainwallet.data.model.getFormattedText +import com.brainwallet.data.model.isCustom +import com.brainwallet.navigation.LegacyNavigation +import com.brainwallet.navigation.UiEffect +import com.brainwallet.ui.composable.MoonpayBuyButton +import com.brainwallet.ui.composable.VerticalWheelPicker +import com.brainwallet.ui.composable.WheelPickerFocusVertical +import com.brainwallet.ui.composable.rememberWheelPickerState +import com.brainwallet.ui.theme.BrainwalletAppTheme +import com.brainwallet.ui.theme.BrainwalletTheme +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import org.koin.android.ext.android.inject +import org.koin.compose.koinInject +import timber.log.Timber + +@Composable +fun ReceiveDialog( + onDismissRequest: () -> Unit, + viewModel: ReceiveDialogViewModel = koinInject() +) { + val state by viewModel.state.collectAsState() + val loadingState by viewModel.loadingState.collectAsState() + val appSetting by viewModel.appSetting.collectAsState() + val context = LocalContext.current + val wheelPickerFiatCurrencyState = rememberWheelPickerState(0) + + LaunchedEffect(Unit) { + viewModel.onEvent(ReceiveDialogEvent.OnLoad(context)) + viewModel.uiEffect.collect { effect -> + when (effect) { + is UiEffect.ShowMessage -> Toast.makeText( + context, + effect.message, + Toast.LENGTH_SHORT + ).show() + + else -> Unit + } + } + } + + LaunchedEffect(Unit) { + delay(500) + wheelPickerFiatCurrencyState.scrollToIndex(state.getSelectedFiatCurrencyIndex()) + } + + LaunchedEffect(wheelPickerFiatCurrencyState) { + snapshotFlow { wheelPickerFiatCurrencyState.currentIndex } + .filter { it > -1 } + .distinctUntilChanged() + .debounce(700) + .collect { + Timber.i("wheelPickerFiatCurrencyState: currentIndex $it") + + viewModel.onEvent(ReceiveDialogEvent.OnFiatCurrencyChange(state.fiatCurrencies[it])) + } + } + + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + CenterAlignedTopAppBar( + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = BrainwalletTheme.colors.content //invert surface + ), + expandedHeight = 56.dp, + title = { + Text( + text = stringResource(R.string.bottom_nav_item_buy_receive_title).uppercase(), + style = BrainwalletTheme.typography.titleSmall + ) + }, + navigationIcon = { + if (state.moonpayWidgetVisible()) { + IconButton(onClick = { + viewModel.onEvent(ReceiveDialogEvent.OnSignedUrlClear) + }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.back) + ) + } + } + }, + actions = { + IconButton(onClick = onDismissRequest) { + Icon( + Icons.Default.Close, + contentDescription = stringResource(R.string.AccessibilityLabels_close), + tint = BrainwalletTheme.colors.surface + ) + } + } + ) + + //moonpay widget + //todo: revisit this later +// AnimatedVisibility(visible = state.moonpayWidgetVisible()) { +// state.moonpayBuySignedUrl?.let { signedUrl -> +// MoonpayBuyWidget( +// modifier = Modifier.height(500.dp), +// signedUrl = signedUrl +// ) +// } +// } + + + //buy / receive +// AnimatedVisibility(visible = state.moonpayWidgetVisible().not()) { + Column { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + state.qrBitmap?.asImageBitmap()?.let { imageBitmap -> + Image( + modifier = Modifier + .weight(1f), + bitmap = imageBitmap, + contentDescription = "address" + ) + } ?: Box( + modifier = Modifier + .weight(1f) + .height(180.dp) + .background(Color.Gray) + ) + + Column( + modifier = Modifier + .weight(1f), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = state.address, + style = BrainwalletTheme.typography.bodyLarge.copy( + fontWeight = FontWeight.Bold, + color = BrainwalletTheme.colors.surface + ), + maxLines = 4, + overflow = TextOverflow.Ellipsis + ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = stringResource(R.string.new_address).uppercase(), + style = BrainwalletTheme.typography.bodySmall.copy( + color = BrainwalletTheme.colors.surface, + ), + modifier = Modifier.weight(1f) + ) + OutlinedIconButton( + modifier = Modifier.size(32.dp), + onClick = { + viewModel.onEvent(ReceiveDialogEvent.OnCopyClick(context)) + Toast.makeText( + context, + R.string.Receive_copied, + Toast.LENGTH_SHORT + ) + .show() + }, + colors = IconButtonDefaults.outlinedIconButtonColors( + containerColor = BrainwalletTheme.colors.content.copy(alpha = 0.5f) + ), + ) { + Icon( + painter = androidx.compose.ui.res.painterResource(id = R.drawable.ic_copy), + contentDescription = stringResource(R.string.URLHandling_copy), + tint = BrainwalletTheme.colors.surface + ) + } + } + } + } + + HorizontalDivider() + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + VerticalWheelPicker( + modifier = Modifier.weight(1f), + focus = { + WheelPickerFocusVertical( + dividerColor = BrainwalletTheme.colors.surface.copy( + alpha = 0.5f + ) + ) + }, + unfocusedCount = 1, + count = state.fiatCurrencies.size, + state = wheelPickerFiatCurrencyState, + ) { index -> + Text( + text = state.fiatCurrencies[index].code, + fontWeight = FontWeight.Bold, + color = BrainwalletTheme.colors.surface + ) + } + + Column( + modifier = Modifier.weight(1f), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = state.getLtcAmountFormatted(loadingState.visible), + style = BrainwalletTheme.typography.titleLarge.copy( + fontWeight = FontWeight.Bold, + color = BrainwalletTheme.colors.surface + ) + ) + Text( + text = state.getRatesUpdatedAtFormatted(), + style = BrainwalletTheme.typography.bodySmall.copy( + color = BrainwalletTheme.colors.surface + ) + ) + } + } + + LazyRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + itemsIndexed(items = state.getQuickFiatAmountOptions()) { index, quickFiatAmountOption -> + AssistChip( + enabled = loadingState.visible.not(), + onClick = { + viewModel.onEvent( + ReceiveDialogEvent.OnFiatAmountOptionIndexChange( + index, + quickFiatAmountOption + ) + ) + }, + label = { + Text( + text = if (quickFiatAmountOption.isCustom()) + stringResource(R.string.custom) + else quickFiatAmountOption.getFormattedText() + ) + }, + leadingIcon = { + if (index == state.selectedQuickFiatAmountOptionIndex) { + Icon(Icons.Default.Check, contentDescription = null) + } + } + ) + } + } + + + AnimatedVisibility(visible = state.isQuickFiatAmountOptionCustom()) { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + prefix = { + Text( + text = state.selectedFiatCurrency.symbol, + style = BrainwalletTheme.typography.bodyMedium.copy(color = BrainwalletTheme.colors.surface) + ) + }, + trailingIcon = { + IconButton(onClick = { + viewModel.onEvent(ReceiveDialogEvent.OnFiatAmountChange(state.fiatAmount)) + }) { + Icon(Icons.Default.Done, contentDescription = null) + } + }, + textStyle = BrainwalletTheme.typography.bodyMedium.copy(color = BrainwalletTheme.colors.surface), + value = "${if (state.fiatAmount < 1) "" else state.fiatAmount}", + singleLine = true, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + onValueChange = { input -> + val amount = input.toFloatOrNull() ?: 0f + viewModel.onEvent(ReceiveDialogEvent.OnFiatAmountChange(amount, false)) + }, + shape = BrainwalletTheme.shapes.large, + isError = state.errorFiatAmountStringId != null, + supportingText = { + state.errorFiatAmountStringId?.let { + Text(stringResource(it, state.fiatAmount)) + } + } + ) + } + + MoonpayBuyButton( + modifier = Modifier.fillMaxWidth(), + enabled = loadingState.visible.not(), + onClick = { + + //todo: revisit this later + //viewModel.onEvent(ReceiveDialogEvent.OnMoonpayButtonClick) + + LegacyNavigation.showMoonPayWidget( + context = context, + params = mapOf( + "baseCurrencyCode" to state.selectedFiatCurrency.code, + "baseCurrencyAmount" to state.fiatAmount.toString(), + "language" to appSetting.languageCode, + "walletAddress" to state.address, + ), + isDarkMode = appSetting.isDarkMode + ) + onDismissRequest.invoke() + }, + ) + +// } + } + + + } +} + +/** + * describe [ReceiveDialogFragment] for backward compat, + * since we are still using [com.brainwallet.presenter.activities.BreadActivity] + */ +class ReceiveDialogFragment : DialogFragment() { + + private val viewModel: ReceiveDialogViewModel by inject() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return ComposeView(requireContext()).apply { + setContent { + val appSetting by viewModel.appSetting.collectAsState() + /** + * we need this theme inside this fragment, + * because we are still using fragment to display ReceiveDialog composable + * pls check BreadActivity.handleNavigationItemSelected + */ + BrainwalletAppTheme(appSetting = appSetting) { + Box( + modifier = Modifier + .padding(12.dp) + .background( + BrainwalletTheme.colors.content, + shape = BrainwalletTheme.shapes.large + ) + .border( + width = 1.dp, + color = BrainwalletTheme.colors.surface, + shape = BrainwalletTheme.shapes.large + ) + .padding(12.dp), + ) { + ReceiveDialog( + viewModel = viewModel, + onDismissRequest = { dismiss() } + ) + } + } + } + } + } + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + dialog?.window?.setBackgroundDrawableResource(android.R.color.transparent) + isCancelable = false + } + + companion object { + @JvmStatic + fun show(manager: FragmentManager) { + ReceiveDialogFragment().show(manager, "ReceiveDialogFragment") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogEvent.kt new file mode 100644 index 00000000..f1968756 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogEvent.kt @@ -0,0 +1,21 @@ +package com.brainwallet.ui.screens.home.receive + +import android.content.Context +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.QuickFiatAmountOption + +sealed class ReceiveDialogEvent { + data class OnLoad(val context: Context) : ReceiveDialogEvent() + data class OnCopyClick(val context: Context) : ReceiveDialogEvent() + data class OnFiatAmountChange(val fiatAmount: Float, val needFetch: Boolean = true) : + ReceiveDialogEvent() + + data class OnFiatCurrencyChange(val fiatCurrency: CurrencyEntity) : ReceiveDialogEvent() + data class OnFiatAmountOptionIndexChange( + val index: Int, + val quickFiatAmountOption: QuickFiatAmountOption + ) : ReceiveDialogEvent() + + object OnMoonpayButtonClick : ReceiveDialogEvent() + object OnSignedUrlClear : ReceiveDialogEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogState.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogState.kt new file mode 100644 index 00000000..745d172a --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogState.kt @@ -0,0 +1,61 @@ +package com.brainwallet.ui.screens.home.receive + +import android.graphics.Bitmap +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.MoonpayCurrencyLimit +import com.brainwallet.data.model.QuickFiatAmountOption +import timber.log.Timber +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + + +data class ReceiveDialogState( + val address: String = "", + val qrBitmap: Bitmap? = null, + val fiatCurrencies: List = listOf(), + val selectedFiatCurrency: CurrencyEntity = CurrencyEntity( + "USD", + "US Dollar", + -1f, + "$" + ), // default from shared prefs then the user can override using picker wheel at [ReceiveDialog] + val moonpayCurrencyLimit: MoonpayCurrencyLimit = MoonpayCurrencyLimit(), + val fiatAmount: Float = 0f, + val ltcAmount: Float = 0f, + val ratesUpdatedAt: Long = System.currentTimeMillis(), + val selectedQuickFiatAmountOptionIndex: Int = 1, //default is 10X, other [min, 10x, max, custom] + val errorFiatAmountStringId: Int? = null, + val moonpayBuySignedUrl: String? = null, +) + +fun ReceiveDialogState.getSelectedFiatCurrencyIndex(): Int = fiatCurrencies + .indexOfFirst { it.code.lowercase() == selectedFiatCurrency.code.lowercase() } + +fun ReceiveDialogState.getDefaultFiatAmount(): Float { + val (_, min, max) = moonpayCurrencyLimit.data.baseCurrency + return min * 10 //default is 10X +} + +fun ReceiveDialogState.getRatesUpdatedAtFormatted(): String { + val date = Date(ratesUpdatedAt) + val format = SimpleDateFormat("d MMM yyyy HH:mm:ss", Locale.ENGLISH) + return format.format(date).uppercase() +} + +fun ReceiveDialogState.getLtcAmountFormatted(isLoading: Boolean): String = + (if (isLoading || ltcAmount < 0f) "x.xxxŁ" else "%.3fŁ".format(ltcAmount)).also { + Timber.d("TImber: ltcamount $ltcAmount") + } + +fun ReceiveDialogState.getQuickFiatAmountOptions(): List { + val selectedFiatSymbol = selectedFiatCurrency.symbol + val (_, min, max) = moonpayCurrencyLimit.data.baseCurrency + return listOf(min, min * 10, max) + .map { QuickFiatAmountOption(symbol = selectedFiatSymbol, it) } + QuickFiatAmountOption() +} + +fun ReceiveDialogState.isQuickFiatAmountOptionCustom(): Boolean = + selectedQuickFiatAmountOptionIndex == 3 //3 will be custom + +fun ReceiveDialogState.moonpayWidgetVisible(): Boolean = moonpayBuySignedUrl != null \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt new file mode 100644 index 00000000..80ab1984 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt @@ -0,0 +1,179 @@ +package com.brainwallet.ui.screens.home.receive + +import androidx.lifecycle.viewModelScope +import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.data.model.isCustom +import com.brainwallet.data.repository.LtcRepository +import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.tools.manager.BRClipboardManager +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.tools.qrcode.QRUtils +import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.ui.BrainwalletViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.updateAndGet +import kotlinx.coroutines.launch + +//todo: wip +class ReceiveDialogViewModel( + private val settingRepository: SettingRepository, + private val ltcRepository: LtcRepository, +) : BrainwalletViewModel() { + + private val _state = MutableStateFlow(ReceiveDialogState()) + val state: StateFlow = _state.asStateFlow() + + val appSetting = settingRepository.settings + .distinctUntilChanged() + .onEach { setting -> + onEvent(ReceiveDialogEvent.OnFiatCurrencyChange(setting.currency)) + } + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + AppSetting() + ) + + override fun onEvent(event: ReceiveDialogEvent) { + when (event) { + is ReceiveDialogEvent.OnLoad -> _state.update { + val address = BRSharedPrefs.getReceiveAddress(event.context) + it.copy( + address = address, + qrBitmap = QRUtils.generateQR(event.context, "litecoin:${address}"), + fiatCurrencies = CurrencyDataSource.getInstance(event.context) + .getAllCurrencies(true), + ) + } + + is ReceiveDialogEvent.OnCopyClick -> BRClipboardManager.putClipboard( + event.context, + state.value.address + ) + + is ReceiveDialogEvent.OnFiatAmountChange -> viewModelScope.launch { + //do validation + val (_, min, max) = state.value.moonpayCurrencyLimit.data.baseCurrency + val errorStringId = when { + event.fiatAmount < min -> R.string.buy_litecoin_fiat_amount_validation_min + event.fiatAmount > max -> R.string.buy_litecoin_fiat_amount_validation_max + else -> null + } + _state.update { + it.copy( + errorFiatAmountStringId = errorStringId, + fiatAmount = event.fiatAmount + ) + } + + if (event.needFetch.not()) { + return@launch + } + + try { + onLoading(true) + + _state.update { + val result = ltcRepository.fetchBuyQuote( + mapOf( + "currencyCode" to "ltc", + "baseCurrencyCode" to it.selectedFiatCurrency.code, + "baseCurrencyAmount" to event.fiatAmount.toString(), + ) + ) + + it.copy( + ltcAmount = result.data.quoteCurrencyAmount, + ) + } + + } catch (e: Exception) { + handleError(e) + } finally { + onLoading(false) + } + + } + + is ReceiveDialogEvent.OnFiatCurrencyChange -> viewModelScope.launch { + try { + onLoading(true) + val currencyLimit = ltcRepository.fetchLimits(event.fiatCurrency.code) + + _state.updateAndGet { + it.copy( + selectedFiatCurrency = event.fiatCurrency, + moonpayCurrencyLimit = currencyLimit, + selectedQuickFiatAmountOptionIndex = 1, //default to 10X + fiatAmount = it.getDefaultFiatAmount(), + ) + }.let { + onEvent( + ReceiveDialogEvent.OnFiatAmountOptionIndexChange( + index = it.selectedQuickFiatAmountOptionIndex, + quickFiatAmountOption = it.getQuickFiatAmountOptions()[it.selectedQuickFiatAmountOptionIndex] + ) + ) + } + + } catch (e: Exception) { + handleError(e) + } finally { + onLoading(false) + } + } + + is ReceiveDialogEvent.OnFiatAmountOptionIndexChange -> _state.updateAndGet { + it.copy( + selectedQuickFiatAmountOptionIndex = event.index, + fiatAmount = if (event.quickFiatAmountOption.isCustom()) it.fiatAmount + else event.quickFiatAmountOption.value + ) + }.let { + if (event.quickFiatAmountOption.isCustom().not()) { + onEvent(ReceiveDialogEvent.OnFiatAmountChange(it.fiatAmount)) + } + } + + ReceiveDialogEvent.OnMoonpayButtonClick -> viewModelScope.launch { + try { + onLoading(true) + + val currentState = state.value + val signedUrl = ltcRepository.fetchMoonpaySignedUrl( + mapOf( + "baseCurrencyCode" to currentState.selectedFiatCurrency.code, + "baseCurrencyAmount" to currentState.fiatAmount.toString(), + "language" to appSetting.value.languageCode, + "walletAddress" to currentState.address, + "defaultCurrencyCode" to "ltc", + "currencyCode" to "ltc", + "themeId" to "main-v1.0.0", + "theme" to if (appSetting.value.isDarkMode) "dark" else "light" + ) + ) + + _state.update { it.copy(moonpayBuySignedUrl = signedUrl) } + + } catch (e: Exception) { + handleError(e) + } finally { + + onLoading(false) + + } + + } + + ReceiveDialogEvent.OnSignedUrlClear -> _state.update { it.copy(moonpayBuySignedUrl = null) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt index ddc14ded..22f5722d 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt @@ -3,10 +3,6 @@ package com.brainwallet.ui.screens.topup -import android.graphics.Bitmap -import android.view.ViewGroup -import android.webkit.WebView -import android.webkit.WebViewClient import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -15,7 +11,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowForward @@ -25,12 +20,6 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate @@ -39,27 +28,25 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.viewmodel.compose.viewModel import com.brainwallet.R import com.brainwallet.navigation.OnNavigate +import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect import com.brainwallet.tools.manager.AnalyticsManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.composable.BorderedLargeButton import com.brainwallet.ui.composable.BrainwalletScaffold import com.brainwallet.ui.composable.BrainwalletTopAppBar -import com.brainwallet.ui.composable.MediumTextButton import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItEvent import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItViewModel -import kotlinx.coroutines.delay @Composable fun TopUpScreen( onNavigate: OnNavigate, viewModel: YourSeedProveItViewModel = viewModel() ) { - val state by viewModel.state.collectAsState() + val context = LocalContext.current /// Layout values @@ -69,13 +56,6 @@ fun TopUpScreen( val spacerHeight = 90 val skipButtonWidth = 100 - var shouldShowWebView by remember { mutableStateOf(false) } - var backEnabled by remember { mutableStateOf(false) } - var shouldSkipBeVisible by remember { mutableStateOf(false) } - - LaunchedEffect(Unit) { - } - BrainwalletScaffold( topBar = { BrainwalletTopAppBar( @@ -93,7 +73,6 @@ fun TopUpScreen( } ) { paddingValues -> - Spacer(modifier = Modifier.height(spacerHeight.dp)) Column( modifier = Modifier @@ -103,129 +82,54 @@ fun TopUpScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), ) { - - if (!shouldShowWebView) { + Spacer(modifier = Modifier.weight(1f)) + Row { + Icon( + Icons.AutoMirrored.Filled.ArrowForward, + contentDescription = stringResource(R.string.down_left_arrow), + modifier = Modifier + .rotate(45f) + .graphicsLayer( + scaleX = 2f, + scaleY = 2f + ) + ) Spacer(modifier = Modifier.weight(1f)) - Row { - Icon( - Icons.AutoMirrored.Filled.ArrowForward, - contentDescription = stringResource(R.string.down_left_arrow), - modifier = Modifier - .rotate(45f) - .graphicsLayer( - scaleX = 2f, - scaleY = 2f - ) - ) - Spacer(modifier = Modifier.weight(1f)) - } + } - Text( - text = stringResource(R.string.top_up_title), - style = MaterialTheme.typography.displaySmall.copy(textAlign = TextAlign.Left), - modifier = Modifier.fillMaxWidth() - ) + Text( + text = stringResource(R.string.top_up_title), + style = MaterialTheme.typography.displaySmall.copy(textAlign = TextAlign.Left), + modifier = Modifier.fillMaxWidth() + ) + + Text( + text = stringResource(R.string.top_up_detail_1), + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.fillMaxWidth() + ) + BorderedLargeButton( + onClick = { onNavigate.invoke(UiEffect.Navigate(destinationRoute = Route.BuyLitecoin)) }, + modifier = Modifier.fillMaxWidth() + ) { Text( - text = stringResource(R.string.top_up_detail_1), - style = MaterialTheme.typography.bodyLarge, - modifier = Modifier.fillMaxWidth() + text = stringResource(R.string.top_up_button_1), + style = MaterialTheme.typography.bodyLarge ) } - if (shouldShowWebView) { - AndroidView( - factory = { - WebView(it).apply { - setInitialScale(99) - setLayerType(ViewGroup.LAYER_TYPE_SOFTWARE, null) - settings.apply { - javaScriptEnabled = true - useWideViewPort = true - loadWithOverviewMode = true - builtInZoomControls = true - domStorageEnabled = true - allowContentAccess = true - } - webViewClient = object : WebViewClient() { - override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) { - backEnabled = view.canGoBack() - } - } - webViewClient = object : WebViewClient() { - override fun onPageFinished(view: WebView?, url: String?) { - shouldSkipBeVisible = true - } - } - - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT) - - } - }, - update = { - it.loadUrl(BRConstants.MOBILE_MP_LINK) - }, - modifier = Modifier - .height(600.dp) - .weight(1f) + BorderedLargeButton( + onClick = { + viewModel.onEvent(YourSeedProveItEvent.OnGameAndSync) + AnalyticsManager.logCustomEvent(BRConstants._20250303_DSTU) + }, + modifier = Modifier.fillMaxWidth() + + ) { + Text( + text = stringResource(R.string.top_up_button_2), + style = MaterialTheme.typography.bodyMedium ) - Row( - modifier = Modifier - .fillMaxWidth() - .height(buttonRowHeight.dp), - - ){ - Spacer(modifier = Modifier.weight(1f)) - if(shouldSkipBeVisible) { - MediumTextButton( - onClick = { - viewModel.onEvent(YourSeedProveItEvent.OnGameAndSync) - AnalyticsManager.logCustomEvent(BRConstants._20250303_DSTU) - }, - modifier = Modifier - .width(skipButtonWidth.dp) - .padding(vertical = horizontalVerticalSpacing.dp), - - ) { - - Text( - text = stringResource(R.string.top_up_button_3), - style = MaterialTheme.typography.bodyMedium, - textAlign = TextAlign.Right - ) - } - } - } - - } - if (!shouldShowWebView) { - BorderedLargeButton( - onClick = { - shouldShowWebView = true - }, - modifier = Modifier.fillMaxWidth() - - ) { - Text( - text = stringResource(R.string.top_up_button_1), - style = MaterialTheme.typography.bodyLarge - ) - } - BorderedLargeButton( - onClick = { - viewModel.onEvent(YourSeedProveItEvent.OnGameAndSync) - AnalyticsManager.logCustomEvent(BRConstants._20250303_DSTU) - }, - modifier = Modifier.fillMaxWidth() - - ) { - Text( - text = stringResource(R.string.top_up_button_2), - style = MaterialTheme.typography.bodyMedium - ) - } - } Spacer(modifier = Modifier.weight(0.05f)) diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt index 6f4d19c4..998ddb00 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt @@ -18,8 +18,8 @@ class YourSeedProveItViewModel : BrainwalletViewModel() { when (event) { is YourSeedProveItEvent.OnLoad -> _state.update { it.copy( - correctSeedWords = event.seedWords.mapIndexed { index, word -> - index to SeedWordItem(expected = word) + correctSeedWords = event.seedWords.mapIndexed { index, word -> + index to SeedWordItem(expected = word) }.toMap(), shuffledSeedWords = event.seedWords.shuffled() ) diff --git a/app/src/main/java/com/brainwallet/ui/theme/Theme.kt b/app/src/main/java/com/brainwallet/ui/theme/Theme.kt index 819eb43e..36afabbe 100644 --- a/app/src/main/java/com/brainwallet/ui/theme/Theme.kt +++ b/app/src/main/java/com/brainwallet/ui/theme/Theme.kt @@ -1,6 +1,7 @@ package com.brainwallet.ui.theme import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Shapes import androidx.compose.material3.Typography import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -84,6 +85,9 @@ object BrainwalletTheme { val typography: Typography @Composable @ReadOnlyComposable get() = MaterialTheme.typography + val shapes: Shapes + @Composable @ReadOnlyComposable get() = MaterialTheme.shapes + //todo: add typography, shape? for the design system } diff --git a/app/src/main/res/drawable/ic_copy.xml b/app/src/main/res/drawable/ic_copy.xml new file mode 100644 index 00000000..6a0293ec --- /dev/null +++ b/app/src/main/res/drawable/ic_copy.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_import.xml b/app/src/main/res/drawable/ic_import.xml new file mode 100644 index 00000000..33f6260c --- /dev/null +++ b/app/src/main/res/drawable/ic_import.xml @@ -0,0 +1,19 @@ + + + + diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index 0d1f4a90..dc0df45e 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -19,10 +19,10 @@ android:icon="@drawable/ic_nav_receive" android:title="@string/Button.receive" /> - + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu_us.xml b/app/src/main/res/menu/bottom_nav_menu_us.xml index 2d26a165..187ac237 100644 --- a/app/src/main/res/menu/bottom_nav_menu_us.xml +++ b/app/src/main/res/menu/bottom_nav_menu_us.xml @@ -1,27 +1,28 @@ + + - + android:title="@string/bottom_nav_item_buy_receive_title" /> - + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 8a3ee8f0..cf9095d7 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -439,4 +439,15 @@ قمة واسطة قليل + مزامنة البيانات التعريفية: + شراء لايتكوين + مدعوم من مونباي + تحميل... + المبلغ أقل من الحد الأدنى (%1$f) + يتجاوز المبلغ الحد الأقصى (%1$f) + شراء لايتكوين + يتم إيداعها في عنوان LTC الخاص بك: + الشراء باستخدام Moonpay + العنوان الجديد + شراء / تلقي diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6d272928..a07b7400 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -800,4 +800,15 @@ Spitze Medium Niedrig + Metadaten synchronisieren: + Kaufen Sie LTC + Unterstützt von Moonpay + Laden... + Betrag liegt unter dem Mindestlimit (%1$f) + Betrag überschreitet Höchstgrenze (%1$f) + Litecoin kaufen + Bitte überweisen Sie es an Ihre LTC-Adresse: + Kaufen Sie mit Moonpay + Neue Adresse + Kaufen / Empfangen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 24bf3fc0..1a918843 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -799,4 +799,15 @@ Arriba Medio Bajo + Sincronizar metadatos: + Comprar LTC + Desarrollado por Moonpay + Cargando... + El monto está por debajo del límite mínimo (%1$f) + El importe supera el límite máximo (%1$f) + Comprar Litecoin + Se depositará en su dirección LTC: + Compra con Moonpay + Nueva dirección + Comprar / Recibir diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 1571dd93..b0e92d08 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -800,4 +800,15 @@ Haut Moyen Faible + Synchroniser les métadonnées : + Acheter des SLD + Propulsé par Moonpay + Chargement... + Le montant est inférieur à la limite minimale (%1$f) + Le montant dépasse la limite maximale (%1$f) + Acheter du Litecoin + Soyez déposé à votre adresse LTC : + Acheter avec Moonpay + Nouvelle adresse + Acheter / Recevoir diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index a03d849c..3c263e70 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -438,4 +438,15 @@ शीर्ष मध्यम कम + मेटाडेटा सिंक करें: + एलटीसी खरीदें + मूनपे द्वारा संचालित + लोड हो रहा है... + राशि न्यूनतम सीमा से कम है (%1$f) + राशि अधिकतम सीमा से अधिक है (%1$f) + लाइटकॉइन खरीदें + अपने एलटीसी पते पर जमा करें: + मूनपे से खरीदें + नया पता + खरीदें/प्राप्त करें diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index d3bb43e0..371a07fa 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -802,4 +802,15 @@ Atas Sedang Rendah + Sinkronkan metadata: + Beli LTC + Didukung oleh Moonpay + Memuat... + Jumlahnya di bawah batas minimum (%1$f) + Jumlah melebihi batas maksimum (%1$f) + Beli Litecoin + Disetorkan ke Alamat LTC Anda: + Beli dengan Moonpay + Alamat Baru + Beli / Terima diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 592ebba1..0246634a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -800,4 +800,15 @@ Superiore Medio Basso + Sincronizza i metadati: + Acquista LTC + Alimentato da Moonpay + Caricamento... + L\'importo è inferiore al limite minimo (%1$f) + L\'importo supera il limite massimo (%1$f) + Acquista Litecoin + Essere depositato al tuo indirizzo LTC: + Acquista con Moonpay + Nuovo indirizzo + Acquista/Ricevi diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index c6ffb20c..9523482b 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -800,4 +800,15 @@ トップ 中くらい 低い + メタデータを同期する: + LTCを購入する + ムーンペイ提供 + 読み込み中... + 金額が下限値 (%1$f) を下回っています + 量が上限を超えています (%1$f) + ライトコインを購入する + LTCアドレスに入金してください: + Moonpay で購入する + 新しい住所 + 買う/受け取る diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 8ec4b384..0f409eb0 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -800,4 +800,15 @@ 맨 위 중간 낮은 + 메타데이터 동기화: + 라이트코인 구매 + 문페이 제공 + 로드 중... + 금액이 최소 한도(%1$f)보다 낮습니다. + 금액이 최대 한도(%1$f)를 초과했습니다. + 라이트코인 구매 + LTC 주소로 입금하세요: + 문페이로 구매하세요 + 새 주소 + 구매 / 받기 diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 27b64935..535904d3 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -799,4 +799,15 @@ Principal Médio Baixo + Sincronizar metadados: + Comprar LTC + Desenvolvido por Moonpay + Carregando... + O valor está abaixo do limite mínimo (%1$f) + O valor excede o limite máximo (%1$f) + Comprar Litecoin + Seja depositado em seu endereço LTC: + Compre com Moonpay + Novo endereço + Comprar / Receber diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 4df74670..5434b353 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -800,4 +800,15 @@ Вершина Середина Низкий + Синхронизировать метаданные: + Купить LTC + При поддержке Moonpay + Загрузка... + Сумма ниже минимального лимита (%1$f) + Сумма превышает максимальный лимит (%1$f) + Купить Лайткоин + Депонируйте на свой адрес LTC: + Купить с помощью Moonpay + Новый адрес + Купить/получить diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 78b503fd..eef96cac 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -438,4 +438,15 @@ Bästa Medium Låg + Synkronisera metadata: + Köp LTC + Drivs av Moonpay + Belastning... + Beloppet är under minimigränsen (%1$f) + Beloppet överskrider maxgränsen (%1$f) + Köp Litecoin + Sätt in till din LTC-adress: + Köp med Moonpay + Ny adress + Köp/ta emot diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index a526c60c..b67506d4 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -823,4 +823,16 @@ Tepe Orta Düşük + + Meta verileri senkronize et: + LTC satın al + Moonpay tarafından desteklenmektedir + Yükleniyor... + Tutar minimum sınırın altında (%1$f) + Tutar maksimum sınırı aşıyor (%1$f) + Litecoin satın al + LTC Adresinize yatırın: + Moonpay ile satın alın + Yeni Adres + Satın Al / Al diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index b5d20546..f8899d68 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -806,4 +806,16 @@ Топ Середній Низький + + Синхронізувати метадані: + Купити LTC + На основі Moonpay + Завантаження... + Сума нижче мінімального ліміту (%1$f) + Сума перевищує максимальний ліміт (%1$f) + Купуйте Litecoin + Зробіть депозит на свою адресу LTC: + Купуйте за допомогою Moonpay + Нова адреса + Купити / Отримати diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 53cd941f..763288ac 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -800,4 +800,15 @@ 顶部 中等的 低的 + 同步元数据: + 购买莱特币 + 由 月付 提供支持 + 加载中... + 金额低于最低限额 (%1$f) + 金额超过最大限制 (%1$f) + 购买莱特币 + 请存入您的 LTC 地址: + 使用 Moonpay 购买 + 新地址 + 购买/接收 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 69514c55..fe1abc56 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -800,4 +800,15 @@ 頂部 中等的 低的 + 同步元資料: + 購買萊特幣 + 由 月付 提供支持 + 載入中... + 金額低於最低限額 (%1$f) + 金額超過最大限制 (%1$f) + 購買萊特幣 + 請存入您的 LTC 地址: + 使用 Moonpay 購買 + 新地址 + 購買/接收 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d107536c..f7c7deb0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -74,7 +74,7 @@ receive - send + Send Settings @@ -839,8 +839,20 @@ Share analytics data Update PIN Show + Buy LTC + Powered by Moonpay + Loading... Network Fee (per kb): Higher value mean the transaction completes sooner Top Medium Low + Amount is below minimum limit (%f) + Amount exceeds maximum limit (%f) + Buy Litecoin + Do be deposited to your LTC Address: + Buy with Moonpay + New Address + + Buy / Receive + Custom From 18eda469fb568e492d9f7a6f3a5b95d240872478 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 12 May 2025 13:29:20 +0100 Subject: [PATCH 29/65] version and code bump --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 80cc7aec..172a0a87 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505021 - versionName = "v4.4.7" + versionCode = 202505121 + versionName = "v4.5.0" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") From dbb6a5fee697fa6d29f0fdd32e77f378029b4a7a Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 19 May 2025 01:22:10 -0700 Subject: [PATCH 30/65] Added support url (#81) - changed the language - code bump --- app/build.gradle.kts | 2 +- app/src/main/java/com/brainwallet/tools/util/BRConstants.java | 1 + .../ui/screens/home/composable/HomeSettingDrawerSheet.kt | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 172a0a87..8add0963 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,7 +20,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505121 + versionCode = 202505141 versionName = "v4.5.0" multiDexEnabled = true diff --git a/app/src/main/java/com/brainwallet/tools/util/BRConstants.java b/app/src/main/java/com/brainwallet/tools/util/BRConstants.java index 1c4d4a53..7c989533 100644 --- a/app/src/main/java/com/brainwallet/tools/util/BRConstants.java +++ b/app/src/main/java/com/brainwallet/tools/util/BRConstants.java @@ -98,6 +98,7 @@ private BRConstants() { public static final String TWITTER_LINK = "https://twitter.com/Brainwallet_App"; public static final String INSTAGRAM_LINK = "https://www.instagram.com/brainwalletapp"; public static final String WEB_LINK = "https://brainwallet.co"; + public static final String SUPPORT_WEB_LINK = "https://brainwallet.co/support.html"; public static final String TOS_LINK = "https://brainwallet.co/privacy-policy.html"; public static final String MOBILE_MP_LINK = "https://brainwallet.co/mobile-top-up.html"; public static String BITREFILL_AFFILIATE_LINK = "https://www.bitrefill.com/"; diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt index 5c0c6a9c..1daa4b33 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -144,11 +144,11 @@ fun HomeSettingDrawerSheet( item { SettingRowItem( title = stringResource(R.string.settings_title_support), - description = "brainwallet.co", + description = "brainwallet.co/support.html", onClick = { val builder = CustomTabsIntent.Builder() val customTabsIntent = builder.build() - customTabsIntent.launchUrl(context, Uri.parse(BRConstants.WEB_LINK)) + customTabsIntent.launchUrl(context, Uri.parse(BRConstants.SUPPORT_WEB_LINK)) } ) } From c82a5e3316282bc3d7d31d3c5e8d7ebb5774f521 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 19 May 2025 09:26:16 +0100 Subject: [PATCH 31/65] version and code bump --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8add0963..290ed2dd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505141 - versionName = "v4.5.0" + versionCode = 202505191 + versionName = "v4.5.3" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") From 2981ec62d3974cbbc12ad70617612588b181135b Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Sun, 25 May 2025 19:32:34 +0700 Subject: [PATCH 32/65] Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington --- .../java/com/brainwallet/data/model/Fee.kt | 27 ++++++++---- .../data/repository/LtcRepository.kt | 18 ++++---- .../data/repository/SettingRepository.kt | 17 ++++++++ .../presenter/fragments/FragmentSend.kt | 32 ++++++++------- .../brainwallet/tools/manager/FeeManager.java | 27 +++++++++--- .../tools/manager/PromptManager.java | 2 + .../brainwallet/tools/util/BRConstants.java | 6 +-- .../brainwallet/tools/util/BRExchange.java | 12 ++++-- .../com/brainwallet/tools/util/Utils.java | 41 ++++++++----------- .../ui/screens/home/SettingsEvent.kt | 2 + .../ui/screens/home/SettingsState.kt | 2 + .../ui/screens/home/SettingsViewModel.kt | 28 ++++++++++++- .../home/composable/HomeSettingDrawerSheet.kt | 1 + .../settingsrows/LitecoinBlockchainDetail.kt | 18 ++------ .../brainwallet/wallet/BRWalletManager.java | 17 +++++--- .../tools/database/DatabaseTests.kt | 1 - .../brainwallet/tools/util/BRConstantsTest.kt | 2 - 17 files changed, 160 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/com/brainwallet/data/model/Fee.kt b/app/src/main/java/com/brainwallet/data/model/Fee.kt index 0ea99667..b1d086ae 100644 --- a/app/src/main/java/com/brainwallet/data/model/Fee.kt +++ b/app/src/main/java/com/brainwallet/data/model/Fee.kt @@ -8,8 +8,6 @@ import com.brainwallet.tools.manager.FeeManager.LUXURY import com.brainwallet.tools.manager.FeeManager.REGULAR import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlin.math.ceil -import kotlin.math.round @Serializable data class Fee( @@ -22,23 +20,31 @@ data class Fee( @JvmField @SerialName("fee_per_kb_economy") var economy: Long, + var timestamp: Long ) { companion object { - //from legacy - // this is the default that matches the mobile-api if the server is unavailable - private const val defaultEconomyFeePerKB: Long = - 2500L // From legacy minimum. default min is 1000 as Litecoin Core version v0.17.1 + /** + * Default value for economy fee rate per kilobyte. + * Used as a fallback when fee rate cannot be determined dynamically. + * + * Previous value: 2500L (2.5 satoshis per byte). From legacy minimum. default min is 1000 as Litecoin Core version v0.17.1 + * Updated economy to 8000L (8 satoshis per byte) on 2023-11-16 (same as iOS) + */ + private const val defaultEconomyFeePerKB: Long = 8000L private const val defaultRegularFeePerKB: Long = 25000L private const val defaultLuxuryFeePerKB: Long = 66746L private const val defaultTimestamp: Long = 1583015199122L -// {"fee_per_kb":5289,"fee_per_kb_economy":2645,"fee_per_kb_luxury":10578} - + /** + * currently we are using this static [Default] for our fee + * maybe we need to update core if we need dynamic fee? + */ @JvmStatic val Default = Fee( defaultLuxuryFeePerKB, defaultRegularFeePerKB, defaultEconomyFeePerKB, + defaultTimestamp ) } } @@ -80,4 +86,9 @@ fun FeeOption.getFiatFormatted(currencyEntity: CurrencyEntity): String { val fiatValue = getFiat(currencyEntity) val formatted = String.format("%.3f", fiatValue) return "${currencyEntity.symbol}$formatted" +} + +fun List.getSelectedIndex(selectedFeeType: String): Int { + return indexOfFirst { it.type == selectedFeeType }.takeIf { it >= 0 } + ?: 2 //2 -> index of top, since we have [low,medium,top] } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index 365bbc0d..962602f7 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -54,17 +54,13 @@ interface LtcRepository { } - override suspend fun fetchFeePerKb(): Fee { - return sharedPreferences.fetchWithCache( - key = PREF_KEY_NETWORK_FEE_PER_KB, - cachedAtKey = PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT, - cacheTimeMs = 6 * 60 * 60 * 1000, - fetchData = { - remoteApiSource.getFeePerKb() - }, - defaultValue = Fee.Default - ) - } + /** + * for now we just using [Fee.Default] + * will move to [RemoteApiSource.getFeePerKb] after fix the calculation when we do send + * + * maybe need updaete core if we need to use dynamic fee? + */ + override suspend fun fetchFeePerKb(): Fee = Fee.Default //using static fee override suspend fun fetchLimits(baseCurrencyCode: String): MoonpayCurrencyLimit { return sharedPreferences.fetchWithCache( diff --git a/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt index 2e4b3388..3f217918 100644 --- a/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt @@ -5,6 +5,7 @@ import androidx.core.content.edit import com.brainwallet.data.model.AppSetting import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Language +import com.brainwallet.tools.manager.FeeManager import com.brainwallet.tools.sqlite.CurrencyDataSource import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -36,6 +37,10 @@ interface SettingRepository { fun toggleDarkMode(isDarkMode: Boolean) + fun putSelectedFeeType(feeType: String) + + fun getSelectedFeeType(): String + class Impl( private val sharedPreferences: SharedPreferences, private val currencyDataSource: CurrencyDataSource @@ -77,6 +82,17 @@ interface SettingRepository { _state.update { it.copy(isDarkMode = isDarkMode) } } + override fun putSelectedFeeType(feeType: String) { + sharedPreferences.edit { + putString(KEY_SELECTED_FEE_TYPE, feeType) + } + } + + override fun getSelectedFeeType(): String = + sharedPreferences.getString(KEY_SELECTED_FEE_TYPE, FeeManager.REGULAR) + ?: FeeManager.REGULAR + + private fun load(): AppSetting { return AppSetting( isDarkMode = sharedPreferences.getBoolean(KEY_IS_DARK_MODE, true), @@ -100,5 +116,6 @@ interface SettingRepository { const val KEY_IS_DARK_MODE = "is_dark_mode" const val KEY_LANGUAGE_CODE = "language_code" const val KEY_FIAT_CURRENCY_CODE = "fiat_currency_code" + const val KEY_SELECTED_FEE_TYPE = "selected_fee_type" } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt index 9b47690e..83d08dcb 100644 --- a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt +++ b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentSend.kt @@ -135,6 +135,9 @@ class FragmentSend : Fragment() { updateText() + //update fee + BRWalletManager.getInstance().setFeePerKb(FeeManager.getInstance().currentFeeValue) + return rootView } @@ -496,7 +499,6 @@ class FragmentSend : Fragment() { override fun onStop() { super.onStop() - FeeManager.getInstance().resetFeeType() } override fun onResume() { @@ -611,9 +613,22 @@ class FragmentSend : Fragment() { } Timber.d("timber: updateText: currentAmountInLitoshis %d", currentAmountInLitoshis) + // Service Fee depending on ISOSymbol + var serviceFee = Utils.tieredOpsFee(activity, currentAmountInLitoshis) + val serviceFeeForISOSymbol = + BRExchange.getAmountFromLitoshis(activity, selectedISOSymbol, BigDecimal(serviceFee)) + .setScale(scaleValue, RoundingMode.HALF_UP) + val formattedServiceFee = BRCurrency.getFormattedCurrencyString( + activity, + selectedISOSymbol, + serviceFeeForISOSymbol + ) + + val totalAmountToCalculateFees = currentAmountInLitoshis + serviceFee + // Network Fee depending on ISOSymbol - var networkFee = if (currentAmountInLitoshis > 0) { - BRWalletManager.getInstance().feeForTransactionAmount(currentAmountInLitoshis) + var networkFee = if (totalAmountToCalculateFees > 0) { + BRWalletManager.getInstance().feeForTransactionAmount(totalAmountToCalculateFees) } else { 0 } //Amount is zero so network fee is also zero @@ -626,17 +641,6 @@ class FragmentSend : Fragment() { networkFeeForISOSymbol ) - // Service Fee depending on ISOSymbol - var serviceFee = Utils.tieredOpsFee(activity, currentAmountInLitoshis) - val serviceFeeForISOSymbol = - BRExchange.getAmountFromLitoshis(activity, selectedISOSymbol, BigDecimal(serviceFee)) - .setScale(scaleValue, RoundingMode.HALF_UP) - val formattedServiceFee = BRCurrency.getFormattedCurrencyString( - activity, - selectedISOSymbol, - serviceFeeForISOSymbol - ) - // Total Fees depending on ISOSymbol val totalFees = networkFee + serviceFee val totalFeeForISOSymbol = diff --git a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java index f9457baa..bf927976 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/FeeManager.java @@ -4,9 +4,10 @@ import androidx.annotation.StringDef; +import com.brainwallet.data.model.Fee; import com.brainwallet.data.repository.LtcRepository; +import com.brainwallet.data.repository.SettingRepository; import com.brainwallet.tools.threads.BRExecutor; -import com.brainwallet.data.model.Fee; import org.koin.java.KoinJavaComponent; @@ -14,7 +15,6 @@ import java.lang.annotation.RetentionPolicy; //we are still using this, maybe in the future will deprecate? -@Deprecated public final class FeeManager { @@ -56,8 +56,24 @@ public boolean isLuxuryFee() { public static final String REGULAR = "regular";//medium public static final String ECONOMY = "economy";//low - public void setFees(long luxuryFee, long regularFee, long economyFee) { - currentFeeOptions = new Fee(luxuryFee, regularFee, economyFee); + public void setFees(Fee fee) { + currentFeeOptions = fee; + } + + public long getCurrentFeeValue() { + SettingRepository settingRepository = KoinJavaComponent.get(SettingRepository.class); + String feeType = settingRepository.getSelectedFeeType(); + + switch (feeType) { + case LUXURY: + return currentFeeOptions.luxury; + case REGULAR: + return currentFeeOptions.regular; + case ECONOMY: + return currentFeeOptions.economy; + default: + return currentFeeOptions.regular; // Default to regular fee + } } public static void updateFeePerKb(Context app) { @@ -66,8 +82,7 @@ public static void updateFeePerKb(Context app) { (coroutineScope, continuation) -> ltcRepository.fetchFeePerKb(continuation) ).whenComplete((fee, throwable) -> { - //legacy logic - FeeManager.getInstance().setFees(fee.luxury, fee.regular, fee.economy); + FeeManager.getInstance().setFees(fee); BRSharedPrefs.putFeeTime(app, System.currentTimeMillis()); //store the time of the last successful fee fetch }); } diff --git a/app/src/main/java/com/brainwallet/tools/manager/PromptManager.java b/app/src/main/java/com/brainwallet/tools/manager/PromptManager.java index e6c9a029..a716d7f7 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/PromptManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/PromptManager.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.view.View; +import com.brainwallet.presenter.activities.settings.SyncBlockchainActivity; import com.brainwallet.tools.security.BRKeyStore; import com.brainwallet.tools.threads.BRExecutor; import com.brainwallet.R; @@ -88,6 +89,7 @@ public void run() { BRSharedPrefs.putStartHeight(app, 0); BRPeerManager.getInstance().rescan(); BRSharedPrefs.putScanRecommended(app, false); + BRSharedPrefs.putAllowSpend(app, false); } }); } diff --git a/app/src/main/java/com/brainwallet/tools/util/BRConstants.java b/app/src/main/java/com/brainwallet/tools/util/BRConstants.java index 7c989533..bd8f810b 100644 --- a/app/src/main/java/com/brainwallet/tools/util/BRConstants.java +++ b/app/src/main/java/com/brainwallet/tools/util/BRConstants.java @@ -129,7 +129,6 @@ private BRConstants() { public static final String _20201118_DTGS = "did_tap_get_support"; public static final String _20200217_DUWP = "did_unlock_with_pin"; public static final String _20200217_DUWB = "did_unlock_with_biometrics"; - public static final String _20200301_DUDFPK = "did_use_default_fee_per_kb"; public static final String _20201121_SIL = "started_IFPS_lookup"; public static final String _20201121_DRIA = "did_resolve_IPFS_address"; public static final String _20201121_FRIA = "failed_resolve_IPFS_address"; @@ -137,6 +136,7 @@ private BRConstants() { public static final String _20230407_DCS = "did_complete_sync"; public static final String _20250303_DSTU = "did_skip_top_up"; + public static final String _20250517_WCINFO = "wallet_callback_info"; ///Dev: These events not yet used public static final String _20200207_DTHB = "did_tap_header_balance"; @@ -170,7 +170,6 @@ private BRConstants() { _20201118_DTGS, _20200217_DUWP, _20200217_DUWB, - _20200301_DUDFPK, _20201121_SIL, _20201121_DRIA, _20201121_FRIA, @@ -187,7 +186,8 @@ private BRConstants() { _20241006_UCR, _HOME_OPEN, _20250222_PAC, - _20250303_DSTU + _20250303_DSTU, + _20250517_WCINFO }) public @interface Event { } diff --git a/app/src/main/java/com/brainwallet/tools/util/BRExchange.java b/app/src/main/java/com/brainwallet/tools/util/BRExchange.java index 52b6df6b..c199b115 100644 --- a/app/src/main/java/com/brainwallet/tools/util/BRExchange.java +++ b/app/src/main/java/com/brainwallet/tools/util/BRExchange.java @@ -102,11 +102,17 @@ public static BigDecimal getLitoshisFromAmount(Context app, String iso, BigDecim if (iso.equalsIgnoreCase("LTC")) { result = BRExchange.getLitoshisForLitecoin(app, amount); } else { - //multiply by 100 because core function localAmount accepts the smallest amount e.g. cents CurrencyEntity ent = CurrencyDataSource.getInstance(app).getCurrencyByIso(iso); if (ent == null) return new BigDecimal(0); - BigDecimal rate = new BigDecimal(ent.rate).multiply(new BigDecimal(100)); - result = new BigDecimal(BRWalletManager.getInstance().bitcoinAmount(amount.multiply(new BigDecimal(100)).longValue(), rate.doubleValue())); + + // Get the exchange rate + BigDecimal rate = new BigDecimal(ent.rate); + + result = amount.divide(rate, 8, BRConstants.ROUNDING_MODE) + .multiply(new BigDecimal("100000000")); + + // Round to a whole number of litoshis + result = result.setScale(0, BRConstants.ROUNDING_MODE); } return result; } diff --git a/app/src/main/java/com/brainwallet/tools/util/Utils.java b/app/src/main/java/com/brainwallet/tools/util/Utils.java index 8e7e6062..fb03d0c3 100644 --- a/app/src/main/java/com/brainwallet/tools/util/Utils.java +++ b/app/src/main/java/com/brainwallet/tools/util/Utils.java @@ -267,38 +267,29 @@ else if (name == ServiceItems.CLIENTCODE) { } /// Description: 1715876807 public static long tieredOpsFee(Context app, long sendAmount) { - - double doubleRate = 83.000; - double sendAmountDouble = new Double(String.valueOf(sendAmount)); - String usIso = Currency.getInstance(new Locale("en", "US")).getCurrencyCode(); - CurrencyEntity currency = CurrencyDataSource.getInstance(app).getCurrencyByIso(usIso); - if (currency != null) { - doubleRate = currency.rate; + if (sendAmount < 1_398_000) { + return 69900; } - double usdInLTC = sendAmountDouble * doubleRate / 100_000_000.0; - usdInLTC = Math.floor(usdInLTC * 100) / 100; - - if (isBetween(usdInLTC, 0.00, 20.00)) { - double lowRate = usdInLTC * 0.01; - return (long) ((lowRate / doubleRate) * 100_000_000.0); + else if (sendAmount < 6_991_000) { + return 111_910; + } + else if (sendAmount < 27_965_000) { + return 279_700; } - else if (isBetween(usdInLTC, 20.00, 50.00)) { - return (long) ((0.30 / doubleRate) * 100_000_000.0); + else if (sendAmount < 139_820_000) { + return 699_540; } - else if (isBetween(usdInLTC, 50.00, 100.00)) { - return (long) ((1.00 / doubleRate) * 100_000_000.0); - } - else if (isBetween(usdInLTC, 100.00, 500.00)) { - return (long) ((2.00 / doubleRate) * 100_000_000.0); + else if (sendAmount < 279_653_600) { + return 1_049_300; } - else if (isBetween(usdInLTC, 500.00, 1000.00)) { - return (long) ((2.50 / doubleRate) * 100_000_000.0); + else if (sendAmount < 699_220_000) { + return 1_398_800; } - else if ( usdInLTC > 1000.00) { - return (long) ((3.00 / doubleRate) * 100_000_000.0); + else if (sendAmount < 1_398_440_000) { + return 2_797_600; } else { - return (long) ((3.00 / doubleRate) * 100_000_000.0); + return 2_797_600; } } private static boolean isBetween(double x, double lower, double upper) { diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt index 48e0750a..61a8ced4 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt @@ -8,6 +8,7 @@ sealed class SettingsEvent { val shareAnalyticsDataEnabled: Boolean = false, val lastSyncMetadata: String? = null, ) : SettingsEvent() + object OnSecurityUpdatePinClick : SettingsEvent() object OnSecuritySeedPhraseClick : SettingsEvent() object OnSecurityShareAnalyticsDataClick : SettingsEvent() @@ -20,4 +21,5 @@ sealed class SettingsEvent { object OnFiatSelectorDismiss : SettingsEvent() data class OnFiatChange(val currency: CurrencyEntity) : SettingsEvent() object OnBlockchainSyncClick : SettingsEvent() + data class OnFeeTypeChange(val feeType: String) : SettingsEvent() } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt index 60a209bd..d0336bff 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt @@ -5,6 +5,7 @@ import com.brainwallet.data.model.Fee import com.brainwallet.data.model.FeeOption import com.brainwallet.data.model.Language import com.brainwallet.data.model.toFeeOptions +import com.brainwallet.tools.manager.FeeManager data class SettingsState( val darkMode: Boolean = true, @@ -20,4 +21,5 @@ data class SettingsState( val shareAnalyticsDataEnabled: Boolean = false, val lastSyncMetadata: String? = null, val currentFeeOptions: List = Fee.Default.toFeeOptions(), + val selectedFeeType: String = FeeManager.LUXURY ) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt index 8859d395..738af4be 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt @@ -8,8 +8,10 @@ import com.brainwallet.data.model.Language import com.brainwallet.data.model.toFeeOptions import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.tools.manager.FeeManager import com.brainwallet.ui.BrainwalletViewModel import com.brainwallet.util.EventBus +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -47,6 +49,25 @@ class SettingsViewModel( AppSetting() ) + init { + viewModelScope.launch { + while (true) { + /** + * need update fee options every 4s, since we are fetching every 4s + * pls check at + * - [CurrencyUpdateWorker] + * - [LtcRepository.fetchRates] + * - [LtcRepository.fetchFeePerKb] + */ + + _state.update { + it.copy(currentFeeOptions = FeeManager.getInstance().currentFeeOptions.toFeeOptions()) + } + delay(4000) + } + } + } + override fun onEvent(event: SettingsEvent) { when (event) { is SettingsEvent.OnLoad -> viewModelScope.launch { @@ -54,7 +75,7 @@ class SettingsViewModel( it.copy( shareAnalyticsDataEnabled = event.shareAnalyticsDataEnabled, lastSyncMetadata = event.lastSyncMetadata, - currentFeeOptions = ltcRepository.fetchFeePerKb().toFeeOptions() + selectedFeeType = settingRepository.getSelectedFeeType() ) } } @@ -143,6 +164,11 @@ class SettingsViewModel( EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_SHARE_ANALYTICS_DATA_TOGGLE)) } + + is SettingsEvent.OnFeeTypeChange -> _state.update { + settingRepository.putSelectedFeeType(event.feeType) + it.copy(selectedFeeType = event.feeType) + } } } diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt index 1daa4b33..b3559014 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -135,6 +135,7 @@ fun HomeSettingDrawerSheet( .fillMaxSize() .wrapContentHeight(), selectedCurrency = state.selectedCurrency, + selectedFeeType = state.selectedFeeType, feeOptions = state.currentFeeOptions, onEvent = { viewModel.onEvent(it) diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt index 138ab31c..f964e418 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt @@ -14,10 +14,6 @@ import androidx.compose.material3.SegmentedButtonDefaults import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -26,24 +22,21 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.brainwallet.R import com.brainwallet.data.model.CurrencyEntity -import com.brainwallet.data.model.Fee import com.brainwallet.data.model.FeeOption import com.brainwallet.data.model.getFiatFormatted -import com.brainwallet.data.model.toFeeOptions -import com.brainwallet.tools.manager.FeeManager +import com.brainwallet.data.model.getSelectedIndex import com.brainwallet.ui.screens.home.SettingsEvent import com.brainwallet.ui.theme.BrainwalletTheme -import com.brainwallet.wallet.BRWalletManager //TODO @Composable fun LitecoinBlockchainDetail( modifier: Modifier = Modifier, selectedCurrency: CurrencyEntity, + selectedFeeType: String, feeOptions: List, onEvent: (SettingsEvent) -> Unit, ) { - var feeOptionsState by remember { mutableIntStateOf(2) } //2 -> index of top, since we have [low,medium,top] /// Layout values val contentHeight = 60 @@ -81,12 +74,9 @@ fun LitecoinBlockchainDetail( NetworkFeeSelector( selectedCurrency = selectedCurrency, feeOptions = feeOptions, - selectedIndex = feeOptionsState + selectedIndex = feeOptions.getSelectedIndex(selectedFeeType) ) { newSelectedIndex -> - feeOptionsState = newSelectedIndex - - //just update inside BRWalletManager.setFeePerKb - BRWalletManager.getInstance().setFeePerKb(feeOptions[newSelectedIndex].feePerKb) + onEvent.invoke(SettingsEvent.OnFeeTypeChange(feeOptions[newSelectedIndex].type)) } } diff --git a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java index 507a5125..59aaed33 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java @@ -9,6 +9,7 @@ import android.media.MediaPlayer; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.Bundle; import android.os.Handler; import android.os.NetworkOnMainThreadException; import android.os.SystemClock; @@ -334,6 +335,14 @@ public void onClick(DialogInterface dialog, int which) { */ public static void publishCallback(final String message, final int error, byte[] txHash) { Timber.d("timber: publishCallback: " + message + ", err:" + error + ", txHash: " + Arrays.toString(txHash)); + + Bundle params = new Bundle(); + params.putString("function", "BRWalletManager.publishCallback"); + params.putString("message", message); + params.putInt("error", error); + params.putString("txHash", Arrays.toString(txHash)); + AnalyticsManager.logCustomEventWithParams(BRConstants._20250517_WCINFO, params); + final Context app = BrainwalletApp.getBreadContext(); BRExecutor.getInstance().forMainThreadTasks().execute(new Runnable() { @Override @@ -440,6 +449,7 @@ public static void onTxDeleted(String hash, int notifyUser, final int recommendR final Context ctx = BrainwalletApp.getBreadContext(); if (ctx != null) { BRSharedPrefs.putScanRecommended(ctx, true); + TransactionDataSource.getInstance(ctx).deleteTxByHash(hash); } else { Timber.i("timber: onTxDeleted: Failed! ctx is null"); } @@ -513,11 +523,8 @@ public void initWallet(final Context ctx) { m.createWallet(transactionsCount, pubkeyEncoded); String firstAddress = BRWalletManager.getFirstAddress(pubkeyEncoded); BRSharedPrefs.putFirstAddress(ctx, firstAddress); - FeeManager feeManager = FeeManager.getInstance(); - if (feeManager.isLuxuryFee()) { - FeeManager.updateFeePerKb(ctx); - BRWalletManager.getInstance().setFeePerKb(feeManager.currentFeeOptions.luxury); - } + //set fee here + BRWalletManager.getInstance().setFeePerKb(FeeManager.getInstance().getCurrentFeeValue()); } if (!pm.isCreated()) { diff --git a/app/src/test/java/com/brainwallet/tools/database/DatabaseTests.kt b/app/src/test/java/com/brainwallet/tools/database/DatabaseTests.kt index 9a3a7d4f..3b8821d0 100644 --- a/app/src/test/java/com/brainwallet/tools/database/DatabaseTests.kt +++ b/app/src/test/java/com/brainwallet/tools/database/DatabaseTests.kt @@ -68,7 +68,6 @@ class DatabaseTests { // Assert.assertSame(BRConstants._20201118_DTGS,"did_tap_get_support"); // Assert.assertSame(BRConstants._20200217_DUWP,"did_unlock_with_pin"); // Assert.assertSame(BRConstants._20200217_DUWB,"did_unlock_with_biometrics"); -// Assert.assertSame(BRConstants._20200301_DUDFPK,"did_use_default_fee_per_kb"); // Assert.assertSame(BRConstants._20201121_SIL,"started_IFPS_lookup"); // Assert.assertSame(BRConstants._20201121_DRIA,"did_resolve_IPFS_address"); // Assert.assertSame(BRConstants._20201121_FRIA,"failed_resolve_IPFS_address"); diff --git a/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt b/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt index 82eabe93..5779b8df 100644 --- a/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt +++ b/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt @@ -43,7 +43,6 @@ class BRConstantsTest { assertSame(BRConstants._20201118_DTGS,"did_tap_get_support"); assertSame(BRConstants._20200217_DUWP,"did_unlock_with_pin"); assertSame(BRConstants._20200217_DUWB,"did_unlock_with_biometrics"); - assertSame(BRConstants._20200301_DUDFPK,"did_use_default_fee_per_kb"); assertSame(BRConstants._20201121_SIL,"started_IFPS_lookup"); assertSame(BRConstants._20201121_DRIA,"did_resolve_IPFS_address"); assertSame(BRConstants._20201121_FRIA,"failed_resolve_IPFS_address"); @@ -128,7 +127,6 @@ class BRConstantsTest { // Assert.assertSame(BRConstants._20201118_DTGS,"did_tap_get_support"); // Assert.assertSame(BRConstants._20200217_DUWP,"did_unlock_with_pin"); // Assert.assertSame(BRConstants._20200217_DUWB,"did_unlock_with_biometrics"); -// Assert.assertSame(BRConstants._20200301_DUDFPK,"did_use_default_fee_per_kb"); // Assert.assertSame(BRConstants._20201121_SIL,"started_IFPS_lookup"); // Assert.assertSame(BRConstants._20201121_DRIA,"did_resolve_IPFS_address"); // Assert.assertSame(BRConstants._20201121_FRIA,"failed_resolve_IPFS_address"); From c161fedb924a437b22b6b905ada4303a0ed51011 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Sun, 25 May 2025 15:48:06 +0100 Subject: [PATCH 33/65] build bump --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 290ed2dd..bfc2e94d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505191 - versionName = "v4.5.3" + versionCode = 202505251 + versionName = "v4.5.4" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") From 63d7494d3e476e60fe645523b954fd004276638a Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Mon, 26 May 2025 17:04:48 +0700 Subject: [PATCH 34/65] chore: open bread activity first then open moonpay widget (#88) --- .../com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt index 97260328..89fd9473 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt @@ -149,6 +149,8 @@ fun BuyLitecoinScreen( modifier = Modifier.align(Alignment.BottomCenter), enabled = loadingState.visible.not(), onClick = { + //open bread activity first then open moonpay widget + LegacyNavigation.restartBreadActivity(context) LegacyNavigation.showMoonPayWidget( context = context, params = mapOf( From f09eb286c60f23ad52f1400ef7f29118f27c7c99 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Thu, 29 May 2025 14:16:53 +0700 Subject: [PATCH 35/65] Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test --- .circleci/config.yml | 139 ++++++++++-- Gemfile.lock | 2 + .../flow/RecoverWalletScreenGrabsTest.kt | 205 ++++++++++++------ .../java/com/brainwallet/BrainwalletApp.kt | 4 +- .../ui/composable/PasscodeKeypad.kt | 3 +- .../home/composable/HomeSettingDrawerSheet.kt | 13 +- .../settingsrows/LockSettingRowItem.kt | 3 + .../ui/screens/home/receive/ReceiveDialog.kt | 6 +- .../ui/screens/welcome/WelcomeScreen.kt | 2 + app/src/main/res/menu/bottom_nav_menu.xml | 12 +- .../brainwallet/BrainwalletScreengrabApp.kt | 26 ++- fastlane/Fastfile | 6 +- 12 files changed, 317 insertions(+), 104 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1ad5baa3..c074e195 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,60 @@ version: 2.1 orbs: - android: circleci/android@3.0.2 + android: circleci/android@3.1.0 + ruby: circleci/ruby@2.5.3 + +# Define reusable commands +commands: + setup_environment: + description: "Sets up the basic environment for all jobs (checkout, credentials, submodules)" + steps: + - checkout + - run: + name: "Setup environment..." + command: "echo Setting up environment for brainwallet-android!" + - run: + name: "Create google-services.json from env" + command: | + mkdir -p app + echo "$GOOGLE_SERVICES_JSON" | base64 --decode > app/google-services.json + ls -la app/google-services.json + - run: + name: "create service-data.json from env" + command: | + mkdir -p app/src/main/assets + echo "$SERVICE_DATA_JSON" | base64 --decode > app/src/main/assets/service-data.json + ls -la app/src/main/assets/service-data.json + - run: + name: "Create keystore files from env" + command: | + echo "$DEBUG_STORE_FILE" | base64 --decode > debug.keystore + echo "$RELEASE_STORE_FILE" | base64 --decode > release.keystore + ls -la *.keystore + - run: + name: "Create local.properties file" + command: | + cat > local.properties \<< EOL + #adjust with your location + DEBUG_STORE_FILE=${CIRCLE_WORKING_DIRECTORY}/debug.keystore + DEBUG_STORE_PASSWORD=${DEBUG_STORE_PASSWORD} + DEBUG_KEY_ALIAS=${DEBUG_KEY_ALIAS} + DEBUG_KEY_PASSWORD=${DEBUG_KEY_PASSWORD} + + #adjust with your location + RELEASE_STORE_FILE=${CIRCLE_WORKING_DIRECTORY}/release.keystore + RELEASE_STORE_PASSWORD=${RELEASE_STORE_PASSWORD} + RELEASE_KEY_ALIAS=${RELEASE_KEY_ALIAS} + RELEASE_KEY_PASSWORD=${RELEASE_KEY_PASSWORD} + + # screengrab paperkey + SCREENGRAB_PAPERKEY=${SCREENGRAB_PAPERKEY} + EOL + ls && cat local.properties + - run: + name: "Initialize submodule" + command: "git submodule init && git submodule update --init --recursive" + - android/restore_gradle_cache # Define a job to be invoked later in a workflow. # See: https://circleci.com/docs/2.0/configuration-reference/#jobs @@ -14,23 +67,7 @@ jobs: resource_class: large tag: 2024.07.1-ndk steps: - - checkout - - run: - name: "brainwallet-android unit test setup..." - command: "echo Building tests for brainwallet-android! && ls" - - run: - name: "Default for gradle.properties" - command: "echo \"RELEASE_STORE_FILE=/\nRELEASE_STORE_PASSWORD=\nRELEASE_KEY_ALIAS=\nRELEASE_KEY_PASSWORD=\nandroid.useAndroidX=true\nandroid.enableJetifier=true\" >> gradle.properties && ls && cat gradle.properties" - - run: - name: "Initialize submodule" - command: "git submodule init && git submodule update --init --recursive" - - run: - name: "Export google-services.json to env" - command: echo 'export $GOOGLE_SERVICES_JSON="$GOOGLE_SERVICES_JSON"' >> $BASH_ENV - - run: - name: "decode $GOOGLE_SERVICES_JSON to google-services.json" - command: echo "$GOOGLE_SERVICES_JSON" | base64 --decode > app/google-services.json - - android/restore_gradle_cache + - setup_environment - run: name: "Execute Unit Test" command: ./gradlew testBrainwalletDebugUnitTest @@ -46,6 +83,57 @@ jobs: - store_artifacts: path: ~/test-results/junit + screengrab: + executor: + name: android/android_machine + resource_class: large + tag: default + steps: + - setup_environment + - ruby/install: + version: '3.2.0' + - ruby/install-deps + - run: + name: "Install fastlane" + command: | + gem install bundler + bundle install + - android/create_avd: + avd_name: bw_avd + install: true + system_image: system-images;android-34;google_apis;x86_64 + additional_args: '-d "pixel_7_pro"' + - android/start_emulator: + avd_name: bw_avd + no_window: true + memory: 4096 + delay_adb: true + run_logcat: true + # additional_args: "-skin 1080x1920 -memory 2048" + post_emulator_launch_assemble_command: | + # bundle exec fastlane android build_and_screengrab + echo "skipping assemble command, as we only need the emulator running for screengrab" + - run: + name: "Wait for emulator to boot and set PIN" + command: | + echo "Waiting for emulator to boot..." + timeout 300 sh -c 'until adb shell getprop sys.boot_completed | grep -m 1 "1"; do sleep 5; done' + echo "Emulator is ready!" + adb shell svc power stayon true + adb shell locksettings set-pin 123456 + adb shell input keyevent 82 + sleep 5 + - run: + name: "Run Screengrab" + command: | + bundle exec fastlane android build_and_screengrab + - run: + name: "List fastlane android contents" + command: ls -R fastlane/android/ + - android/save_gradle_cache + - store_artifacts: + path: fastlane/metadata/android/ + destination: android-screenshots # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows @@ -53,3 +141,18 @@ workflows: test-and-build: jobs: - unit-test +# - screengrab: +# requires: +# - unit-test + + # Daily scheduled screengrab workflow + # daily-screengrab: + # triggers: + # - schedule: + # cron: "0 0 * * *" # Run at midnight UTC every day + # filters: + # branches: + # only: + # - develop # Adjust to your main branch name + # jobs: + # - screengrab diff --git a/Gemfile.lock b/Gemfile.lock index f322ed56..03d4f21e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -214,6 +214,8 @@ GEM PLATFORMS arm64-darwin-23 arm64-darwin-24 + x86-linux + x86_64-linux DEPENDENCIES fastlane diff --git a/app/src/androidTest/kotlin/flow/RecoverWalletScreenGrabsTest.kt b/app/src/androidTest/kotlin/flow/RecoverWalletScreenGrabsTest.kt index 30060516..56e381e6 100644 --- a/app/src/androidTest/kotlin/flow/RecoverWalletScreenGrabsTest.kt +++ b/app/src/androidTest/kotlin/flow/RecoverWalletScreenGrabsTest.kt @@ -1,33 +1,46 @@ package flow import android.Manifest +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onChild import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performScrollTo +import androidx.compose.ui.test.performScrollToNode import androidx.compose.ui.test.performTextInput import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.filters.LargeTest import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.GrantPermissionRule import androidx.test.uiautomator.UiDevice -import com.brainwallet.BuildConfig import com.brainwallet.R +import com.brainwallet.test.BuildConfig import com.brainwallet.ui.BrainwalletActivity +import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import timber.log.Timber import tools.fastlane.screengrab.FalconScreenshotStrategy import tools.fastlane.screengrab.Screengrab +import tools.fastlane.screengrab.cleanstatusbar.BluetoothState +import tools.fastlane.screengrab.cleanstatusbar.CleanStatusBar +import tools.fastlane.screengrab.cleanstatusbar.IconVisibility +import tools.fastlane.screengrab.cleanstatusbar.MobileDataType import tools.fastlane.screengrab.locale.LocaleTestRule /** * TODO: revisit this, since breaking with new navigation + * + * this will require pixel 7 pro */ @RunWith(JUnit4::class) @LargeTest @@ -47,23 +60,47 @@ class RecoverWalletScreenGrabsTest { @get:Rule val composeTestRule = createAndroidComposeRule() + private val uiDevice + get() = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + @Before + fun setUp() { + CleanStatusBar() + .setBluetoothState(BluetoothState.DISCONNECTED) + .setMobileNetworkDataType(MobileDataType.LTE) + .setWifiVisibility(IconVisibility.HIDE) + .setShowNotifications(false) + .setClock("0900") + .setBatteryLevel(100) + .enable() + } + + @After + fun tearDown() { + CleanStatusBar.disable() + } + + + @OptIn(ExperimentalTestApi::class) @Test fun onRecoverFlowSuccess() { + composeTestRule.activityRule.scenario.onActivity { Screengrab.setDefaultScreenshotStrategy(FalconScreenshotStrategy(it)) } - val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + waitUntilReady() - Screengrab.screenshot("1_intro_screen") + uiDevice.waitForIdle(60_000) + composeTestRule.waitForIdle() - onView(withId(R.id.button_recover_wallet)).perform(click()) + Screengrab.screenshot("1_welcome_screen") - Screengrab.screenshot("2_recover_screen") + composeTestRule.onNode(hasTestTag("buttonRestore")).performClick() - onView(withId(R.id.send_button)).perform(click()) //actually next button + uiDevice.waitForIdle() - Screengrab.screenshot("3_input_paperkey_screen") + Screengrab.screenshot("2_input_words_screen") //seed words input val editTextTags = (0..11).map { index -> "textFieldSeedWord$index" } @@ -71,123 +108,159 @@ class RecoverWalletScreenGrabsTest { val paperKey = BuildConfig.SCREENGRAB_PAPERKEY editTextTags.zip(paperKey).forEachIndexed { index, (textFieldTag, value) -> - device.waitForIdle(100) + uiDevice.waitForIdle() val textForTyping = value.dropLast(1) composeTestRule.onNodeWithTag(textFieldTag).onChild().performTextInput(textForTyping) composeTestRule.onNodeWithText(value).performClick() - } - composeTestRule.onNodeWithTag("buttonRestore").performClick() + Screengrab.screenshot("3_input_words_screen_2") - device.waitForIdle(300) + composeTestRule.onNodeWithTag("buttonRestore").performScrollTo() + composeTestRule.onNodeWithTag("buttonRestore").assertExists() + composeTestRule.onNodeWithTag("buttonRestore").performClick() - Screengrab.screenshot("4_input_paperkey_screen_2") + uiDevice.waitForIdle() - Screengrab.screenshot("5_setpin_screen") + composeTestRule.waitUntilAtLeastOneExists(hasTestTag("keypad1")) - repeat(6) { - onView(withId(R.id.num1)).perform(click()) + repeat(4) { + uiDevice.waitForIdle() + composeTestRule.onNodeWithTag("keypad1").assertExists() + composeTestRule.onNodeWithTag("keypad1").performClick() } - Screengrab.screenshot("6_setpin_confirm_screen") + Screengrab.screenshot("4_set_passcode_screen") - repeat(6) { - onView(withId(R.id.num1)).perform(click()) - } + composeTestRule.waitUntilAtLeastOneExists(hasTestTag("keypad1")) - device.waitForIdle(3000) + repeat(4) { + uiDevice.waitForIdle() + composeTestRule.onNodeWithTag("keypad1").assertExists() + composeTestRule.onNodeWithTag("keypad1").performClick() + } - Screengrab.screenshot("7_main_screen") + Screengrab.screenshot("5_set_passcode_confirm_screen") - onView(withId(R.id.menuBut)).perform(click()) + uiDevice.waitForIdle() - Screengrab.screenshot("8_menu_bottom_sheet") + Thread.sleep(1000) - onView(withText(R.string.MenuButton_security)).perform(click()) + Screengrab.screenshot("6_main_screen") - Screengrab.screenshot("9_security_center_screen") + //setting drawer + onView(withId(R.id.menuBut)).perform(click()) - onView(withId(R.id.close_button)).perform(click()) + Screengrab.screenshot("7_setting_drawer_open") - onView(withId(R.id.menuBut)).perform(click()) + composeTestRule.onNodeWithTag("settingSecurity").assertExists() + composeTestRule.onNodeWithTag("settingSecurity").performClick() - onView(withText(R.string.MenuButton_settings)).perform(click()) + composeTestRule.waitForIdle() - Screengrab.screenshot("10_settings_screen") + Screengrab.screenshot("8_setting_drawer_open_security") - onView(withText(R.string.settings_show_seed)).perform(click()) + composeTestRule.waitForIdle() - onView(withId(R.id.show_seed_button)).perform(click()) + composeTestRule.onNodeWithTag("settingLanguage").assertExists() + composeTestRule.onNodeWithTag("settingLanguage").performClick() - Screengrab.screenshot("11_settings_seed_phrase") + composeTestRule.waitForIdle() - device.pressBack() + Screengrab.screenshot("9_setting_drawer_open_language") - onView(withText(R.string.Settings_wipe)).perform(click()) + composeTestRule.waitForIdle() - Screengrab.screenshot("12_settings_recover_another_wallet") + composeTestRule.onNodeWithTag("settingCurrency").assertExists() + composeTestRule.onNodeWithTag("settingCurrency").performClick() - onView(withId(R.id.close_button)).perform(click()) + composeTestRule.waitForIdle() - onView(withText(R.string.Settings_languages)).perform(click()) + Screengrab.screenshot("10_setting_drawer_open_currency") - Screengrab.screenshot("13_settings_language") + composeTestRule.waitForIdle() - device.pressBack() + composeTestRule.onNodeWithTag("settingGames").assertExists() + composeTestRule.onNodeWithTag("settingGames").performClick() - onView(withText(R.string.Settings_currency)).perform(click()) + composeTestRule.waitForIdle() - Screengrab.screenshot("14_settings_currency") + Screengrab.screenshot("11_setting_drawer_open_games") - device.pressBack() + composeTestRule.waitForIdle() - onView(withText(R.string.Settings_sync)).perform(click()) + composeTestRule.onNodeWithTag("lazyColumnSetting").performScrollToNode(hasTestTag("settingBlockchain")) + composeTestRule.onNodeWithTag("settingBlockchain").assertExists() + composeTestRule.onNodeWithTag("settingBlockchain").performClick() - Screengrab.screenshot("15_settings_sync") + composeTestRule.waitForIdle() - device.pressBack() + Screengrab.screenshot("12_setting_drawer_open_blockchain") - onView(withText(R.string.Settings_shareData)).perform(click()) + composeTestRule.waitForIdle() - Screengrab.screenshot("16_settings_share_anonymous_data") + composeTestRule.onNodeWithTag("lazyColumnSetting").performScrollToNode(hasTestTag("settingLock")) + composeTestRule.onNodeWithTag("settingLock").assertExists() + composeTestRule.onNodeWithTag("settingLock").performClick() - device.pressBack() + composeTestRule.waitForIdle() - onView(withText(R.string.Settings_about)).perform(click()) + Screengrab.screenshot("13_setting_drawer_lock") - Screengrab.screenshot("17_settings_about") + repeat(4) { + uiDevice.waitForIdle() + composeTestRule.onNodeWithTag("keypad1").assertExists() + composeTestRule.onNodeWithTag("keypad1").performClick() + } - device.pressBack() + uiDevice.waitForIdle() + Thread.sleep(1000) - device.pressBack() + //tx send ui onView(withId(R.id.nav_send)).perform(click()) onView(withId(R.id.amount_edit)).perform(click()) - Screengrab.screenshot("18_transaction_send") + Screengrab.screenshot("14_transaction_send") onView(withId(R.id.close_button)).perform(click()) - onView(withId(R.id.nav_receive)).perform(click()) - - Screengrab.screenshot("19_transaction_receive") - onView(withId(R.id.close_button)).perform(click()) - - onView(withId(R.id.nav_buy)).perform(click()) - - Screengrab.screenshot("20_transaction_buy") + //tx buy/receive ui + onView(withId(R.id.nav_receive)).perform(click()) - onView(withId(R.id.nav_history)).perform(click()) + Screengrab.screenshot("15_transaction_buy_receive") - onView(withId(R.id.menuBut)).perform(click()) + composeTestRule.onNodeWithTag("buttonClose").performClick() - onView(withText(R.string.MenuButton_lock)).perform(click()) + uiDevice.waitForIdle() - Screengrab.screenshot("21_lock_screen") + } + private fun waitUntilReady() { + var attempts = 0 + val maxAttempts = 5 + + while (attempts < maxAttempts) { + try { + composeTestRule.waitUntil(timeoutMillis = 60_000) { + try { + composeTestRule.onRoot().fetchSemanticsNode() + true + } catch (e: Exception) { + Timber.e("[waitForComposeHierarchy] Error1 : ${e.message}", e) + false + } + } + return + } catch (e: Exception) { + Timber.e("[waitForComposeHierarchy] Error2 : ${e.message}", e) + attempts++ + if (attempts >= maxAttempts) throw e + Thread.sleep(1000) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/BrainwalletApp.kt b/app/src/main/java/com/brainwallet/BrainwalletApp.kt index 237bf5a1..03fd029e 100644 --- a/app/src/main/java/com/brainwallet/BrainwalletApp.kt +++ b/app/src/main/java/com/brainwallet/BrainwalletApp.kt @@ -31,7 +31,7 @@ import java.util.Timer import java.util.TimerTask import java.util.concurrent.atomic.AtomicInteger -class BrainwalletApp : Application() { +open class BrainwalletApp : Application() { override fun onCreate() { super.onCreate() @@ -73,7 +73,7 @@ class BrainwalletApp : Application() { appsFlyerLib.start(this) } - protected fun initializeModule() { + protected open fun initializeModule() { startKoin { androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.ERROR) androidContext(this@BrainwalletApp) diff --git a/app/src/main/java/com/brainwallet/ui/composable/PasscodeKeypad.kt b/app/src/main/java/com/brainwallet/ui/composable/PasscodeKeypad.kt index 4fac2149..a0607cbc 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/PasscodeKeypad.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/PasscodeKeypad.kt @@ -17,6 +17,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp @Composable @@ -34,7 +35,7 @@ fun PasscodeKeypad( repeat(9) { index -> val number = index + 1 CircleButton( - modifier = modifierCircleButton, + modifier = modifierCircleButton.testTag("keypad$number"), onClick = { onEvent.invoke(PasscodeKeypadEvent.OnPressed(number)) }, diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt index b3559014..d96cda42 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.AbstractComposeView import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.coroutineScope @@ -76,6 +77,7 @@ fun HomeSettingDrawerSheet( ) { LazyColumn( modifier = Modifier + .testTag("lazyColumnSetting") .weight(1f) .padding(top = headerPadding.dp) .wrapContentHeight(align = Alignment.Top) @@ -83,6 +85,7 @@ fun HomeSettingDrawerSheet( item { SecurityDetail( modifier = Modifier + .testTag("settingSecurity") .fillMaxSize() .wrapContentHeight(), shareAnalyticsDataEnabled = state.shareAnalyticsDataEnabled, @@ -94,6 +97,7 @@ fun HomeSettingDrawerSheet( item { LanguageDetail( modifier = Modifier + .testTag("settingLanguage") .fillMaxSize() .wrapContentHeight(), selectedLanguage = state.selectedLanguage, @@ -110,6 +114,7 @@ fun HomeSettingDrawerSheet( item { CurrencyDetail( modifier = Modifier + .testTag("settingCurrency") .fillMaxSize() .wrapContentHeight(), selectedCurrency = state.selectedCurrency, @@ -125,6 +130,7 @@ fun HomeSettingDrawerSheet( item { GamesDetail( modifier = Modifier + .testTag("settingGames") .fillMaxSize() .wrapContentHeight() ) @@ -132,6 +138,7 @@ fun HomeSettingDrawerSheet( item { LitecoinBlockchainDetail( modifier = Modifier + .testTag("settingBlockchain") .fillMaxSize() .wrapContentHeight(), selectedCurrency = state.selectedCurrency, @@ -144,6 +151,7 @@ fun HomeSettingDrawerSheet( } item { SettingRowItem( + modifier = Modifier.testTag("settingSupport"), title = stringResource(R.string.settings_title_support), description = "brainwallet.co/support.html", onClick = { @@ -155,6 +163,7 @@ fun HomeSettingDrawerSheet( } item { SettingRowItem( + modifier = Modifier.testTag("settingSocialMedia"), title = stringResource(R.string.settings_title_social_media), description = "linktr.ee/brainwallet", onClick = { @@ -166,7 +175,9 @@ fun HomeSettingDrawerSheet( } item { // Lock / Unlock - LockSettingRowItem { + LockSettingRowItem( + modifier = Modifier.testTag("settingLock"), + ) { viewModel.onEvent(SettingsEvent.OnToggleLock) } } diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt index 8f0ab2eb..871b466f 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt @@ -4,14 +4,17 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Lock import androidx.compose.material3.Icon import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import com.brainwallet.R @Composable fun LockSettingRowItem( + modifier: Modifier = Modifier, onClick: () -> Unit, ) { SettingRowItem( + modifier = modifier, title = stringResource(R.string.settings_title_lock), onClick = onClick ) { diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt index 291015e2..8292904c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt @@ -52,6 +52,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType @@ -152,7 +153,10 @@ fun ReceiveDialog( } }, actions = { - IconButton(onClick = onDismissRequest) { + IconButton( + modifier = Modifier.testTag("buttonClose"), + onClick = onDismissRequest + ) { Icon( Icons.Default.Close, contentDescription = stringResource(R.string.AccessibilityLabels_close), diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index f4d8ba3a..b0370f4b 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -202,6 +203,7 @@ fun WelcomeScreen( }, shape = RoundedCornerShape(50), modifier = Modifier + .testTag("buttonRestore") .padding(horizontal = leadTrailPadding.dp) .padding(vertical = rowPadding.dp) .height(activeRowHeight.dp) diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index dc0df45e..947c8a79 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -1,18 +1,18 @@ - - + + Date: Thu, 29 May 2025 15:45:24 +0700 Subject: [PATCH 36/65] fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated --- .../ui/screens/welcome/WelcomeScreen.kt | 212 +++++++++--------- 1 file changed, 110 insertions(+), 102 deletions(-) diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index b0370f4b..f7c32e61 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -3,6 +3,7 @@ package com.brainwallet.ui.screens.welcome import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -10,10 +11,12 @@ import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Card +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -26,6 +29,7 @@ import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -61,7 +65,8 @@ fun WelcomeScreen( val configuration = LocalConfiguration.current val screenHeight = configuration.screenHeightDp - var mainBoxFactor = 0.5 + val density = LocalDensity.current.density + val mainBoxFactor = if (density > 2) 0.5 else 0.4 val thirdOfScreenHeight = (screenHeight * mainBoxFactor).toInt() LaunchedEffect(Unit) { @@ -73,11 +78,11 @@ fun WelcomeScreen( val buttonFontSize = 24 val thinButtonFontSize = 22 val toggleButtonSize = 45 - val leadTrailPadding = 18 + val leadTrailPadding = 8 val halfLeadTrailPadding = leadTrailPadding / 2 val doubleLeadTrailPadding = leadTrailPadding * 2 val rowPadding = 8 - val versionPadding = 12 + val versionPadding = 8 val activeRowHeight = 58 val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.welcomeemoji20250212)) @@ -86,16 +91,12 @@ fun WelcomeScreen( iterations = LottieConstants.IterateForever ) - Column( + Box( modifier = Modifier .fillMaxSize() - .background(BrainwalletTheme.colors.surface), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.SpaceBetween + .background(BrainwalletTheme.colors.surface) + .verticalScroll(rememberScrollState()), ) { - - Spacer(modifier = Modifier.weight(0.2f)) - Image( painterResource(R.drawable.brainwallet_logotype_white), contentDescription = "brainwallet_logotype_white", @@ -104,124 +105,131 @@ fun WelcomeScreen( BrainwalletTheme.colors.content, ), modifier = Modifier + .align(Alignment.TopCenter) .fillMaxWidth() .padding(doubleLeadTrailPadding.dp) ) // Animation Placeholder - Card( + LottieAnimation( modifier = Modifier + .offset(y = 120.dp) .fillMaxWidth() - .height(thirdOfScreenHeight.dp) .padding(leadTrailPadding.dp) - ) { - - LottieAnimation( - modifier = Modifier.background(BrainwalletTheme.colors.surface), - composition = composition, - contentScale = ContentScale.Fit, - progress = { progress } - ) - } - // TODO: implement later, for now just comment this - Row( - modifier = Modifier - .fillMaxWidth() - .height(activeRowHeight.dp) - .padding(horizontal = leadTrailPadding.dp) - .padding(vertical = rowPadding.dp), - horizontalArrangement = Arrangement.SpaceEvenly + .background( + BrainwalletTheme.colors.surface, + BrainwalletTheme.shapes.large + ) + .height(thirdOfScreenHeight.dp) + .clip(BrainwalletTheme.shapes.large), + composition = composition, + contentScale = ContentScale.FillWidth, + alignment = Alignment.Center, + progress = { progress } + ) + Column( + modifier = Modifier.align(Alignment.BottomCenter), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) ) { - - BrainwalletButton( + Row( modifier = Modifier - .weight(1f) - .fillMaxWidth(), - onClick = { - viewModel.onEvent(WelcomeEvent.OnLanguageSelectorButtonClick) - } + .fillMaxWidth() + .height(activeRowHeight.dp) + .padding(horizontal = leadTrailPadding.dp) + .padding(vertical = rowPadding.dp), + horizontalArrangement = Arrangement.SpaceEvenly + ) { - Text( - text = state.selectedLanguage.title, - fontSize = 14.sp, - color = BrainwalletTheme.colors.content + + BrainwalletButton( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + onClick = { + viewModel.onEvent(WelcomeEvent.OnLanguageSelectorButtonClick) + } + ) { + Text( + text = state.selectedLanguage.title, + fontSize = 14.sp, + color = BrainwalletTheme.colors.content + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + DarkModeToggleButton( + modifier = Modifier + .width(toggleButtonSize.dp) + .aspectRatio(1f), + checked = state.darkMode, + onCheckedChange = { + viewModel.onEvent(WelcomeEvent.OnToggleDarkMode) + } ) - } - Spacer(modifier = Modifier.weight(0.1f)) + Spacer(modifier = Modifier.weight(0.1f)) - DarkModeToggleButton( - modifier = Modifier - .width(toggleButtonSize.dp) - .aspectRatio(1f), - checked = state.darkMode, - onCheckedChange = { - viewModel.onEvent(WelcomeEvent.OnToggleDarkMode) + BrainwalletButton( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + onClick = { viewModel.onEvent(WelcomeEvent.OnFiatButtonClick) } + ) { + Text( + text = state.selectedCurrency.name, + fontSize = 14.sp, + color = BrainwalletTheme.colors.content + ) } - ) - - Spacer(modifier = Modifier.weight(0.1f)) - BrainwalletButton( + } + // Ready Button + BorderedLargeButton( + onClick = { + onNavigate.invoke(UiEffect.Navigate(Route.Ready)) + }, + shape = RoundedCornerShape(50), modifier = Modifier - .weight(1f) - .fillMaxWidth(), - onClick = { viewModel.onEvent(WelcomeEvent.OnFiatButtonClick) } + .padding(horizontal = leadTrailPadding.dp) + .height(activeRowHeight.dp) + ) { Text( - text = state.selectedCurrency.name, - fontSize = 14.sp, - color = BrainwalletTheme.colors.content + text = stringResource(R.string.ready), + fontSize = buttonFontSize.sp, + fontWeight = FontWeight.SemiBold, ) } - } - // Ready Button - BorderedLargeButton( - onClick = { - onNavigate.invoke(UiEffect.Navigate(Route.Ready)) - }, - shape = RoundedCornerShape(50), - modifier = Modifier - .padding(horizontal = leadTrailPadding.dp) - .padding(vertical = rowPadding.dp) - .height(activeRowHeight.dp) - - ) { - Text( - text = stringResource(R.string.ready), - fontSize = buttonFontSize.sp, - fontWeight = FontWeight.SemiBold, - ) - } + // Restore Button + BorderedLargeButton( + onClick = { + onNavigate.invoke(UiEffect.Navigate(Route.InputWords())) + }, + shape = RoundedCornerShape(50), + modifier = Modifier + .testTag("buttonRestore") + .padding(horizontal = leadTrailPadding.dp) + .height(activeRowHeight.dp) + .clip(RoundedCornerShape(50)) + ) { + Text( + text = stringResource(R.string.restore), + fontSize = thinButtonFontSize.sp, + fontWeight = FontWeight.Thin, + ) + } - // Restore Button - BorderedLargeButton( - onClick = { - onNavigate.invoke(UiEffect.Navigate(Route.InputWords())) - }, - shape = RoundedCornerShape(50), - modifier = Modifier - .testTag("buttonRestore") - .padding(horizontal = leadTrailPadding.dp) - .padding(vertical = rowPadding.dp) - .height(activeRowHeight.dp) - .clip(RoundedCornerShape(50)) - ) { Text( - text = stringResource(R.string.restore), - fontSize = thinButtonFontSize.sp, - fontWeight = FontWeight.Thin, + modifier = Modifier.padding(vertical = versionPadding.dp), + text = BRConstants.APP_VERSION_NAME_CODE, + fontSize = 13.sp, + color = BrainwalletTheme.colors.content ) } - - Text( modifier = Modifier - .padding(vertical = versionPadding.dp), - text = BRConstants.APP_VERSION_NAME_CODE, - fontSize = 13.sp, - color = BrainwalletTheme.colors.content - ) } //language selector From a9c4a63d604a8c7e6252757766a7c26168fd5db5 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Thu, 29 May 2025 17:35:10 +0700 Subject: [PATCH 37/65] fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout --- .../brainwallet/ui/composable/SeedWordItem.kt | 18 ++-- .../ui/composable/SeedWordsLayout.kt | 27 ++++++ .../yourseedproveit/YourSeedProveItScreen.kt | 83 ++++++++----------- .../yourseedwords/YourSeedWordsScreen.kt | 31 +++---- app/src/main/res/values/strings.xml | 1 + 5 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/ui/composable/SeedWordsLayout.kt diff --git a/app/src/main/java/com/brainwallet/ui/composable/SeedWordItem.kt b/app/src/main/java/com/brainwallet/ui/composable/SeedWordItem.kt index 040457fd..202f21f8 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/SeedWordItem.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/SeedWordItem.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -22,7 +21,6 @@ import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.Typography import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -32,18 +30,12 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.PopupProperties -import com.brainwallet.ui.screens.welcome.WelcomeScreen import com.brainwallet.ui.theme.BrainwalletTheme import com.brainwallet.ui.theme.chilli @@ -56,10 +48,14 @@ fun SeedWordItem( ) { SeedWordItemBox(modifier = modifier) { Text( - modifier = Modifier.padding(vertical = 12.dp), + modifier = Modifier + .padding(vertical = 12.dp) + .weight(1f), text = label, style = MaterialTheme.typography.bodyMedium, - color = if (isError) chilli else BrainwalletTheme.colors.content + color = if (isError) chilli else BrainwalletTheme.colors.content, + overflow = TextOverflow.Ellipsis, + maxLines = 1 ) trailingIcon?.let { icon -> Spacer(modifier = Modifier.width(8.dp)) diff --git a/app/src/main/java/com/brainwallet/ui/composable/SeedWordsLayout.kt b/app/src/main/java/com/brainwallet/ui/composable/SeedWordsLayout.kt new file mode 100644 index 00000000..a8f3d98c --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/SeedWordsLayout.kt @@ -0,0 +1,27 @@ +package com.brainwallet.ui.composable + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridScope +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SeedWordsLayout( + modifier: Modifier = Modifier, + content: LazyGridScope.() -> Unit +) { + LazyVerticalGrid( + modifier = modifier + .height(220.dp), + columns = GridCells.Fixed(3), //fixed 3 + contentPadding = PaddingValues(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt index 171186ab..214982a7 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt @@ -9,27 +9,24 @@ import android.content.ClipData import android.content.ClipDescription import android.media.MediaPlayer import android.view.View -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.draganddrop.dragAndDropSource import androidx.compose.foundation.draganddrop.dragAndDropTarget import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Clear import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -60,6 +57,7 @@ import com.brainwallet.ui.composable.BrainwalletScaffold import com.brainwallet.ui.composable.BrainwalletTopAppBar import com.brainwallet.ui.composable.LargeButton import com.brainwallet.ui.composable.SeedWordItem +import com.brainwallet.ui.composable.SeedWordsLayout import org.koin.compose.koinInject @Composable @@ -72,7 +70,7 @@ fun YourSeedProveItScreen( val context = LocalContext.current /// Layout values - val columnPadding = 18 + val columnPadding = 12 val horizontalVerticalSpacing = 8 val spacerHeight = 48 val maxItemsPerRow = 3 @@ -104,23 +102,12 @@ fun YourSeedProveItScreen( } }) }, - floatingActionButton = { - if (state.orderCorrected.not()) { - FloatingActionButton( - onClick = { - viewModel.onEvent(YourSeedProveItEvent.OnClear) - } - ) { - Icon(Icons.Default.Clear, contentDescription = null) - } - } - } ) { paddingValues -> Column( modifier = Modifier + .fillMaxSize() .padding(paddingValues) .padding(columnPadding.dp) - .fillMaxSize() .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), @@ -138,17 +125,10 @@ fun YourSeedProveItScreen( ) ) - Spacer(modifier = Modifier.height(spacerHeight.dp)) - - FlowRow( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - maxItemsInEachRow = maxItemsPerRow - ) { - state.correctSeedWords.values.forEachIndexed { index, (expectedWord, actualWord) -> + Spacer(modifier = Modifier.weight(0.1f)) + SeedWordsLayout { + itemsIndexed(items = state.correctSeedWords.values.toList()) { index: Int, (expectedWord, actualWord): SeedWordItem -> val label = if (expectedWord != actualWord && actualWord.isEmpty()) { "${index + 1}" } else { @@ -158,7 +138,6 @@ fun YourSeedProveItScreen( SeedWordItem( modifier = Modifier .fillMaxWidth() - .weight(1f) .dragAndDropTarget( shouldStartDragAndDrop = { event -> event @@ -195,17 +174,20 @@ fun YourSeedProveItScreen( Spacer(modifier = Modifier.weight(1f)) - AnimatedVisibility(visible = state.orderCorrected.not()) { - FlowRow( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - maxItemsInEachRow = maxItemsPerRow - ) { - state.shuffledSeedWords.forEachIndexed { index, word -> + SeedWordsLayout { + itemsIndexed(items = state.shuffledSeedWords) { index, word -> + + val isWordUsedCorrectly = + state.correctSeedWords.values.any { (expectedWord, actualWord) -> + expectedWord == word && actualWord == word + } + + if (isWordUsedCorrectly) { + Box(modifier = Modifier.fillMaxWidth()) + } else { SeedWordItem( modifier = Modifier + .fillMaxWidth() .dragAndDropSource { detectTapGestures( onLongPress = { @@ -230,20 +212,25 @@ fun YourSeedProveItScreen( } ) } + + } } - AnimatedVisibility(visible = state.orderCorrected) { - LargeButton( - onClick = { + + LargeButton( + onClick = { + if (state.orderCorrected) { onNavigate.invoke(UiEffect.Navigate(Route.TopUp)) - }, - ) { - Text( - text = stringResource(R.string.game_and_sync), - style = MaterialTheme.typography.labelLarge - ) - } + } else { + viewModel.onEvent(YourSeedProveItEvent.OnClear) + } + }, + ) { + Text( + text = stringResource(if (state.orderCorrected) R.string.game_and_sync else R.string.reset_start_over).uppercase(), + style = MaterialTheme.typography.labelLarge + ) } } diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt index c541f588..17bdaf18 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsScreen.kt @@ -5,12 +5,11 @@ package com.brainwallet.ui.screens.yourseedwords import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -36,6 +35,7 @@ import com.brainwallet.ui.composable.BrainwalletScaffold import com.brainwallet.ui.composable.BrainwalletTopAppBar import com.brainwallet.ui.composable.LargeButton import com.brainwallet.ui.composable.SeedWordItem +import com.brainwallet.ui.composable.SeedWordsLayout import org.koin.compose.koinInject @Composable @@ -45,12 +45,11 @@ fun YourSeedWordsScreen( viewModel: YourSeedWordsViewModel = koinInject() ) { /// Layout values - val columnPadding = 16 + val columnPadding = 12 val horizontalVerticalSpacing = 8 - val spacerHeight = 48 - val maxItemsPerRow = 3 - val leadingCopyPadding = 16 - val detailLineHeight = 28 + val spacerHeight = 36 + val leadingCopyPadding = 8 + val detailLineHeight = 24 LaunchedEffect(Unit) { viewModel.uiEffect.collect { effect -> @@ -78,9 +77,9 @@ fun YourSeedWordsScreen( ) { paddingValues -> Column( modifier = Modifier + .fillMaxSize() .padding(paddingValues) .padding(columnPadding.dp) - .fillMaxSize() .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), @@ -102,16 +101,10 @@ fun YourSeedWordsScreen( ) ) - Spacer(modifier = Modifier.height(spacerHeight.dp)) + Spacer(modifier = Modifier.weight(0.1f)) - FlowRow( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - maxItemsInEachRow = maxItemsPerRow - ) { - seedWords.forEachIndexed { index, word -> + SeedWordsLayout(modifier = Modifier.weight(1f)) { + itemsIndexed(items = seedWords) { index, word -> SeedWordItem( modifier = Modifier .fillMaxWidth() @@ -121,14 +114,14 @@ fun YourSeedWordsScreen( } } - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(0.1f)) Text( text = stringResource(R.string.blockchain_litecoin), style = MaterialTheme.typography.bodyMedium.copy(textAlign = TextAlign.Center) ) - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(0.2f)) LargeButton( onClick = { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f7c7deb0..12fca16d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -855,4 +855,5 @@ Buy / Receive Custom + Reset / Start Over From d8f08adf506c7166f1c930dc7c9da923c3e714d3 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Thu, 29 May 2025 04:29:26 -0700 Subject: [PATCH 38/65] tiny resizing (#94) --- .../java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index f7c32e61..845a9073 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -79,8 +79,6 @@ fun WelcomeScreen( val thinButtonFontSize = 22 val toggleButtonSize = 45 val leadTrailPadding = 8 - val halfLeadTrailPadding = leadTrailPadding / 2 - val doubleLeadTrailPadding = leadTrailPadding * 2 val rowPadding = 8 val versionPadding = 8 val activeRowHeight = 58 @@ -107,7 +105,8 @@ fun WelcomeScreen( modifier = Modifier .align(Alignment.TopCenter) .fillMaxWidth() - .padding(doubleLeadTrailPadding.dp) + .padding(horizontal = 55.dp) + .padding(vertical = 30.dp) ) // Animation Placeholder From ef935858b84faa6723120b009b0f7b58128c8a62 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Thu, 29 May 2025 12:32:00 +0100 Subject: [PATCH 39/65] code and version bump --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bfc2e94d..08429835 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505251 - versionName = "v4.5.4" + versionCode = 202505291 + versionName = "v4.5.5" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") From 174d612e80724d5d4c1cc6f9bb03c8752ef39b72 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Fri, 30 May 2025 14:14:02 -0700 Subject: [PATCH 40/65] change break (#97) adds a android user agent and externalID --- .../main/java/com/brainwallet/navigation/LegacyNavigation.kt | 5 ++++- app/src/main/java/com/brainwallet/tools/util/Utils.java | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index d38eaeb9..08bb8258 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -12,6 +12,7 @@ import com.brainwallet.R import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.di.getKoinInstance import com.brainwallet.presenter.activities.BreadActivity +import com.brainwallet.tools.util.Utils import com.brainwallet.ui.BrainwalletActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -66,6 +67,7 @@ object LegacyNavigation { context.startActivity(it) } + @JvmOverloads @JvmStatic fun showMoonPayWidget( context: Context, @@ -73,7 +75,7 @@ object LegacyNavigation { isDarkMode: Boolean = true, ) { val remoteApiSource: RemoteApiSource = getKoinInstance() - + val agentString = Utils.getAgentString(context, "android/HttpURLConnection") val progressDialog = ProgressDialog(context).apply { setMessage(context.getString(R.string.loading)) setCancelable(false) @@ -86,6 +88,7 @@ object LegacyNavigation { remoteApiSource.getMoonpaySignedUrl( params = params.toMutableMap().apply { put("defaultCurrencyCode", "ltc") + put("externalTransactionId", agentString) put("currencyCode", "ltc") put("themeId", "main-v1.0.0") put("theme", if (isDarkMode) "dark" else "light") diff --git a/app/src/main/java/com/brainwallet/tools/util/Utils.java b/app/src/main/java/com/brainwallet/tools/util/Utils.java index fb03d0c3..21b556dd 100644 --- a/app/src/main/java/com/brainwallet/tools/util/Utils.java +++ b/app/src/main/java/com/brainwallet/tools/util/Utils.java @@ -171,6 +171,9 @@ public static void hideKeyboard(Context app) { public static String getAgentString(Context app, String cfnetwork) { int versionNumber = 0; + String deviceCode = Build.MANUFACTURER + "-|-" + Build.MODEL; + + if (app != null) { try { PackageInfo pInfo = app.getPackageManager().getPackageInfo(app.getPackageName(), 0); @@ -179,7 +182,7 @@ public static String getAgentString(Context app, String cfnetwork) { Timber.e(e); } } - return String.format(Locale.ENGLISH, "%s/%d %s Android/%s", "Brainwallet", versionNumber, cfnetwork, Build.VERSION.RELEASE); + return String.format(Locale.ENGLISH, "%s/%d %s Android/%s Device/%s", "Brainwallet", versionNumber, cfnetwork, Build.VERSION.RELEASE, deviceCode); } public static String reverseHex(String hex) { From a4521d7028495031bb2ad208323b7a1b35517590 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Sat, 31 May 2025 13:19:07 +0700 Subject: [PATCH 41/65] build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) --- app/build.gradle.kts | 2 +- .../presenter/activities/BreadActivity.java | 7 +---- app/src/main/res/layout/activity_bread.xml | 2 +- app/src/main/res/menu/bottom_nav_menu.xml | 8 +----- app/src/main/res/menu/bottom_nav_menu_us.xml | 28 ------------------- 5 files changed, 4 insertions(+), 43 deletions(-) delete mode 100644 app/src/main/res/menu/bottom_nav_menu_us.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 08429835..326d7062 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,7 +20,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505291 + versionCode = 202505311 versionName = "v4.5.5" multiDexEnabled = true diff --git a/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java index b210395c..2fd05ab0 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java @@ -421,7 +421,7 @@ private void initializeViews() { bottomNav = findViewById(R.id.bottomNav); bottomNav.getMenu().clear(); - bottomNav.inflateMenu(isInUsa() ? R.menu.bottom_nav_menu_us : R.menu.bottom_nav_menu); + bottomNav.inflateMenu(R.menu.bottom_nav_menu); balanceTxtV = findViewById(R.id.balanceTxtV); primaryPrice = findViewById(R.id.primary_price); @@ -447,11 +447,6 @@ public void onGlobalLayout() { balanceTxtV.append(":"); } - private boolean isInUsa() { - TelephonyManager telManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); - return "us".equals(telManager.getSimCountryIso()); - } - @Override public void onBalanceChanged(final long balance) { updateUI(); diff --git a/app/src/main/res/layout/activity_bread.xml b/app/src/main/res/layout/activity_bread.xml index 7ad85ca9..e17e37f7 100644 --- a/app/src/main/res/layout/activity_bread.xml +++ b/app/src/main/res/layout/activity_bread.xml @@ -146,7 +146,7 @@ android:layout_height="64dp" android:layout_alignParentBottom="true" app:labelVisibilityMode="labeled" - tools:menu="@menu/bottom_nav_menu_us" /> + tools:menu="@menu/bottom_nav_menu" /> diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index 947c8a79..e5323f61 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -17,12 +17,6 @@ android:id="@+id/nav_receive" android:enabled="true" android:icon="@drawable/ic_nav_receive" - android:title="@string/Button.receive" /> - - - - - - + android:title="@string/bottom_nav_item_buy_receive_title" /> \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu_us.xml b/app/src/main/res/menu/bottom_nav_menu_us.xml deleted file mode 100644 index 187ac237..00000000 --- a/app/src/main/res/menu/bottom_nav_menu_us.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file From 6fec1e25e9cf1f35d4737112351cac4b59f7e05e Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Mon, 2 Jun 2025 13:04:59 +0700 Subject: [PATCH 42/65] fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) --- .../tools/sqlite/CurrencyDataSource.java | 20 +++++++++++++++++++ .../home/receive/ReceiveDialogViewModel.kt | 3 +-- .../com/brainwallet/currency/CurrencyTests.kt | 7 +++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java b/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java index 7c15df6d..6640916f 100644 --- a/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java +++ b/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java @@ -89,6 +89,26 @@ public void putCurrencies(Collection currencyEntities) { } } + public List getCurrenciesForBuy() { + List supportedFiatCodes = Arrays.asList( + "AUD", + "BRL", + "CAD", + "CHF", + "EUR", + "GBP", + "IDR", + "MXN", + "NGN", + "TRY", + "USD", + "ZAR" + ); + return getAllCurrencies(true).stream() + .filter(currencyEntity -> supportedFiatCodes.contains(currencyEntity.code)) + .collect(Collectors.toList()); + } + public List getAllCurrencies(Boolean shouldBeFiltered) { List currencies = new ArrayList<>(); diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt index 80ab1984..ea6df431 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt @@ -49,8 +49,7 @@ class ReceiveDialogViewModel( it.copy( address = address, qrBitmap = QRUtils.generateQR(event.context, "litecoin:${address}"), - fiatCurrencies = CurrencyDataSource.getInstance(event.context) - .getAllCurrencies(true), + fiatCurrencies = CurrencyDataSource.getInstance(event.context).getCurrenciesForBuy(), ) } diff --git a/app/src/test/java/com/brainwallet/currency/CurrencyTests.kt b/app/src/test/java/com/brainwallet/currency/CurrencyTests.kt index 37b7e46a..6be7752e 100644 --- a/app/src/test/java/com/brainwallet/currency/CurrencyTests.kt +++ b/app/src/test/java/com/brainwallet/currency/CurrencyTests.kt @@ -50,6 +50,13 @@ class CurrencyTests { assertEquals(currencyDataSource?.getAllCurrencies(true)?.count(), 0) } + @Test + fun `invoke CurrencyDataSource instance and Brainwallet filtered Fiats for Buy, should return the correct number of supported currencies (moonpay)`() { + //The actual number of BW currencies is 16. The 0 is a placeholder and needs to be replaced with a db query. + mockCursorDataFromDatabase() + assertEquals(currencyDataSource?.currenciesForBuy?.count(), 0) + } + @Test fun `invoke CurrencyDataSource instance and open database, then should validate database was not null`() { val database = currencyDataSource?.openDatabase() From c8fdf8d73be2753e5f772be5d38ee0ec169afde4 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 2 Jun 2025 20:38:32 +0100 Subject: [PATCH 43/65] Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana --- .../brainwallet/data/repository/LtcRepository.kt | 10 +++++++++- .../com/brainwallet/navigation/LegacyNavigation.kt | 13 ++++--------- .../screens/home/receive/ReceiveDialogViewModel.kt | 6 ++---- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index 962602f7..b5983c3c 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -13,6 +13,7 @@ import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse import com.brainwallet.tools.manager.BRSharedPrefs import com.brainwallet.tools.manager.FeeManager import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.tools.util.Utils interface LtcRepository { suspend fun fetchRates(): List @@ -77,7 +78,14 @@ interface LtcRepository { remoteApiSource.getBuyQuote(params) override suspend fun fetchMoonpaySignedUrl(params: Map): String { - return remoteApiSource.getMoonpaySignedUrl(params) + val agentString = Utils.getAgentString(context, "android/HttpURLConnection") + val finalParams = params + mapOf( + "defaultCurrencyCode" to "ltc", + "externalTransactionId" to agentString, + "currencyCode" to "ltc", + "themeId" to "main-v1.0.0", + ) + return remoteApiSource.getMoonpaySignedUrl(finalParams) .signedUrl.toUri() .buildUpon() .apply { diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index 08bb8258..26e1b5dc 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -9,10 +9,10 @@ import androidx.browser.customtabs.CustomTabsIntent import androidx.core.net.toUri import com.brainwallet.BuildConfig import com.brainwallet.R +import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.source.RemoteApiSource import com.brainwallet.di.getKoinInstance import com.brainwallet.presenter.activities.BreadActivity -import com.brainwallet.tools.util.Utils import com.brainwallet.ui.BrainwalletActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -74,8 +74,7 @@ object LegacyNavigation { params: Map = mapOf(), isDarkMode: Boolean = true, ) { - val remoteApiSource: RemoteApiSource = getKoinInstance() - val agentString = Utils.getAgentString(context, "android/HttpURLConnection") + val ltcRepository: LtcRepository = getKoinInstance() val progressDialog = ProgressDialog(context).apply { setMessage(context.getString(R.string.loading)) setCancelable(false) @@ -85,18 +84,14 @@ object LegacyNavigation { CoroutineScope(Dispatchers.Main).launch { try { val result = withContext(Dispatchers.IO) { - remoteApiSource.getMoonpaySignedUrl( + ltcRepository.fetchMoonpaySignedUrl( params = params.toMutableMap().apply { - put("defaultCurrencyCode", "ltc") - put("externalTransactionId", agentString) - put("currencyCode", "ltc") - put("themeId", "main-v1.0.0") put("theme", if (isDarkMode) "dark" else "light") } ) } - val widgetUri = result.signedUrl.toUri().buildUpon() + val widgetUri = result.toUri().buildUpon() .apply { if (BuildConfig.DEBUG) { authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt index ea6df431..f6b2ba8a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt @@ -49,7 +49,8 @@ class ReceiveDialogViewModel( it.copy( address = address, qrBitmap = QRUtils.generateQR(event.context, "litecoin:${address}"), - fiatCurrencies = CurrencyDataSource.getInstance(event.context).getCurrenciesForBuy(), + fiatCurrencies = CurrencyDataSource.getInstance(event.context) + .getCurrenciesForBuy(), ) } @@ -153,9 +154,6 @@ class ReceiveDialogViewModel( "baseCurrencyAmount" to currentState.fiatAmount.toString(), "language" to appSetting.value.languageCode, "walletAddress" to currentState.address, - "defaultCurrencyCode" to "ltc", - "currencyCode" to "ltc", - "themeId" to "main-v1.0.0", "theme" to if (appSetting.value.isDarkMode) "dark" else "light" ) ) From 3f646dfc8c46619597ae52a6fb01460b3f5e0c47 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Sat, 14 Jun 2025 22:15:17 +0100 Subject: [PATCH 44/65] Add agent string obfuscation (#103) --- .../data/repository/LtcRepository.kt | 4 +- .../presenter/entities/ServiceItems.kt | 1 + .../com/brainwallet/tools/util/Utils.java | 114 ++++++++++++++++-- 3 files changed, 104 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index b5983c3c..39542354 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -78,10 +78,10 @@ interface LtcRepository { remoteApiSource.getBuyQuote(params) override suspend fun fetchMoonpaySignedUrl(params: Map): String { - val agentString = Utils.getAgentString(context, "android/HttpURLConnection") + val externalTransactionID = Utils.getEncryptedAgentString(context) val finalParams = params + mapOf( "defaultCurrencyCode" to "ltc", - "externalTransactionId" to agentString, + "externalTransactionId" to externalTransactionID, "currencyCode" to "ltc", "themeId" to "main-v1.0.0", ) diff --git a/app/src/main/java/com/brainwallet/presenter/entities/ServiceItems.kt b/app/src/main/java/com/brainwallet/presenter/entities/ServiceItems.kt index 1a8b7a4d..fc9b1983 100644 --- a/app/src/main/java/com/brainwallet/presenter/entities/ServiceItems.kt +++ b/app/src/main/java/com/brainwallet/presenter/entities/ServiceItems.kt @@ -6,4 +6,5 @@ enum class ServiceItems(val key: String) { WALLETSTART("start-date"), AFDEVID("af-dev-id"), CLIENTCODE("client-code"), + AGENTPUBKEY("agent-base64-pubkey") } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/tools/util/Utils.java b/app/src/main/java/com/brainwallet/tools/util/Utils.java index 21b556dd..1596c5c5 100644 --- a/app/src/main/java/com/brainwallet/tools/util/Utils.java +++ b/app/src/main/java/com/brainwallet/tools/util/Utils.java @@ -3,8 +3,6 @@ import android.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.net.Uri; import android.os.Build; @@ -15,10 +13,21 @@ import android.view.inputmethod.InputMethodManager; import com.brainwallet.tools.manager.AnalyticsManager; -import com.brainwallet.tools.sqlite.CurrencyDataSource; -import com.brainwallet.data.model.CurrencyEntity; import com.brainwallet.presenter.entities.ServiceItems; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -33,7 +42,6 @@ import java.util.Calendar; import java.util.Collection; import java.util.Collections; -import java.util.Currency; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -168,21 +176,98 @@ public static void hideKeyboard(Context app) { } } - public static String getAgentString(Context app, String cfnetwork) { - int versionNumber = 0; + String deviceCode = Build.MANUFACTURER + "-|-" + Build.MODEL; + String appVersion = BRConstants.APP_VERSION_NAME_CODE; + return String.format(Locale.ENGLISH, "%s/%d %s Android/%s Device/%s", "Brainwallet", + appVersion, cfnetwork, Build.VERSION.RELEASE, deviceCode); + } + public static String getEncryptedAgentString(Context app) { + String deviceCode = Build.MANUFACTURER; + String deviceType = Build.DEVICE; + String deviceModel = Build.MODEL; + String appVersion = BRConstants.APP_VERSION_NAME_CODE; + String formattedAgentString = String.format(Locale.ENGLISH, "brainwallet-android,%s,%s-%s-%s", + appVersion, deviceCode,deviceType,deviceModel); + + try { + + // Convert base64 public key string to PublicKey object + byte[] keyBytes; + try { + String pubkey = Utils.fetchServiceItem(app, ServiceItems.AGENTPUBKEY).toString(); + keyBytes = Base64.getDecoder().decode(pubkey); + + // Decode the base64 to get the PEM string + byte[] pemBytes = Base64.getDecoder().decode(pubkey); + String pemString = new String(pemBytes, "UTF-8"); + + // Extract just the key data (remove PEM headers and whitespace) + String keyData = pemString + .replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "") + .replaceAll("\\s+", ""); + + // Decode the clean base64 key data + keyBytes = Base64.getDecoder().decode(keyData); + } catch (IllegalArgumentException e) { + Timber.d("Invalid base64 public key format: %s", e.toString()); + return "ERROR-CANNOT-KEYBYTES-DO-CONVERSION"; + } + KeyFactory keyFactory; + try { + keyFactory = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + Timber.d("RSA algorithm not available: %s", e.toString()); + return "ERROR-CANNOT-NOSUCHALGO"; + } - if (app != null) { + // Generate PublicKey object + PublicKey publicKey; try { - PackageInfo pInfo = app.getPackageManager().getPackageInfo(app.getPackageName(), 0); - versionNumber = pInfo.versionCode; - } catch (PackageManager.NameNotFoundException e) { - Timber.e(e); + publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyBytes)); + } catch (InvalidKeySpecException e) { + Timber.d("Invalid public key specification: %s", e.toString()); + return "ERROR-CANNOT-INVALID-PUBLIC-KEY-SPEC"; } + + // Initialize cipher for encryption + Cipher cipher; + try { + cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + Timber.d("RSA cipher algorithm/padding not available: %s", e.toString()); + return "ERROR-RSA-CIPHER-NA"; + } + + try { + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + } catch (InvalidKeyException e) { + Timber.d("Invalid public key for encryption: %s", e.toString()); + return "ERROR-CANNOT-INVALID-PUBLIC-KEY-ENCRYPTION"; + } + + // Encrypt the agent string + byte[] encryptedBytes; + try { + encryptedBytes = cipher.doFinal(formattedAgentString.getBytes()); + } catch (IllegalBlockSizeException e) { + Timber.d("Agent string too large for RSA encryption. Consider using hybrid encryption.: %s", e.toString()); + return "ERROR-ILLEGAL-BLOCK-SIZE"; + } catch (BadPaddingException e) { + Timber.d("Padding error during encryption: %s", e.toString()); + return "ERROR-BAD-PADDING-EXCEPTION"; + } + + return Base64.getEncoder().encodeToString(encryptedBytes); + + } catch (Exception e) { + // Catch any unexpected exceptions + Timber.d("Unexpected error during encryption: %s", e.toString()); + return "ERROR-UNEXPECTED-DURING-ENCRYPTION"; } - return String.format(Locale.ENGLISH, "%s/%d %s Android/%s Device/%s", "Brainwallet", versionNumber, cfnetwork, Build.VERSION.RELEASE, deviceCode); } public static String reverseHex(String hex) { @@ -245,6 +330,9 @@ else if (name == ServiceItems.OPSALL) { else if (name == ServiceItems.AFDEVID) { return keyObject.optString(name.getKey()); } + else if (name == ServiceItems.AGENTPUBKEY) { + return keyObject.optString(name.getKey()); + } else if (name == ServiceItems.CLIENTCODE) { return keyObject.optString(name.getKey()); } From 642f9e6ea00637cdc5de29196cbe3e7a826dc214 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Tue, 24 Jun 2025 09:09:05 +0100 Subject: [PATCH 45/65] updated metadata (#105) --- app/build.gradle.kts | 4 ++-- app/src/main/java/com/brainwallet/tools/util/Utils.java | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 326d7062..be73cab7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202505311 - versionName = "v4.5.5" + versionCode = 202506231 + versionName = "v4.6.1" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/src/main/java/com/brainwallet/tools/util/Utils.java b/app/src/main/java/com/brainwallet/tools/util/Utils.java index 1596c5c5..5a346596 100644 --- a/app/src/main/java/com/brainwallet/tools/util/Utils.java +++ b/app/src/main/java/com/brainwallet/tools/util/Utils.java @@ -46,8 +46,10 @@ import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; +import kotlin.uuid.Uuid; import timber.log.Timber; public class Utils { @@ -187,9 +189,10 @@ public static String getEncryptedAgentString(Context app) { String deviceCode = Build.MANUFACTURER; String deviceType = Build.DEVICE; String deviceModel = Build.MODEL; + String udidString = String.valueOf(UUID.randomUUID()); String appVersion = BRConstants.APP_VERSION_NAME_CODE; - String formattedAgentString = String.format(Locale.ENGLISH, "brainwallet-android,%s,%s-%s-%s", - appVersion, deviceCode,deviceType,deviceModel); + String formattedAgentString = String.format(Locale.ENGLISH, "brainwallet-android,%s,%s-%s-%s,%s", + appVersion, deviceCode,deviceType,deviceModel,udidString); try { From 50f44de142f3673d1e0be13ad0d35488b98f7d40 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Tue, 24 Jun 2025 15:10:19 +0700 Subject: [PATCH 46/65] chore: remove screen lock detection (#106) --- .../brainwallet/wallet/BRWalletManager.java | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java index 59aaed33..b1031ea8 100644 --- a/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java +++ b/app/src/main/java/com/brainwallet/wallet/BRWalletManager.java @@ -457,27 +457,10 @@ public static void onTxDeleted(String hash, int notifyUser, final int recommendR public void startTheWalletIfExists(final Activity app) { final BRWalletManager m = BRWalletManager.getInstance(); - if (!m.isPasscodeEnabled(app)) { - //Device passcode/password should be enabled for the app to work - BRDialog.showCustomDialog(app, app.getString(R.string.JailbreakWarnings_title), app.getString(R.string.Prompts_NoScreenLock_body_android), - app.getString(R.string.AccessibilityLabels_close), null, new BRDialogView.BROnClickListener() { - @Override - public void onClick(BRDialogView brDialogView) { - app.finish(); - } - }, null, new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - app.finish(); - } - }, 0); - } else { - if (!m.noWallet(app) && BRSharedPrefs.getPhraseWroteDown(app)) { - BRAnimator.startBreadActivity(app, true); - } - //else just sit in the intro screen - + if (!m.noWallet(app) && BRSharedPrefs.getPhraseWroteDown(app)) { + BRAnimator.startBreadActivity(app, true); } + //else just sit in the intro screen } @WorkerThread From ea154239e367ee6cea42ccbb7b145c70527309c5 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Wed, 25 Jun 2025 16:57:17 +0100 Subject: [PATCH 47/65] =?UTF-8?q?=F0=9F=A7=B0=20=20Fx/seed=20words=20UI=20?= =?UTF-8?q?polish=20(#108)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound --- app/build.gradle.kts | 4 ++-- .../yourseedproveit/YourSeedProveItScreen.kt | 20 ++++++++++++++---- app/src/main/res/raw/clickseedword.m4a | Bin 3866 -> 0 bytes app/src/main/res/raw/clickseedword.mp3 | Bin 0 -> 3829 bytes app/src/main/res/raw/errorsound.mp3 | Bin 0 -> 41086 bytes app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-hi/strings.xml | 1 + app/src/main/res/values-in/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 4 +++- 22 files changed, 37 insertions(+), 7 deletions(-) delete mode 100644 app/src/main/res/raw/clickseedword.m4a create mode 100644 app/src/main/res/raw/clickseedword.mp3 create mode 100644 app/src/main/res/raw/errorsound.mp3 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index be73cab7..fc08272e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202506231 - versionName = "v4.6.1" + versionCode = 202506251 + versionName = "v4.6.2" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt index 214982a7..04fcf6f2 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt @@ -76,6 +76,7 @@ fun YourSeedProveItScreen( val maxItemsPerRow = 3 val clickAudioPlayer = remember { MediaPlayer.create(context, R.raw.clickseedword) } + val errorAudioPlayer = remember { MediaPlayer.create(context, R.raw.errorsound) } val coinAudioPlayer = remember { MediaPlayer.create(context, R.raw.coinflip) } LaunchedEffect(Unit) { @@ -156,10 +157,13 @@ fun YourSeedProveItScreen( expectedWord = expectedWord, actualWord = text.toString() ) - ) - if (expectedWord == actualWord) { - clickAudioPlayer.start() + ) + if (text.toString() == expectedWord) { + clickAudioPlayer.start() // Success sound + } + else { + errorAudioPlayer.start() // Success sound } return true } @@ -173,6 +177,14 @@ fun YourSeedProveItScreen( } Spacer(modifier = Modifier.weight(1f)) + Text( + text = stringResource(if (state.orderCorrected) R.string.empty_string else R.string.tap_drag_a_word), + style = MaterialTheme.typography.bodyMedium.copy( + textAlign = TextAlign.Center, + color = Color.Gray + ) + ) + Spacer(modifier = Modifier.weight(0.1f)) SeedWordsLayout { itemsIndexed(items = state.shuffledSeedWords) { index, word -> @@ -190,7 +202,7 @@ fun YourSeedProveItScreen( .fillMaxWidth() .dragAndDropSource { detectTapGestures( - onLongPress = { + onPress = { startTransfer( DragAndDropTransferData( clipData = ClipData.newPlainText( diff --git a/app/src/main/res/raw/clickseedword.m4a b/app/src/main/res/raw/clickseedword.m4a deleted file mode 100644 index 53758e26a756a36bbab8c9882e19fd9be5e4c567..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3866 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سهم لأسفل لليسار شعار تبديل الوضع المظلم + اضغط على كلمة واسحبها إلى مكانها اشحن رصيدك؟\n عقلك فارغ الآن.. احصل على عملة اللايتكوين في 5 دقائق diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a07b7400..31708d56 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -773,6 +773,7 @@ Pfeil nach unten links Logo Dunkelmodus umschalten + Tippen Sie auf ein Wort und ziehen Sie es an die richtige Stelle Nachfüllen? Im Moment ist dein Gehirn leer... Holen Sie sich Litecoin in 5 Minuten diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 1a918843..3eaded9b 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -772,6 +772,7 @@ flecha abajo-izquierda logo alternar-modo-oscuro + Toca una palabra y arrástrala a su lugar ¿Completar? Ahora mismo tu cerebro está vacío... Obtén Litecoin en 5 minutos diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b0e92d08..2d0343e3 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -773,6 +773,7 @@ flèche bas-gauche logo basculer en mode sombre + Appuyez sur un mot et faites-le glisser en place Recharger ? En ce moment, votre cerveau est vide... Obtenez du Litecoin en 5 minutes diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 3c263e70..cb889a37 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -411,6 +411,7 @@ नीचे-बाएँ-तीर प्रतीक चिन्ह टॉगल-डार्क-मोड + एक शब्द पर टैप करें और इसे सही जगह खींचें लबालब भरना? अभी तो तुम्हारा दिमाग खाली है... 5 मिनट में लाइटकॉइन प्राप्त करें diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 371a07fa..73f60f4d 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -775,6 +775,7 @@ panah kiri bawah logo beralih-mode gelap + Ketuk kata dan seret ke tempatnya Isi ulang? Saat ini otakmu kosong... Dapatkan Litecoin dalam 5 menit diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0246634a..69116bf1 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -773,6 +773,7 @@ freccia giù a sinistra logo attiva/disattiva la modalità oscura + Tocca una parola e trascinala al posto giusto Ricaricare? In questo momento il tuo cervello è vuoto... Ottieni Litecoin in 5 minuti diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 9523482b..5550e8f1 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -773,6 +773,7 @@ 左下矢印 ロゴ ダークモードの切り替え + 単語をタップしてドラッグして配置してください 補充しますか? 今、あなたの脳は空っぽです... 5分でライトコインをゲット diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 0f409eb0..693a92ae 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -773,6 +773,7 @@ 아래쪽 왼쪽 화살표 심벌 마크 토글 다크 모드 + 단어를 탭하고 제자리로 드래그하세요 충전하시겠습니까? 지금 당신의 뇌는 비어있습니다... 5분 안에 라이트코인을 받으세요 diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 535904d3..1e68ec84 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -772,6 +772,7 @@ seta para baixo à esquerda logotipo alternar modo escuro + Toque em uma palavra e arraste-a para o lugar Recarregar? Neste momento seu cérebro está vazio... Obtenha Litecoin em 5 minutos diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5434b353..183a5c30 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -773,6 +773,7 @@ стрелка вниз-влево логотип переключить темный режим + Нажмите на слово и перетащите его на место Пополнить? Сейчас в твоем мозгу пусто... Получите Litecoin за 5 минут diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index eef96cac..1e7f0342 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -411,6 +411,7 @@ ned-vänster-pil logotyp växla mellan mörkt läge + Tryck på ett ord och dra det på plats Fylla på? Just nu är din hjärna tom... Få Litecoin på 5 minuter diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index b67506d4..cd3a9eaf 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -795,6 +795,7 @@ sol aşağı ok logo karanlık moda geçiş + Bir kelimeye dokunun ve yerine sürükleyin Tamamlansın mı?\n Tamamlansın mı?\n Tamamlansın mı? diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index f8899d68..cd63237d 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -779,6 +779,7 @@ стрілка вниз-ліворуч логотип перемикати темний режим + Торкніться слова і перетягніть його на місце Поповнити? Зараз ваш мозок порожній... Отримайте Litecoin за 5 хвилин diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 763288ac..4f28b512 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -773,6 +773,7 @@ 左下箭头 标识 切换暗模式 + 点击单词并拖拽到位 充值? 现在你的大脑一片空白…… 5 分钟内获得莱特币 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fe1abc56..378bc1aa 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -772,6 +772,7 @@ 左下箭頭 標識 切換暗模式 + 點擊單詞並拖拽到位 儲值? 現在你的大腦一片空白… 5 分鐘內獲得萊特幣 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12fca16d..8323d2ac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -776,13 +776,14 @@ + Back Your seed words "Just for you. \n It is the private key that lets you send." Blockchain: Litecoin I saved it on paper or metal You saved it, right? - Prove it!\nDrag thƒe words in the correct order. + Prove it!\nDrag the words in the correct order. Game & Sync Ready? Do this for you. Please do it @@ -795,6 +796,7 @@ Use biometrics You saved your keys. Crush the next level. + Tap a word and drag it in place Top up? Right now your brain is empty... Get Litecoin in 5 minutes From 5b6dff30504257d908bf56db047dd7b723081901 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Fri, 27 Jun 2025 23:46:23 +0100 Subject: [PATCH 48/65] =?UTF-8?q?=E2=9D=87=EF=B8=8F=20Feat/add=20polish=20?= =?UTF-8?q?punjabi=20farsi=20(#109)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * Removed unused audio files * polished tests * removed unused asset pack * code bump --- app/build.gradle.kts | 4 +- .../data/model/IntroLanguageResource.kt | 142 --- .../com/brainwallet/data/model/Language.kt | 4 + app/src/main/res/raw/arabic.mp3 | Bin 5184 -> 0 bytes app/src/main/res/raw/bahasaindonesia.mp3 | Bin 8928 -> 0 bytes app/src/main/res/raw/deutsch.mp3 | Bin 3936 -> 0 bytes app/src/main/res/raw/english.mp3 | Bin 3936 -> 0 bytes app/src/main/res/raw/french.mp3 | Bin 3648 -> 0 bytes app/src/main/res/raw/hindi.mp3 | Bin 6912 -> 0 bytes app/src/main/res/raw/italiano.mp3 | Bin 4416 -> 0 bytes app/src/main/res/raw/japanese.mp3 | Bin 4320 -> 0 bytes app/src/main/res/raw/korean.mp3 | Bin 4416 -> 0 bytes app/src/main/res/raw/portugues.mp3 | Bin 5280 -> 0 bytes app/src/main/res/raw/russian.mp3 | Bin 4224 -> 0 bytes app/src/main/res/raw/simplifiedchinese.mp3 | Bin 5088 -> 0 bytes app/src/main/res/raw/spanish.mp3 | Bin 4032 -> 0 bytes app/src/main/res/raw/traditionalchinese.mp3 | Bin 5088 -> 0 bytes app/src/main/res/raw/turkish.mp3 | Bin 3552 -> 0 bytes app/src/main/res/raw/ukrainian.mp3 | Bin 5184 -> 0 bytes app/src/main/res/values-fa/strings.xml | 852 ++++++++++++++++++ app/src/main/res/values-pa/strings.xml | 846 +++++++++++++++++ app/src/main/res/values-pl/strings.xml | 841 +++++++++++++++++ .../tools/util/LocaleHelperTest.kt | 26 +- fast_follow_asset_pack_01/.DS_Store | Bin 6148 -> 0 bytes fast_follow_asset_pack_01/build.gradle.kts | 10 - .../src/main/assets/audio/arabic.mp3 | Bin 5184 -> 0 bytes .../src/main/assets/audio/bahasaindonesia.mp3 | Bin 8928 -> 0 bytes .../src/main/assets/audio/coinflip.mp3 | Bin 23680 -> 0 bytes .../src/main/assets/audio/deutsch.mp3 | Bin 3936 -> 0 bytes .../src/main/assets/audio/english.mp3 | Bin 3936 -> 0 bytes .../src/main/assets/audio/french.mp3 | Bin 3648 -> 0 bytes .../src/main/assets/audio/hindi.mp3 | Bin 6912 -> 0 bytes .../src/main/assets/audio/italiano.mp3 | Bin 4416 -> 0 bytes .../src/main/assets/audio/japanese.mp3 | Bin 4320 -> 0 bytes .../src/main/assets/audio/korean.mp3 | Bin 4416 -> 0 bytes .../src/main/assets/audio/portugues.mp3 | Bin 5280 -> 0 bytes .../src/main/assets/audio/russian.mp3 | Bin 4224 -> 0 bytes .../main/assets/audio/simplifiedchinese.mp3 | Bin 5088 -> 0 bytes .../src/main/assets/audio/spanish.mp3 | Bin 4032 -> 0 bytes .../main/assets/audio/traditionalchinese.mp3 | Bin 5088 -> 0 bytes .../src/main/assets/audio/turkish.mp3 | Bin 3552 -> 0 bytes .../src/main/assets/audio/ukrainian.mp3 | Bin 5184 -> 0 bytes settings.gradle.kts | 1 - 43 files changed, 2552 insertions(+), 174 deletions(-) delete mode 100644 app/src/main/java/com/brainwallet/data/model/IntroLanguageResource.kt delete mode 100644 app/src/main/res/raw/arabic.mp3 delete mode 100644 app/src/main/res/raw/bahasaindonesia.mp3 delete mode 100644 app/src/main/res/raw/deutsch.mp3 delete mode 100644 app/src/main/res/raw/english.mp3 delete mode 100644 app/src/main/res/raw/french.mp3 delete mode 100644 app/src/main/res/raw/hindi.mp3 delete mode 100644 app/src/main/res/raw/italiano.mp3 delete mode 100644 app/src/main/res/raw/japanese.mp3 delete mode 100644 app/src/main/res/raw/korean.mp3 delete mode 100644 app/src/main/res/raw/portugues.mp3 delete mode 100644 app/src/main/res/raw/russian.mp3 delete mode 100644 app/src/main/res/raw/simplifiedchinese.mp3 delete mode 100644 app/src/main/res/raw/spanish.mp3 delete mode 100644 app/src/main/res/raw/traditionalchinese.mp3 delete mode 100644 app/src/main/res/raw/turkish.mp3 delete mode 100644 app/src/main/res/raw/ukrainian.mp3 create mode 100644 app/src/main/res/values-fa/strings.xml create mode 100644 app/src/main/res/values-pa/strings.xml create mode 100644 app/src/main/res/values-pl/strings.xml delete mode 100644 fast_follow_asset_pack_01/.DS_Store delete mode 100644 fast_follow_asset_pack_01/build.gradle.kts delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/arabic.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/bahasaindonesia.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/coinflip.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/deutsch.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/english.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/french.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/hindi.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/italiano.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/japanese.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/korean.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/portugues.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/russian.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/simplifiedchinese.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/spanish.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/traditionalchinese.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/turkish.mp3 delete mode 100644 fast_follow_asset_pack_01/src/main/assets/audio/ukrainian.mp3 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fc08272e..802fe2e6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,7 +20,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202506251 + versionCode = 202506271 versionName = "v4.6.2" multiDexEnabled = true @@ -40,7 +40,7 @@ android { } } - assetPacks.addAll(setOf(":install_time_asset_pack", ":fast_follow_asset_pack_01")) + assetPacks.addAll(setOf(":install_time_asset_pack")) signingConfigs { getByName("debug") { diff --git a/app/src/main/java/com/brainwallet/data/model/IntroLanguageResource.kt b/app/src/main/java/com/brainwallet/data/model/IntroLanguageResource.kt deleted file mode 100644 index f1399dc1..00000000 --- a/app/src/main/java/com/brainwallet/data/model/IntroLanguageResource.kt +++ /dev/null @@ -1,142 +0,0 @@ -package com.brainwallet.data.model - -import com.brainwallet.R - -class IntroLanguageResource { - fun loadResources(): Array { - return arrayOf( - IntroLanguage( - Language.ENGLISH.code, - Language.ENGLISH.title, - "The most fun thing to do with your Litecoin!", - R.raw.english, - "Are you sure you want to change the language to English?", - Language.ENGLISH - ), - IntroLanguage( - Language.SPANISH.code, - Language.SPANISH.title, - "¡Lo más divertido que puedes hacer con tus Litecoin!", - R.raw.spanish, - "¿Estás seguro de que quieres cambiar el idioma a español?", - Language.SPANISH, - ), - IntroLanguage( - Language.INDONESIAN.code, - Language.INDONESIAN.title, - "Hal paling menyenangkan untuk dilakukan dengan Litecoin Anda!", - R.raw.bahasaindonesia, - "Yakin ingin mengubah bahasanya ke bahasa Indonesia?", - Language.INDONESIAN - ), - IntroLanguage( - Language.ARABIC.code, - Language.ARABIC.title, - "الشيء الأكثر متعة يمكنك القيام به مع Litecoin الخاص بك!", - R.raw.arabic, - "هل أنت متأكد أنك تريد تغيير اللغة إلى الإندونيسية؟", - Language.ARABIC - ), - IntroLanguage( - Language.UKRAINIAN.code, - Language.UKRAINIAN.title, - "Найцікавіша річ, яку можна зробити зі своїм Litecoin!", - R.raw.ukrainian, - "Ви впевнені, що хочете змінити мову на українську?", - Language.UKRAINIAN - ), - IntroLanguage( - Language.RUSSIAN.code, - Language.RUSSIAN.title, - "Самое веселое занятие с вашими Litecoin!", - R.raw.russian, - "Вы уверены, что хотите сменить язык на русский?", - Language.RUSSIAN - ), - IntroLanguage( - Language.PORTUGUESE.code, - Language.PORTUGUESE.title, - "A coisa mais divertida para fazer com seu Litecoin!", - R.raw.portugues, - "Tem certeza de que deseja alterar o idioma para português?", - Language.PORTUGUESE - ), - IntroLanguage( - Language.KOREAN.code, - Language.KOREAN.title, - "라이트코인으로 할 수 있는 가장 재밌는 일!", - R.raw.korean, - "언어를 한국어로 변경하시겠습니까?", - Language.KOREAN - ), - IntroLanguage( - Language.FRENCH.code, - Language.FRENCH.title, - "La chose la plus amusante à faire avec votre Litecoin!", - R.raw.french, - "Êtes-vous sûr de vouloir changer la langue en français ?", - Language.FRENCH - ), - IntroLanguage( - Language.CHINESE_TRADITIONAL.code, - Language.CHINESE_TRADITIONAL.title, - "用萊特幣做的最有趣的事!", - R.raw.traditionalchinese, - "您確定要將語言改為中文嗎?", - Language.CHINESE_TRADITIONAL - ), - IntroLanguage( - Language.TURKISH.code, - Language.TURKISH.title, - "Litecoin'inizle yapabileceğiniz en eğlenceli şey!", - R.raw.turkish, - "Dili türkçeye değiştirmek istediğinizden emin misiniz?", - Language.TURKISH - ), - IntroLanguage( - Language.JAPANESE.code, - Language.JAPANESE.title, - "ライトコインでできる最も楽しいこと!", - R.raw.japanese, - "言語を日本語に変更してもよろしいですか?", - Language.JAPANESE - ), - IntroLanguage( - Language.GERMAN.code, - Language.GERMAN.title, - "Das macht am meisten Spaß, was Sie mit Ihrem Litecoin machen können!", - R.raw.deutsch, - "Sind Sie sicher, dass Sie die Sprache auf Deutsch ändern möchten?", - Language.GERMAN - ), - IntroLanguage( - Language.CHINESE_SIMPLIFIED.code, - Language.CHINESE_SIMPLIFIED.title, - "用使用萊特幣可以做的最有趣的事情!", - R.raw.simplifiedchinese, - "您確定要將語言改為中文嗎?", - Language.CHINESE_SIMPLIFIED - ), - IntroLanguage( - Language.HINDI.code, - Language.HINDI.title, - "अपने लाइटकॉइन के साथ करने के लिए सबसे मज़ेदार चीज़!", - R.raw.hindi, - "您確定要將語言改為中文嗎?", - Language.HINDI - ), - IntroLanguage( - Language.ITALIAN.code, - Language.ITALIAN.title, - "La cosa più divertente da fare con i tuoi Litecoin!", - R.raw.italiano, - "Sei sicuro di voler cambiare la lingua in italiano?", - Language.ITALIAN - ), - ) - } - - fun findLanguageIndex(language: Language): Int { - return loadResources().map { intro -> intro.lang }.indexOf(language) - } -} diff --git a/app/src/main/java/com/brainwallet/data/model/Language.kt b/app/src/main/java/com/brainwallet/data/model/Language.kt index 340af45b..9a9d6c8c 100644 --- a/app/src/main/java/com/brainwallet/data/model/Language.kt +++ b/app/src/main/java/com/brainwallet/data/model/Language.kt @@ -23,6 +23,9 @@ enum class Language ( PORTUGUESE("pt", "Português", "Selecione o idioma"), HINDI("hi", "हिंदी", "भाषा चुने"), GERMAN("de", "Deutsch", "Sprache auswählen"), + PERSIAN("fa", "فارسی", "زبان را انتخاب کنید"), + PUNJABI("pa", "پنجابی", "زبان دا انتخاب کرو"), + POLISH("pl", "Polski", "Wybierz język"), KOREAN("ko", "한국어", "언어 선택"), FRENCH("fr", "Français", "Sélectionner la langue"), CHINESE_TRADITIONAL("zh-TW", "繁體字", "選擇語言"), @@ -30,6 +33,7 @@ enum class Language ( JAPANESE("ja", "日本語", "言語を選択する"), CHINESE_SIMPLIFIED("zh-CN", "简化字", "选择语言"), ITALIAN("it", "Italiano", "Seleziona la lingua"), + SWEDISH("sv", "Svenska", "Välj språk") ; companion object { diff --git a/app/src/main/res/raw/arabic.mp3 b/app/src/main/res/raw/arabic.mp3 deleted file mode 100644 index 65e0112eb5652104577cf2ef357343de135eaf24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5184 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 R{x9SE-)8yW|KtC+{~v%HY3%?2 diff --git a/app/src/main/res/raw/deutsch.mp3 b/app/src/main/res/raw/deutsch.mp3 deleted file mode 100644 index 868409d093b4b4a67adbed42bca46d1c292c97fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3936 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 C1S38G diff --git a/app/src/main/res/raw/hindi.mp3 b/app/src/main/res/raw/hindi.mp3 deleted file mode 100644 index 7ba1ad66b8a76602c541525030faaaa6cf72a0ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6912 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 diff --git a/app/src/main/res/raw/japanese.mp3 b/app/src/main/res/raw/japanese.mp3 deleted file mode 100644 index 379a6938050723055096af20025fa6d452f4032b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4320 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 BkHP=| diff --git a/app/src/main/res/raw/korean.mp3 b/app/src/main/res/raw/korean.mp3 deleted file mode 100644 index f17488e15429e9f3e4bd9a27b3b9ec0b577cb9e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4416 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 D^BFm+ diff --git a/app/src/main/res/raw/portugues.mp3 b/app/src/main/res/raw/portugues.mp3 deleted file mode 100644 index f7d54262bd996b2956365b7e60914d3d83cb7fda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5280 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 diff --git a/app/src/main/res/raw/simplifiedchinese.mp3 b/app/src/main/res/raw/simplifiedchinese.mp3 deleted file mode 100644 index b9f00f6cbbfa304d949fd2a280ff21de1a1789d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5088 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 z 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 JSKYtb{~P66Pfh>; diff --git a/app/src/main/res/raw/traditionalchinese.mp3 b/app/src/main/res/raw/traditionalchinese.mp3 deleted file mode 100644 index b9f00f6cbbfa304d949fd2a280ff21de1a1789d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5088 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 F{{ilF$iM&q diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml new file mode 100644 index 00000000..8f82d491 --- /dev/null +++ b/app/src/main/res/values-fa/strings.xml @@ -0,0 +1,852 @@ + + + + + وب‌سایت + + + + سیاست حفظ حریم خصوصی + + + شرایط استفاده + + درباره + + توییتر + + بستن + + مرکز پشتیبانی + + + + به نظر می‌رسد شما از یک صفحه کلید شخص ثالث استفاده می‌کنید که می‌تواند آنچه را تایپ می‌کنید ثبت کرده و کلید کاغذی شما را سرقت کند. لطفاً برای محافظت بیشتر به صفحه کلید پیش‌فرض اندروید تغییر دهید. + + خطا + + مشکلی با کلید ذخیره سیستم عامل اندروید شما وجود دارد، لطفاً با support.brainwallet.co تماس بگیرید. + + داده‌های رمزگذاری شده کیف پول ذهنی (Brainwallet) شما اخیراً به دلیل غیرفعال شدن صفحه قفل اندروید شما نامعتبر شده است. + + خطای کلید ذخیره اندروید + + اتصال اینترنت یافت نشد. اتصال خود را بررسی کنید و دوباره تلاش کنید. + + هشدار + + آدرس‌ها کپی شدند + + تمام آدرس‌های کیف پول با موفقیت کپی شدند. + + مجموعه کلید کاغذی + + عالی! + + رمز تنظیم شده + + ارسال ناموفق + + تأیید ارسال + + پول ارسال شد! + + اثر انگشت شناسایی شد + + خطای سریال‌سازی JSON + + کیف پول آماده نیست + + قادر به بازیابی توکن API نیست + + لغو + + نادیده بگیرید + + منو + + نه + + خوب + + دریافت کردن + + ارسال کنید + + تنظیمات + + ارسال کنید + + بله + + مبلغ ارسالی: + + هزینه شبکه: + + شبکه + + زمان پردازش: پیش‌بینی می‌شود این تراکنش در %1$s تکمیل شود. + + ارسال کنید + + تأیید + + به + + هزینه کل: + + برای اطمینان از اینکه همه چیز به درستی نوشته شده است، لطفاً کلمات زیر را از کلید کاغذی خود وارد کنید. + + کلمه #%1$s + + واحد نمایش لایت کوین + + نرخ ارز + + + + کیف پول مغزی به دلیل یک اشکال در نسخه اندروید شما قابل تأیید نیست. [لطفاً برای اطلاعات بیشتر اینجا ضربه بزنید.] + + این دستگاه برای ارسال پیام‌ها پیکربندی نشده است. + + پیام‌رسانی در دسترس نیست + + اثر انگشت شناسایی نشد. لطفاً دوباره تلاش کنید. + + اقتصاد + + ۱۰+ دقیقه + + این گزینه برای تراکنش‌های حساس به زمان توصیه نمی‌شود. + + زمان تحویل تخمینی: %1$s + + عادی + + ۲.۵ - ۵+ دقیقه + + سرعت پردازش + + بررسی موجودی کلید خصوصی... + + ارسال %1$s از این کلید خصوصی به کیف پول شما؟ شبکه لایت کوین هزینه‌ای به میزان %2$s دریافت خواهد کرد. + + این کلید خصوصی در حال حاضر در کیف پول شما موجود است. + + این کلید خصوصی خالی است. + + هزینه‌های تراکنش بیشتر از وجوه موجود در این کلید خصوصی خواهد بود. + + کلید خصوصی معتبر نیست + + خطا در امضای تراکنش + + واردات + + وارد کردن کیف پول + + کیف پول برای وارد کردن + + وارد کردن یک کیف پول، تمام پول از کیف پول دیگر شما را با استفاده از یک تراکنش واحد به کیف پول مغزی شما منتقل می‌کند. + + این کلید خصوصی با رمز عبور محافظت شده است. + + رمز عبور + + + اسکن کلید خصوصی + + موفقیت + + کیف پول با موفقیت وارد شد. + + وارد کردن کیف پول + + باز کردن کلید + + وارد کردن کیف پول شامل تاریخچه تراکنش‌ها یا سایر جزئیات نمی‌شود. + + رمز عبور اشتباه است، لطفاً دوباره تلاش کنید. + + نادیده بگیرید + + امنیت دستگاه به خطر افتاده است +هر برنامه \'جیلبرک\' می‌تواند به داده‌های کیف کلید دسترسی پیدا کند و لایت‌کوین شما را سرقت کند! این کیف پول را فوراً پاک کنید و در یک دستگاه امن بازیابی کنید. + + امنیت دستگاه به خطر افتاده است +هر برنامه \'جیلبرک\' می‌تواند به داده‌های کیچین دسترسی پیدا کند و لایت‌کوین شما را سرقت کند. لطفاً از Brainwallet فقط در دستگاهی که جیلبریک نشده است استفاده کنید. + + هشدار + + خدمات مکان‌یابی غیرفعال است. + + برین‌والت اجازه دسترسی به خدمات موقعیت‌یابی را ندارد. + + شما کیف پول خود را در %1$s ایجاد کردید + + نام کیف پول شما فقط در تاریخچه تراکنش‌های حساب شما نمایش داده می‌شود و توسط هیچ شخص دیگری قابل مشاهده نیست. + + نام کیف پول + + مدیریت کیف پول + + خرید + + قفل کیف پول + + مرکز امنیت + + تنظیمات + + پشتیبانی مشتری + + ایجاد کیف پول جدید + + منو + + بازیابی کیف پول + + به حالت خودکار تغییر دهید + + متصل + + آدرس IP گره و پورت (اختیاری) را وارد کنید + + وارد گره شوید + + به حالت دستی تغییر دهید + + گره اصلی فعلی + + متصل نیست + + وضعیت اتصال گره + + نودهای لایت کوین + + درخواست پرداخت نامعتبر + + سند پشتیبانی نشده یا خراب شده + + گواهی مفقود شده + + درخواست منقضی شده است + + نتوانستم پرداخت را انجام دهم + + پرداخت‌های لایت‌کوین نمی‌توانند کمتر از %1$s باشند. + + خروجی‌های تراکنش لایت‌کوین نمی‌توانند کمتر از %1$s باشند. + + نوع امضای پشتیبانی نشده + + گواهی نامه غیر قابل اعتماد + + برای محافظت از کیف پول شما، رمز عبور دستگاه مورد نیاز است. به تنظیمات بروید و رمز عبور را فعال کنید. + + رمز عبور دستگاه را فعال کنید + + برای محافظت از کیف پول شما، قفل صفحه نمایش دستگاه مورد نیاز است. به «تنظیمات» > «امنیت» > «قفل صفحه نمایش» بروید و برای ادامه فعال کنید. + + قفل صفحه نمایش غیرفعال شد + + کلید کاغذی شما باید ذخیره شود تا در صورت گم شدن یا تغییر تلفن همراه خود، بتوانید از آن استفاده کنید. اینجا را برای ادامه لمس کنید. + + اقدام لازم است + + کیف پول شما ممکن است ناهمگام باشد. این اغلب می‌تواند با اسکن مجدد بلاک‌چین برطرف شود. + + تراکنش رد شد + + کمک کنید تا Brainwallet را با به اشتراک گذاشتن داده‌های ناشناس خود با ما بهبود دهیم + + اشتراک‌گذاری داده‌های ناشناس + + اینجا را لمس کنید تا Touch ID فعال شود + + برای فعال‌سازی احراز هویت اثر انگشت اینجا ضربه بزنید + + فعال‌سازی تاچ آی‌دی + + فعال‌سازی احراز هویت اثر انگشت + + پین + + کیف پول مغزی به استفاده از یک پین ۶ رقمی ارتقا یافته است. اینجا را برای ارتقا لمس کنید. + + ارتقاء پین + + فعال کردن اعلان‌ها برای دریافت پیام‌های ویژه از Brainwallet در آینده. + + اعلان‌های پوش + + خاموش + + روی + + اعلان‌ها + + کپی شده به کلیپ‌بورد. + + ایمیل + + درخواست مبلغ + + اشتراک گذاری + + پیام متنی + + دریافت کردن + + انجام شد + + بازیابی کیف پول + + بازنشانی پین + + وارد کردن کلید کاغذی + + بازیابی کیف پول مغزی خود را با کلید کاغذی خود انجام دهید. + + کلید کاغذی که وارد کردید نامعتبر است. لطفاً هر کلمه را دوباره بررسی کنید و مجدداً تلاش کنید. + + فلش چپ + + بعدی + + برای اطلاعات بیشتر اینجا ضربه بزنید. + + فلش به سمت راست + + کلید کاغذی را برای کیف پولی که می‌خواهید بازیابی کنید، وارد نمایید. + + برای بازنشانی رمز عبور خود، کلمات کلید کاغذی خود را در کادرهای زیر وارد کنید. + + لطفاً ابتدا یک مبلغ را وارد کنید. + + درخواست مبلغ + + همگام‌سازی + + شما در حین همگام‌سازی قادر به ارسال پول نخواهید بود. + + همگام‌سازی با بلاکچین؟ + + ۲۰-۴۵ دقیقه + + اگر یک تراکنش در شبکه لایت‌کوین به عنوان تکمیل‌شده نشان داده می‌شود اما در کیف پول مغزی شما نمایش داده نمی‌شود. + + شما مکرراً خطایی دریافت می‌کنید که می‌گوید تراکنش شما رد شده است. + + شروع همگام‌سازی + + شما در حین همگام‌سازی با بلاک‌چین قادر به ارسال پول نخواهید بود. + + سینک بلاکچین + + زمان تخمینی + + چه زمانی همگام‌سازی کنیم؟ + + فلاش دوربین + + کامل + + در انتظار + + دریافت شد + + ارسال شد + + تمام ویژگی‌های امنیتی را برای حداکثر محافظت فعال کنید. + + تنها راه دسترسی به لایت‌کوین شما در صورت گم کردن یا ارتقاء تلفن همراه‌تان. + + کلید کاغذی + + محافظت از کیف پول مغزی شما در برابر کاربران غیرمجاز. + + رمز 4 رقمی + + مرکز امنیت + + به راحتی کیف پول مغزی خود را باز کنید و تا سقف مشخصی پول ارسال کنید. + + تاچ آی‌دی + + تأیید هویت اثر انگشت + + مبلغ + + موجودی: %1$s + + دسترسی دوربین را در "تنظیمات" > "برنامه‌ها" > "Brainwallet" > "مجوزها" فعال کنید + + دیوار مغزی اجازه دسترسی به دوربین را ندارد + + برای اجازه دسترسی به دوربین به تنظیمات بروید. + + دیوار مغزی اجازه دسترسی به دوربین را ندارد + + مقصد آدرس خود شماست. شما نمی‌توانید به خودتان ارسال کنید. + + نمی‌توان تراکنش را ایجاد کرد. + + یادداشت + + متن منبع برای ترجمه ارائه نشده است. + + هزینه شبکه: %1$s + + هویت گیرنده وجه تأیید نشده است. + + آدرس مقصد یک آدرس لایت‌کوین معتبر نیست. + + تخته یادداشت حاوی آدرس لایت‌کوین معتبر نیست. + + آدرس نامعتبر + + ارسال در طول اسکن مجدد کامل غیرفعال است. + + درحال بارگذاری درخواست + + لطفاً آدرس گیرنده را وارد کنید. + + لطفاً مبلغی را برای ارسال وارد کنید. + + چسباندن + + نمی‌توان تراکنش را منتشر کرد. + + نتوانست درخواست پرداخت را بارگذاری کند + + اسکن + + ارسال کنید + + ارسال کنید + + یک آدرس لایت کوین وارد کنید + + یک دامنه‌ی .crypto، .wallet، .zil، .nft، .blockchain، +.bitcoin، .coin، .888، .dao، یا .x وارد کنید. + + یا + + جستجو + + آدرس شما حل شد! + + آدرس‌های لایت‌کوین فقط برای یک بار استفاده در نظر گرفته شده‌اند. + + استفاده مجدد، حریم خصوصی را هم برای شما و هم برای گیرنده کاهش می‌دهد و می‌تواند منجر به از دست دادن [دارایی] شود اگر گیرنده به طور مستقیم کنترل آدرس را در اختیار نداشته باشد. + + آدرس قبلاً استفاده شده است + + درباره + + تنظیمات پیشرفته + + نمایش ارز + + پیوستن به دسترسی زودهنگام + + آیا از Brainwallet لذت می‌برید؟ + + وارد کردن کیف پول + + مدیریت کردن + + اعلان‌ها + + نظر خود را برای ما بنویسید + + اشتراک‌گذاری داده‌های ناشناس + + سینک بلاکچین + + تنظیمات + + حد مجاز خرج کردن با تاچ آی‌دی + + حد مجاز هزینه برای احراز هویت اثر انگشت + + کیف پول + + شروع/بازیابی کیف پول دیگر + + کمک کنید تا Brainwallet را با به اشتراک گذاری داده‌های ناشناس خود با ما بهبود دهیم. این شامل هیچ اطلاعات مالی نمی‌شود. ما به حریم خصوصی مالی شما احترام می‌گذاریم. + + اشتراک گذاری داده‌ها؟ + + اشتراک‌گذاری داده‌های ناشناس؟ + + کلید کاغذی را دوباره یادداشت کنید + + کلید کاغذی شما تنها راه برای بازیابی کیف پول مغزی شما است اگر تلفن شما گم، دزدیده، خراب یا ارتقا داده شود. + +ما فهرستی از کلمات را به شما نشان خواهیم داد تا روی یک تکه کاغذ بنویسید و در جای امنی نگه دارید. + + کلید کاغذی را یادداشت کنید + + شما آخرین بار کلید کاغذی خود را در %1$s یادداشت کردید + + امن‌ترین و ایمن‌ترین راه برای استفاده از لایت‌کوین. + + اتصال + + همگام‌سازی + + تلاش مجدد + + همگام‌سازی + + %1$s d + + %1$s h + + %1$s م + + %1$s s + + شما می‌توانید محدودیت خرج کردن Touch ID خود را از %1$s سفارشی کنید. + + شما می‌توانید محدودیت مخارج تأیید اثر انگشت خود را از صفحه محدودیت مخارج تأیید اثر انگشت سفارشی کنید + + شما احراز هویت اثر انگشت را در این دستگاه فعال نکرده‌اید. به تنظیمات -> امنیت بروید تا احراز هویت اثر انگشت را راه‌اندازی کنید. + + احراز هویت اثر انگشت فعال نیست + + از اثر انگشت خود برای باز کردن قفل کیف پول مغزی خود استفاده کنید و تا سقف تعیین شده پول ارسال کنید. + + صفحه محدودیت هزینه تاچ آیدی + + محدودیت هزینه: %1$s (%2$s) + + فعال‌سازی تاچ آیدی برای کیف پول مغزی + + فعال‌سازی احراز هویت اثر انگشت + + تاچ آی‌دی + + تأیید هویت اثر انگشت + + شما Touch ID را روی این دستگاه راه‌اندازی نکرده‌اید. به تنظیمات -> شناسه لمسی و رمز عبور بروید تا آن را اکنون راه‌اندازی کنید. + + تاچ آی‌دی تنظیم نشده است + + همیشه رمز عبور را الزامی کنید + + شما برای ارسال هر تراکنش بیش از حد مجاز خرج کردن خود، و هر ۴۸ ساعت از آخرین باری که رمز ۶ رقمی خود را وارد کرده‌اید، باید رمز ۶ رقمی خود را وارد کنید. + + حد مجاز خرج کردن با تاچ آی‌دی + + محدودیت هزینه تأیید اثر انگشت + + موجودی قابل خرج + + کامل + + موجودی پایانی: %1$s + + نرخ ارز هنگام دریافت: + + نرخ ارز هنگام ارسال: + + (%1$s هزینه) + + نامعتبر + + همین الان + + در حال پیشرفت: %1$s + + در حال پیشرفت: %1$s + + موجودی اولیه: %1$s + + منتظر تایید هستم. برخی از فروشندگان برای تکمیل تراکنش نیاز به تأیید دارند. زمان تخمینی: ۱-۲ ساعت. + + حساب + + مبلغ + + تایید شده در بلاک + + یادداشت + + تراکنش‌های شما اینجا نمایش داده خواهند شد. + + در %1$s + + بیشتر... + + انتقال یافت %1$s + + منتقل شد %1$s + + تایید نشده + + دریافت شد %1$s + + دریافت شد %1$s + + ارسال %1$sشد + + ارسال شد %1$s + + وضعیت + + جزئیات تراکنش + + به %1$s + + شناسه تراکنش لایت کوین + + دریافت شده در این آدرس + + ارسال شده به این آدرس + + معلول تا: %1$s + + آدرس من + + بازنشانی پین + + اسکن + + وارد کردن پین + + سنسور لمسی + + باز کردن قفل کیف پول مغزی شما. + + لطفاً دستگاه اندروید خود را برای ادامه باز کنید. + + باز کردن با تاچ آی‌دی + + مشاهده در بلاک‌چین + + احراز هویت لازم است + + کیف پول باز شد + + فراموش کردن عبارت بازیابی یا پین؟ + + این پین را به خاطر بسپارید. اگر آن را فراموش کنید، نمی‌توانید به لایت‌کوین خود دسترسی داشته باشید. + + رمز شما برای باز کردن قفل کیف پول مغزی شما و ارسال پول استفاده خواهد شد. + + تنظیم پین + + وارد کردن مجدد پین + + پین فعلی خود را وارد کنید. + + پین جدید خود را وارد کنید. + + پین جدید خود را دوباره وارد کنید. + + متأسفانه، نمی‌توان پین را به‌روزرسانی کرد. + + خطای به‌روزرسانی پین + + بروزرسانی پین + + آدرس‌های کیف پول به کلیپ‌بورد کپی شوند؟ + + اجازه کپی آدرس کیف پول در کلیپ‌بورد + + کپی آدرس‌های کیف پول + + کپی + + لطفاً برای تأیید این تراکنش، رمز عبور خود را وارد کنید. + + لطفاً برای ادامه، پین خود را وارد کنید. + + رمز مورد نیاز است + + تأیید این تراکنش + + برنامه Brainwallet آیفون را باز کنید تا کیف پول خود را راه‌اندازی کنید. + + رد کردن + + خطایی در بارگذاری محتوا رخ داد. لطفاً دوباره تلاش کنید. + + در حال به‌روزرسانی... + + برین‌والت به‌تازگی به‌روزرسانی شده است! \nاگر به کمک نیاز دارید، دنبال علامت (؟) در گوشه بالا سمت راست اکثر صفحات بگردید. + + به کیف پول مغزی خوش آمدید! + + آیا مطمئن هستید که می‌خواهید این کیف پول را حذف کنید؟ + + پاک کردن کیف پول؟ + + عدم موفقیت در پاک کردن کیف پول. + + شکست خورده + + برای شروع یک کیف پول جدید یا بازیابی یک کیف پول موجود، ابتدا باید کیف پولی که در حال حاضر نصب شده است را پاک کنید. برای ادامه، کلید کاغذی کیف پول فعلی را وارد کنید. + + شروع یا بازیابی کیف پول دیگر به شما امکان می‌دهد تا به یک Brainwallet متفاوت در این دستگاه دسترسی داشته باشید و آن را مدیریت کنید. + + کیف پول فعلی شما از این دستگاه حذف خواهد شد. اگر می‌خواهید در آینده آن را بازیابی کنید، باید کلید کاغذی خود را وارد کنید. + + شروع یا بازیابی کیف پول دیگر + + پاک کردن + + پاک کردن... + + هر کلمه را به ترتیب بنویسید و آن را در مکانی امن نگهداری کنید. + + بعدی + + قبلی + + %1$dاز%2$d + زمان پردازش: این تراکنش‌ها %1$s دقیقه برای پردازش زمان خواهند برد. + آدرس: + لوکس + ۲.۵ - ۵+ دقیقه + این گزینه تقریباً تضمین می‌کند که تراکنش شما پذیرفته می‌شود، اگرچه شما هزینه بیشتری پرداخت می‌کنید. + + مون‌پی + «• خرید LTC با جفت‌های متعدد ارز فیات +• پرداخت با روش‌های متنوع +• ارائه‌دهنده پرداخت جهانی» + بیت‌ریفیل + «• خرید کارت‌های هدیه +• شارژ تلفن‌های پیش‌پرداخت +• استیم، آمازون، Hotels.com +• در ۱۷۰ کشور قابل استفاده است» + دلار استرالیا + پوند استرلینگ + هنگ کنگ دلار + ریال ایران + روبل + اس‌جی‌دی + کد + یورو + ین ژاپن + دلار آمریکا + تاریخ + + تعادل + 1 LTC = %1$s + ارزش فعلی LTC در %1$s + زبان‌ها + آیا مطمئن هستید که می‌خواهید زبان را به انگلیسی تغییر دهید؟ + بستن + + اینستاگرام + ۱: %s ۲: %s ۳: %s ۴: %s \\n۵: %s ۶: %s ۷: %s ۸: %s%s \\n۹: %s ۱۰: %s ۱۱: %s ۱۲: %s %s + نمایش + نمایش عبارت بازیابی من + ترجیح همگام‌سازی: %1$s مثبت‌های کاذب + حریم خصوصی کم (حدود ۴۵ دقیقه) + نیمه خصوصی (~۶۰ دقیقه) + ناشناس (~77 دقیقه) + مهم: برنامه برای اجازه دادن به آدرس‌های 1ltc همگام‌سازی خواهد شد. منتظر بمانید ~1 ساعت برای همگام‌سازی! + + چیزی را از دست ندهید! + بستن + برای دریافت اطلاعات درباره به‌روزرسانی‌ها و مسابقات از تیم Brainwallet ثبت‌نام کنید! پذیرش اعلان‌ها برای دریافت اخبار زنده، قیمت و اطلاعات بازار! + نه، ممنون! + خدمات + هزینه‌ها: + عمومی + اخبار لایت کوین + بروزرسانی کیف پول مغزی + لغو + باشه + لطفاً اجازه اعلان را صادر کنید + اطلاعات مجوز + مجوز اعلان اعطا شد + + + بازگشت + کلمات بذر شما + "فقط برای تو. \n این است" کلید خصوصی "که به شما اجازه می‌دهد ارسال کنید." + بلاک‌چین: لایت‌کوین + من آن را روی کاغذ یا فلز ذخیره کردم + شما ذخیره‌اش کردی، درسته؟ + اثباتش کن! +کلمات را به ترتیب صحیح بکشید. + بازی و همگام‌سازی + آماده‌اید؟ + برای شما انجام می‌دهم. لطفاً انجامش بده + تنها + یک قلم، کاغذ و ۵ دقیقه بردارید + تنظیم رمز عبور برنامه + یک رمز عبور را برای باز کردن قفل کیف پول مغزی خود انتخاب کنید + قفل تلفن نیست! + متفاوتش کن. خنک کنید. + استفاده از بیومتریک + کلیدهای خود را ذخیره کردید. + سطح بعدی را در هم بکوب. + روی یک کلمه ضربه بزنید و آن را به محل مورد نظر بکشید + شارژ کنم؟ + الان ذهن شما خالی است... + دریافت لایت کوین در ۵ دقیقه + لایت کوین بگیرید! + شاید بعداً. + رد کردن + بازیابی قدرت خود + می‌توانی به جایی که از آن شروع کردی برگردی + بازیابی کیف پول مغزی من + صاف + حدس نزن.\n\nبرای این کار به \n۵,۴۴۴,۵۱۷,۹۵۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰, تلاش نیاز دارید. + تایید + فراموش نکردی، مگه نه؟ وارد کنید دوباره. یا، به عقب برگردید تا از ابتدا شروع کنید. + آماده + بازیابی + رمز عبور نادرست، لطفاً دوباره تلاش کنید! + فلش به سمت پایین و چپ + لوگو + تغییر حالت تاریک + قفل-حالت-تغییر + امنیت + زبان + ارز + بازی‌ها + پشتیبانی + رسانه‌های اجتماعی + قفل + باز کردن + موضوع + نسخه برنامه: + همگام‌سازی فراداده‌ها: + همگام‌سازی + مدت همگام‌سازی: >۲۰ دقیقه + بازی %1$d: + %s + %s + %s + %s + پین + عبارت بازیابی + عبارت کیف پول مغزی + اشتراک‌گذاری داده‌های تحلیلی + بروزرسانی پین + نمایش + خرید LTC + با پشتیبانی مون‌پی + در حال بارگذاری... + کارمزد شبکه (به ازای هر کیلوبایت): مقدار بالاتر به معنای تکمیل سریع‌تر تراکنش است + بالا + متوسط + کم + مبلغ کمتر از حد مجاز (%f) است + مقدار از حد مجاز (%f) بیشتر است + خرید لایت کوین + به آدرس LTC شما واریز شود: + خرید با مون‌پی + آدرس جدید + خرید / دریافت + سفارشی + بازنشانی / شروع مجدد + \ No newline at end of file diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml new file mode 100644 index 00000000..4e8aa15c --- /dev/null +++ b/app/src/main/res/values-pa/strings.xml @@ -0,0 +1,846 @@ + + + + + ویب سائٹ + + + + پرائیویسی پالیسی + + + استعمال کی شرائط + + متعلق + + ٹوئٹر + + بند کرو + + سپورٹ سینٹر + + + + لگدا اے کہ تُسی تیسری پارٹی دا کی بورڈ استعمال کر رہے او، جو تُہاڈا لکھیا ہویا ریکارڈ کر سکدا اے تے تُہاڈی پیپر کی چُرا سکدا اے۔ مہربانی کرکے اضافی تحفظ کے لیے ڈیفالٹ اینڈرائیڈ کی بورڈ پر سوئچ کریں۔ + + غلطی + + تہاڈے اینڈرائیڈ او ایس کی اسٹور وچ کوئی مسئلہ ہے، مہربانی کرکے support.brainwallet.co نال رابطہ کرو۔ + + تہاڈا برین والٹ انکرپٹڈ ڈیٹا حال ہی وچ غیر مؤثر ہو گیا سی کیونجے تہانڈا اینڈرائیڈ لاک سکرین غیر فعال کر دتا گیا سی۔ + + اینڈرائیڈ کی اسٹور خرابی + + کوئی انٹرنیٹ کنکشن نہیں ملا۔ اپنا کنکشن چیک کرو تے دوبارہ کوشش کرو۔ + + انتباہ + + پتے کاپی ہو گئے ہیں۔ + + تمام والٹ ایڈریس کامیابی سے کاپی ہو گئے ہیں۔ + + پیپر کی سیٹ + + کمال! + + پن سیٹ + + بھیجنا ناکام ہوگیا۔ + + تصدیق بھیجو + + پیسے بھیج دیے گئے! + + فنگرپرنٹ تسلیم شدہ ہے۔ + + JSON سیریلائزیشن خرابی + + پرس تیار نہیں ہے۔ + + اے پی آئی ٹوکن حاصل کرنے میں ناکام + + منسوخ کریں۔ + + نظر انداز کریں۔ + + مینؤں + + نہیں + + ٹھیک ہے۔ + + وصول کرنا + + بھیجیں + + ترتیبات + + جمع کرو + + جی ہاں + + بھیجنے والی رقم: + + نیٹ ورک فیس: + + نیٹ ورک + + پروسسنگ وقت: اس لین دین کے مکمل ہونے کی پیش گوئی %1$s میں کی گئی ہے۔ + + بھیجو + + تصدیق + + نو + + کل لاگت: + + یقینی بنانے کے لیے کہ سب کچھ صحیح طریقے سے لکھا گیا ہے، براہ کرم اپنے پیپر کی کی سے مندرجہ ذیل الفاظ درج کریں۔ + + لفظ #%1$s + + لائٹ کوائن ڈسپلے یونٹ + + تبادلہ ریٹ + + + + برین والٹ کو آپ کے اینڈرائیڈ کے ورژن میں ایک بگ کی وجہ سے تصدیق نہیں کی جا سکتی۔ [مزید معلومات کے لیے یہاں ٹیپ کریں۔] + + یہ ڈیوائس پیغامات بھیجنے کے لیے ترتیب نہیں دی گئی۔ + + پیغام رسانی دستیاب نہیں ہے۔ + + فنگر پرنٹ تسلیم نہیں ہوا۔ براہ کرم دوبارہ کوشش کریں۔ + + معیشت + + 10+ منٹ + + یہ آپشن وقت حساس لین دین کے لیے تجویز نہیں کی جاتی۔ + + متوقع ترسیل: %1$s + + باقاعدہ + + ۲.۵ - ۵+ منٹ + + پروسيسنگ سپیڈ + + پرائیویٹ کی بیلنس چیک کر رہے ہیں... + + کیا آپ اس پرائیویٹ کی سے %1$s کو اپنی والٹ میں بھیجنا چاہتے ہیں؟ لائٹ کوائن نیٹ ورک کو %2$s کی فیس موصول ہوگی۔ + + یہ نجی کلید پہلے ہی آپ کے والٹ میں موجود ہے۔ + + یہ نجی کلید خالی ہے۔ + + لین دین دی فیس اس نجی کلید اُتے موجود فنڈز توں زیادہ خرچ ہووے گی۔ + + نجی کلید درست نہیں ہے۔ + + ٹرانزیکشن سائن کرنے میں غلطی + + درآمد + + والٹ درآمد کرنا + + پرس درآمد کرنا ہے۔ + + ایک والٹ کو درآمد کرنے سے آپ کے دوسرے والٹ سے سارا پیسہ ایک ہی لین دین کے ذریعے آپ کے برین والٹ میں منتقل ہو جاتا ہے۔ + + یہ نجی کلید پاس ورڈ سے محفوظ ہے۔ + + پاسورڈ + + + پرائیویٹ کی سکین کریں + + کامیابی + + والٹ کامیابی سے درآمد ہو گیا۔ + + والٹ درآمد کرو + + کلیدی کھولنا + + پرس درآمد کرنے سے لین دین کی تاریخ یا دیگر تفصیلات شامل نہیں ہوتیں۔ + + غلط پاسورڈ، براہ کرم دوبارہ کوشش کریں۔ + + نظر انداز کریں + + ڈیوائس سیکیورٹی متاثر\n کوئی بھی \'جیل بریک\' ایپ کی چین ڈیٹا تک رسائی حاصل کر سکتی ہے اور آپ کے لائٹ کوائن چرا سکتی ہے! اس والٹ کو فوراً صاف کریں اور کسی محفوظ ڈیوائس پر بحال کریں۔ + + ڈیوائس سیکیورٹی متاثر\n کوئی بھی \'جیلبریک\' ایپ کی چین ڈیٹا تک رسائی حاصل کر سکتی ہے اور آپ کے لائٹ کوائن چرا سکتی ہے۔ براہ کرم صرف برین والٹ کو غیر جیل بریک شدہ ڈیوائس پر استعمال کریں۔ + + خبردار + + لوکیشن سروسز غیر فعال ہیں۔ + + برین والٹ کو مقام کی خدمات تک رسائی کی اجازت نہیں ہے۔ + + تُسیں اپنا والٹ %1$s اُتے بنایا۔ + + تہاڈے والٹ دا ناں صرف تہاڈی اکاؤنٹ ٹرانزیکشن ہسٹری وچ ہی نظر آندا اے تے کسے ہور نوں نظر نہیں آ سکدا۔ + + پرس دا ناں + + پرس سنبھالیں + + خریدیں۔ + + لاک والیٹ + + سیکیورٹی سینٹر + + ترتیبات + + گاہک کی حمایت + + نواں والٹ بناؤ + + مینؤ + + والٹ بحال کریں + + خودکار موڈ پر سوئچ کریں۔ + + مربوط + + نوڈ آئی پی ایڈریس اور پورٹ درج کریں (اختیاری) + + نوڈ داخل کریں۔ + + دستی موڈ پر سوئچ کریں۔ + + موجودہ پرائمری نوڈ + + کنیکٹڈ نہیں ہے۔ + + نوڈ کنکشن کی حالت + + لائٹ کوائن نوڈز + + ناقص ادائیگی کی درخواست + + غیر معاون یا خراب شدہ دستاویز + + گمشدہ سرٹیفکیٹ + + درخواست کی میعاد ختم ہو گئی ہے۔ + + ادائیگی نہیں ہو سکی۔ + + لائٹ کوائن ادائیگیاں %1$s سے کم نہیں ہو سکتیں۔ + + لائٹ کوائن ٹرانزیکشن آؤٹ پُٹس %1$s سے کم نہیں ہو سکتے۔ + + غیر معاون دستخط قسم + + غیر معتبر سرٹیفکیٹ + + آپ کے والٹ کی حفاظت کے لیے ایک ڈیوائس پاسکوڈ کی ضرورت ہے۔ سیٹنگز وچ جاؤ تے پاسکوڈ آن کرو۔ + + ڈیوائس پاسکوڈ آن کرو + + آپ کے بٹوے کی حفاظت کے لیے ایک ڈیوائس سکرین لاک کی ضرورت ہے۔ "سیٹنگز" > "سیکیورٹی" > "سکرین لاک" پر جائیں اور جاری رکھنے کے لیے فعال کریں۔ + + سکرین لاک غیر فعال کر دیا گیا ہے۔ + + تہاڈا پیپر کی محفوظ رکھنا لازمی ہے جے کدے تہاڈا فون کھو جائے یا تبدیل ہو جائے۔ یہاں جاری رکھنے کے لیے ٹیپ کریں۔ + + عمل درکار ہے + + تُہاڈا والٹ شاید ہم آہنگی وچ نہیں۔ یہ اکثر بلاک چین کو دوبارہ سکین کر کے ٹھیک کیا جا سکتا ہے۔ + + لین دین مسترد کر دیا گیا ہے۔ + + برین والٹ کو بہتر بنانے میں مدد کریں اور اپنا گمنام ڈیٹا ہمارے ساتھ شیئر کریں۔ + + گمنام ڈیٹا شیئر کرو + + یہاں ٹیپ کریں تاکہ ٹچ آئی ڈی فعال ہو سکے۔ + + یہاں تھپتھپائیں تاکہ فنگر پرنٹ تصدیق فعال ہو سکے۔ + + ٹچ آئی ڈی فعال کریں۔ + + فنگرپرنٹ تصدیق کو فعال کریں۔ + + پن + + برین والٹ نے 6-عددی پن کا استعمال اپ گریڈ کر لیا ہے۔ یہاں اپگریڈ کرنے کے لیے ٹیپ کریں۔ + + پن اپگریڈ کریں + + نوٹیفکیشنز آن کرو تاکہ مستقبل وچ برین والٹ توں خاص پیغامات حاصل کر سکو۔ + + پُش نوٹیفکیشنز + + بند + + تے + + اطلاعات + + کلپ بورڈ وچ نقل کیتا گیا۔ + + ای میل + + رقم دی درخواست کرو + + شئیر + + پیغام + + وصول کرو + + مکمل ہو گیا۔ + + والٹ بحال کریں + + پن کو دوبارہ سیٹ کریں + + پیپر کی کلید درج کریں۔ + + اپنے برین والٹ کو اپنے پیپر کی کے ساتھ بحال کریں۔ + + تُسیں داخل کیتا ہویا پیپر کلید غلط ہے۔ براہ کرم ہر لفظ کو دوبارہ چیک کریں اور دوبارہ کوشش کریں۔ + + بائیں تیر + + اگلا + + یہاں مزید معلومات کے لیے ٹیپ کریں۔ + + دائیں تیر + + براہ کرم اُس والٹ کے لیے پیپر کی درج کریں جسے آپ بحال کرنا چاہتے ہیں۔ + + اپنا پن ری سیٹ کرنے کے لیے، نیچے دیے گئے خانوں میں اپنے پیپر کی کی الفاظ درج کریں۔ + + مہربانی کرکے پہلے ایک رقم درج کریں۔ + + رقم دی درخواست کرو + + ہم آہنگی + + تُسیں پیسے نہیں بھیج سکدے جدو تک ہم آہنگی ہو رہی ہے۔ + + بلاک چین کے ساتھ ہم آہنگی؟ + + ۲۰-۴۵ منٹ + + اگر لائٹ کوائن نیٹ ورک\'تے کوئی لین دین مکمل ہو کے وکھائی دیوے پر تُہاڈے برین والٹ \'چ نہ ہووے۔ + + تُسیں بار بار اِک غلطی دا سامنا کر رہے ہو کہ تُہاڈی ٹرانزیکشن رد کر دِتی گئی اے۔ + + آغاز ہم آہنگی + + تُسیں بلاک چین نال ہم آہنگی کرن دوران پیسے نہیں بھیج سکدے۔ + + سنگ بلاک چین + + تخمینہ شدہ وقت + + کدوں ہم آہنگ کرنا ہے؟ + + کیمرہ فلیش + + مکمل + + زیر التواء + + موصول ہويا + + بھیجیا گیا + + تمام سیکیورٹی خصوصیات کو زیادہ سے زیادہ تحفظ کے لیے فعال کریں۔ + + اگر آپ اپنا فون کھو دیتے ہیں یا اپ گریڈ کرتے ہیں تو اپنے لائٹ کوائن تک رسائی حاصل کرنے کا واحد طریقہ۔ + + پیپر کیی + + آپ کے برین والٹ کو غیر مجاز صارفین سے محفوظ رکھتا ہے۔ + + ۴-عددی پن کوڈ + + سیکیورٹی سینٹر + + آسانی سے اپنا برین والٹ کھولیں اور مقررہ حد تک پیسے بھیجیں۔ + + ٹچ آئی ڈی + + فنگرپرنٹ تصدیق + + رقم + + توازن: %1$s + + "سیٹنگز" > "ایپس" > "برین والٹ" > "پرمیشرز" وچ کیمرہ رسائی دی اجازت دو۔ + + برین والٹ کو کیمرے تک رسائی کی اجازت نہیں ہے۔ + + کیمرہ رسائی کی اجازت دینے کے لیے سیٹنگز پر جائیں۔ + + برین والٹ کو کیمرے تک رسائی کی اجازت نہیں ہے۔ + + منزل مقصود آپنا پتہ ہے۔ تُسیں اپنے آپ نوں نہیں بھیج سکدے۔ + + لین دین پیدا نہیں ہو سکی۔ + + یادداشت + + پیسٹ بورڈ خالی ہے۔ + + نیٹ ورک فیس: %1$s + + ادائیگی کنندہ کی شناخت تصدیق شدہ نہیں ہے۔ + + منزل دا پتہ ایک درست لائٹ کوائن پتہ نہیں ہے۔ + + پیسٹ بورڈ وچ کوئی صحیح لائٹ کوائن پتہ موجود نہیں۔ + + غلط پتہ + + مکمل دوبارہ سکیننگ کے دوران بھیجنا غیر فعال ہے۔ + + درخواست لوڈ ہو رہی ہے۔ + + براہ کرم وصول کنندہ کا پتہ درج کریں۔ + + براہ کرم بھیجنے کے لیے رقم درج کریں۔ + + پیسٹ + + لین دین شائع نہیں ہو سکی۔ + + ادائیگی کی درخواست لوڈ نہیں ہو سکی۔ + + سکین + + بھیجو + + بھیجیں + + لائٹ کوائن پتہ درج کریں۔ + + .کرپٹو، .والٹ، .زیل، .این ایف ٹی، .بلاکچین، .بٹکوائن، .کوائن، .۸۸۸، .ڈاؤ، یا .ایکس ڈومین درج کریں۔ + + یا + + تلاش + + تہاڈا پتہ حل ہو گیا! + + لائٹ کوائن پتہ جات صرف ایک بار استعمال کے لیے بنائے گئے ہیں۔ + + دوبارہ استعمال کرنا آپ اور وصول کنندہ دونوں کے لیے پرائیویسی کو کم کرتا ہے اور اگر وصول کنندہ پتہ کو براہ راست کنٹرول نہیں کرتا تو نقصان کا باعث بن سکتا ہے۔ + + پتہ پہلے ہی استعمال ہو چکا ہے۔ + + متعلق + + ترقی یافتہ ترتیبات + + کرنسی دکھاؤ + + ابتدائی رسائی میں شامل ہوں۔ + + کیا تسی برین والٹ دا لطف لے رہے ہو؟ + + والٹ درآمد کرو + + مینج + + اطلاعات + + ساڈے لئی ریویو چھوڑو + + گمنام ڈیٹا شیئر کرو + + سنگ بلاک چین + + سیٹنگز + + ٹچ آئی ڈی خرچ کرنے دی حد + + فنگر پرنٹ تصدیق خرچ کرنے دی حد + + پرس + + شروع/دوسرا والٹ بحال کریں + + برین والٹ کو بہتر بنانے میں مدد کریں اور اپنا گمنام ڈیٹا ہمارے ساتھ شیئر کریں۔ یہ کسی مالی معلومات کو شامل نہیں کرتا۔ اسیٰ توہاڈی مالی رازداری دی عزت کردے آں۔ + + ڈیٹا شیئر کرو؟ + + گمنام ڈیٹا شیئر کرو؟ + + کاغذ دی چابی دوبارہ لکھو + + تہاڈا پیپر کی واحد طریقہ ہے جڑا تہاڈی برین والٹ نوں بحال کر سکدا اے جے کر تہاڈا فون کھو جائے، چوری ہو جائے، ٹٹ جائے، یا اپگریڈ ہو جائے۔ + +اسی تہانوں کچھ الفاظ دی لسٹ دکھاواں گے جِنہاں نوں تسی کاغذ اُتے لکھ کے محفوظ رکھنا اے۔ + + کاغذ دی چابی لکھو + + تُسیں آخری واری اپنا پیپر کی %1$s اُتے لکھیا۔ + + لائٹ کوائن استعمال کرنے کا سب سے محفوظ اور محفوظ طریقہ۔ + + کنیکٹ کرنا + + ہم آہنگی + + دوبارہ کوشش کریں۔ + + ہم آہنگی + + %1$s د + + %1$s ہ + + %1$s م + + %1$s س + + تُسیں اپنے ٹچ آئی ڈی خرچ دی حد نوں %1$s توں حسب ضرورت تبدیل کر سکدے ہو۔ + + تُسیں فنگرپرنٹ اتھارائزیشن سپینڈنگ لِمٹ سکرین توں اپنی فنگرپرنٹ آتھنٹیکیشن خرچ دی حد نوں اپنی مرضی دے مطابق بنا سکدے ہو۔ + + تُسیں اس ڈیوائس اُتے فنگرپرنٹ تصدیق فعال نہیں کیتی۔ سیٹنگز -> سیکیورٹی پر جائیں تاکہ فنگر پرنٹ تصدیق کو سیٹ اپ کریں۔ + + فنگر پرنٹ تصدیق فعال نہیں ہے۔ + + اپنی برین والٹ کو ان لاک کرنے اور مقررہ حد تک پیسے بھیجنے کے لیے اپنی فنگر پرنٹ کا استعمال کریں۔ + + ٹچ آئی ڈی خرچ کرنے کی حد سکرین + + خرچ دی حد: %1$s (%2$s) + + برین والٹ لئی ٹچ آئی ڈی فعال کرو۔ + + فنگر پرنٹ تصدیق کو فعال کریں۔ + + ٹچ آئی ڈی + + فنگرپرنٹ تصدیق + + تُسیں اس ڈیوائس اُتے ٹچ آئی ڈی سیٹ نئیں کیتا۔ سیٹنگز->ٹچ آئی ڈی & پاسکوڈ پر جا کر اسے ابھی سیٹ اپ کریں۔ + + ٹچ آئی ڈی سیٹ اپ نہیں ہوئی + + ہمیشہ پاسکوڈ کی ضرورت ہے۔ + + تُسیں کسے وی خرچ دی حد توں وادھ لین دین بھیجݨ لئی اپنا 6-عددی پن درج کرݨ لئی پُچھے جاوگے، تے ہر 48 کنٹے بعد جدو تُسیں آخری واری اپنا 6-عددی پن درج کیتا سی۔ + + ٹچ آئی ڈی خرچ کرنے دی حد + + فنگرپرنٹ اجازت خرچ کرنے دی حد + + خرچ کرنے کے لئے دستیاب ہے۔ + + مکمل + + آخری بیلنس: %1$s + + موصول ہونے پر تبادلہ ریٹ: + + بھیجتے وقت تبادلہ ریٹ: + + (%1$sفیس) + + غلط + + ابھی ہال ہی میں + + جاری ہے: %1$s + + جاری ہے: %1$s + + آغازي بیلنس: %1$s + + تصدیق ہونے کا انتظار ہے۔ کچھ تاجران کو لین دین مکمل کرنے کے لیے تصدیق کی ضرورت ہوتی ہے۔ تخمینہ شدہ وقت: 1-2 گھنٹے۔ + + کھاتہ + + رقم + + تصدیق شدہ بلاک میں + + یادداشت + + تہاڈیاں لین دین اتھے نظر آون گیاں۔ + + پر%1$s + + زیادہ... + + منتقل ہو گیا %1$s + + منتقل ہوگیا %1$s + + تصدیق نہیں ہوئی + + موصول ہو گیا %1$s + + موصول ہويا %1$s + + بھیجیا گیا %1$s + + بھیجیا گیا %1$s + + حالت + + ٹرانزیکشن کی تفصیلات + + نو %1$s + + لائٹ کوائن ٹرانزیکشن آئی ڈی + + اس پتے پر موصول ہوا۔ + + اس پتے پر بھیجا گیا + + معذور ہے تآنکہ: %1$s + + میرا پتہ + + پن کو دوبارہ مقرر کریں + + سکین + + پن درج کریں۔ + + ٹچ سینسر + + اپنا برین والٹ کھولیں۔ + + براہ کرم جاری رکھنے کے لیے اپنی اینڈرائیڈ ڈیوائس کو ان لاک کریں۔ + + ٹچ آئی ڈی نال کھولو۔ + + بلاک چین پر دیکھیں + + تصدیق درکار ہے۔ + + پرس کھل گیا + + اپنا سیڈ فریز یا پن بھول گئے؟ + + یاد رکھو اس پن کو۔ اگر تُسیں ایہہ بھُل جاندے او، تے تُسیں اپنی لائٹ کوائن تک رسائی حاصل نہیں کر سکوں گے۔ + + تہاڈا پن کوڈ توہاڈی برین والٹ کھولن لئی تے پیسے بھیجن لئی استعمال ہووے گا۔ + + پن سیٹ کرو + + پن کو دوبارہ درج کریں۔ + + اپنا موجودہ پن درج کریں۔ + + اپنا نواں پن درج کرو۔ + + اپنا نواں پن دوبارہ درج کرو۔ + + معاف کرنا، پن اپڈیٹ نہیں ہو سکی۔ + + پن کو اپڈیٹ کرنے میں غلطی + + پن کو اپڈیٹ کریں + + والٹ پتہ جات کلپ بورڈ پر کاپی کریں؟ + + کلپ بورڈ پر والٹ ایڈریس کاپی کرنے کی اجازت دیں۔ + + والٹ پتہ جات کاپی کرو + + نقل کریں۔ + + براہ کرم اس لین دین کی اجازت دینے کے لیے اپنا پن درج کریں۔ + + براہ کرم جاری رکھنے کے لیے اپنا پن درج کریں۔ + + پن درکار ہے۔ + + اس لین دین کی اجازت دیں۔ + + برین والٹ آئی فون ایپ کھولیں تاکہ آپ اپنی والٹ سیٹ اپ کر سکیں۔ + + برخاست کریں۔ + + مواد لوڈ کرنے میں ایک غلطی ہوئی۔ براہ کرم دوبارہ کوشش کریں۔ + + اپ ڈیٹ ہو رہا ہے... + + برین والٹ نے ابھی تازہ کاری کی ہے! \nاگر آپ کو مدد کی ضرورت ہے، تو زیادہ تر سکرینوں کے اوپر دائیں جانب موجود (?) کو دیکھیں۔ + + برین والٹ میں خوش آمدید! + + کیا تسی یقین نال ایہہ والٹ حذف کرنا چوندے او؟ + + پرس صاف کرو؟ + + پرس صاف کرنے میں ناکام۔ + + ناکام ہو گیا۔ + + نواں والٹ شروع کرنے یا موجودہ والٹ بحال کرنے لئی، تہانوں پہلاں اوس والٹ نوں مٹانا پوے گا جو اس وقت انسٹال ہے۔ جاری رکھنے کے لیے، موجودہ والٹ کی پیپر کی درج کریں۔ + + کسی ہور والٹ نوں شروع کرنا یا بحال کرنا تہاڈے لئی اس ڈیوائس اُتے اک مختلف برین والٹ تک رسائی حاصل کرنا تے اس نوں منیج کرنا ممکن بناندا اے۔ + + آپ کا موجودہ والٹ اس ڈیوائس سے ہٹا دیا جائے گا۔ اگر تسی اسے مستقبل وچ بحال کرنا چاهندے ہو، تاں تہانوں اپنا پیپر کی داخل کرنا پوے گا۔ + + دوسرا والٹ شروع یا بحال کریں + + پونچھو + + صاف کرنا... + + ہر لفظ کو ترتیب سے لکھو اور اسے محفوظ جگہ پر رکھو۔ + + اگلا + + پچھلا + + ت%1$dصویر%2$d 1 دی تصویر 2 نال موازنہ + پروسسنگ وقت: ایہہ لین دین %1$s منٹ لیں گے پروسس کرنے لئی۔ + پتہ: + عیش + ۲.۵ - ۵+ منٹ + یہ آپشن عملی طور پر آپ کے لین دین کی منظوری کی ضمانت دیتا ہے حالانکہ آپ ایک اضافی قیمت ادا کر رہے ہیں۔ + + مون پے + "• ایل ٹی سی کو کئی فیاٹ جوڑوں کے ساتھ خریدیں\n• متعدد طریقوں سے ادائیگی کریں\n• عالمی ادائیگی فراہم کنندہ" + بِٹریفِل + "• تحفے کے کارڈ خریدیں\n• پری پیڈ فونز کو ریفل کریں\n• سٹیم، ایمیزون، ہوٹلز ڈاٹ کام\n• 170 ممالک میں کام کرتا ہے" + اے یو ڈی + پاؤنڈ سٹرلنگ + ایچ کے ڈی + آئی ڈی آر + رُوب + ایس جی ڈی + سی اے ڈی + یورو + جے پی وائی + امریکی ڈالر + تاریخ + + توازن + 1 ایل ٹی سی = %1$s + موجودہ ایل ٹی سی قیمت %1$s میں + زبانیں + کیا آپ واقعی زبان کو انگریزی میں تبدیل کرنا چاہتے ہیں؟ + بند کرو + + انسٹاگرام + 1: %s 2: %s 3: %s 4: %s \\n5: %s 6: %s 7: %s 8: %s%s \\n9: %s 10: %s 11: %s 12: %s %s + شو + میری سیڈ فریس دکھاؤ + ترجیح ہم آہنگی: %1$s غلط مثبتیاں + کم پرائیویسی (تقریباً 45 منٹ) + نیم نجی (تقریباً 60 منٹ) + گمنام (تقریباً 77 منٹ) + اہم: ایپ 1ltc پتوں کو ہم آہنگ کرنے کی اجازت دے گی۔ تقریباً 1 گھنٹہ انتظار کریں تاکہ ہم آہنگی ہو سکے! + + کچھ وی نہ چھڈو! + بند کرو + برین والٹ ٹیم کی طرف سے اپڈیٹس اور مقابلوں کے بارے میں سننے کے لیے سائن اپ کریں! نوٹیفکیشنز قبول کرو تاکہ آپ کو لائیو خبریں، قیمتیں، اور مارکیٹ کی معلومات مل سکیں! + نہیں، شکریہ! + سروس + فیس: + جنرل + لائٹ کوائن خبریں + برین والٹ اپڈیٹ + منسوخ کریں۔ + ٹھیک ہے۔ + براہ کرم اطلاع کی اجازت دیں۔ + اجازت کی معلومات + اطلاع دی اجازت دیتی گئی ہے۔ + + + واپس + تہاڈے بیج دے الفاظ + "صرف آپ کے لئے۔ +یہ ہے" نجی کلید جو تہانوں پیغام بھیجنے دی اجازت دیندا اے۔ + بلاک چین: لائٹ کوائن + میں نے اِسے کاغذ یا دھات پر محفوظ کر لیا۔ + تُسیں اِس نُوں بچا لیا، ٹھیک؟ + ثابت کرو! \nالفاظ نوں صحیح ترتیب وچ کھچو۔ + گیم اینڈ سنک + تیار؟ + اے اپنے لئی کرو۔ براہ کرم یہ کریں۔ + اکیلا + قلم، کاغذ تے 5 منٹ لَے لو۔ + ایپ پاسکوڈ سیٹ کریں + اپنے برین والٹ کو ان لاک کرنے کے لیے ایک پاس کوڈ منتخب کریں۔ + فون لاک کوڈ نہیں! + اسے مختلف بناؤ۔ اسنوں ٹھنڈا بنا دو۔ + بایومیٹرکس کا استعمال کریں۔ + تُسیں اپنی چابیاں بچا لیاں۔ + اگلے درجے کو فتح کرو۔ + الفاظ نوں تھپ تھپاؤ تے اس نوں اپنی جگہ تے کھسکاؤ۔ + ریچارج؟ + اس وقت آپ کا دماغ خالی ہے... + 5 منٹ وچ لائٹ کوائن حاصل کرو + لائٹ کوائن حاصل کرو! + شاید بعد وچ۔ + چھڈو + اپنی طاقت بحال کرو + تُسیں اُتھے واپس جا سکتے ہو جتھے تُسیں شُروع کیتا سی۔ + میرا برین والٹ بحال کرو۔ + صاف + اندازہ نہ لگائیں۔ + +تُہانوں 5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000 کوششاں لگن گیاں۔ + تصدیق کریں۔ + تُسیں بھلّے تاں نئیں؟ اسے دوبارہ داخل کریں۔ یا، واپس جا کر دوبارہ شروع کرو۔ + تیار + بحال کرو + غلط پاسکوڈ، براہ کرم دوبارہ کوشش کریں! + نیچے-کھبے-تیر + لوگو + ٹوگل ڈارک موڈ + ٹوگل-لاک-موڈ + تحفظ + زبان + کرنسی + کھیلاں + مدد + سوشل میڈیا + تالا + ان لاک + موضوع + ایپ ورژن: + میٹا ڈیٹا ہم آہنگ کریں: + مزامنت + ہم آہنگی کا دورانیہ: >20 منٹ + کھیل %1$d: + %s + %s + %s + %s + پن + بیج عبارت + برین والٹ فریس + تجزیاتی ڈیٹا شئیر کریں۔ + پن کو اپ ڈیٹ کریں + شوو + ایل ٹی سی خریدیں۔ + مون پے کے ذریعے چلایا گیا + لوڈ ہو رہا ہے... + نیٹ ورک فیس (فی کلو بائٹ): زیادہ قیمت کا مطلب ہے کہ لین دین جلدی مکمل ہو جاتا ہے۔ + اوپر + درمیانہ + کم + رقم کم از کم حد (%f) سے نیچے ہے۔ + رقم زیادہ سے زیادہ حد (%f) سے تجاوز کر گئی ہے۔ + لائٹ کوائن خریدیں۔ + آپ کے ایل ٹی سی ایڈریس پر جمع کر دیا جائے: + مون پے نال خریداری کرو + نواں پتہ + خرید / وصول + حسب ضرورت + ری سیٹ / دوبارہ شروع کریں + \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 00000000..d1646132 --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,841 @@ + + + + + Strona internetowa + + + + Polityka prywatności + + + Warunki użytkowania + + O + + Twitter + + Zamknij + + Centrum wsparcia + + + + Wygląda na to, że używasz klawiatury innej firmy, która może rejestrować to, co piszesz i kraść Twój klucz Paper Key. Dla dodatkowej ochrony należy przełączyć się na domyślną klawiaturę systemu Android. + + Błąd + + Wystąpił problem z magazynem kluczy systemu operacyjnego Android, skontaktuj się z support.brainwallet.co + + Twoje zaszyfrowane dane Brainwallet zostały niedawno unieważnione, ponieważ ekran blokady Androida został wyłączony. + + Błąd magazynu kluczy systemu Android + + Nie znaleziono połączenia internetowego. Sprawdź połączenie i spróbuj ponownie. + + Ostrzeżenie + + Skopiowane adresy + + Wszystkie adresy portfeli zostały pomyślnie skopiowane. + + Zestaw kluczy papierowych + + Niesamowite! + + Zestaw PIN + + Wysyłanie nie powiodło się + + Wyślij potwierdzenie + + Pieniądze wysłane! + + Rozpoznany odcisk palca + + Błąd serializacji JSON + + Portfel nie jest gotowy + + Nie można pobrać tokenu API + + Anuluj + + Ignorować + + menu + + Nie + + OK + + otrzymywać + + Wyślij + + Ustawienia + + Prześlij + + Tak + + Kwota do wysłania: + + Opłata sieciowa: + + Sieć + + Czas przetwarzania: Przewiduje się, że ta transakcja zakończy się w %1$s. + + Wyślij + + Potwierdzenie + + Do + + Całkowity koszt: + + Aby upewnić się, że wszystko zostało poprawnie zapisane, wpisz następujące słowa z klucza do papieru. + + Słowo #%1$s + + Wyświetlacz Litecoin + + Kurs wymiany + + + + Nie można uwierzytelnić Brainwallet z powodu błędu w wersji systemu Android. [Kliknij tutaj, aby uzyskać więcej informacji]. + + To urządzenie nie jest skonfigurowane do wysyłania wiadomości. + + Wiadomości niedostępne + + Odcisk palca nie został rozpoznany. Spróbuj ponownie. + + Gospodarka + + 10+ minut + + Ta opcja nie jest zalecana w przypadku transakcji wrażliwych na czas. + + Szacowana dostawa: %1$s + + Regularny + + 2,5 - 5+ minut + + Szybkość przetwarzania + + Sprawdzanie salda klucza prywatnego... + + Wysłać %1$sz tego klucza prywatnego do swojego portfela? Sieć Litecoin otrzyma opłatę w wysokości %2$s. + + Ten klucz prywatny znajduje się już w portfelu użytkownika. + + Ten klucz prywatny jest pusty. + + Opłaty transakcyjne kosztowałyby więcej niż środki dostępne na tym kluczu prywatnym. + + Nieprawidłowy klucz prywatny + + Błąd podpisywania transakcji + + Import + + Importowanie portfela + + Importowany portfel + + Importowanie portfela przenosi wszystkie pieniądze z innego portfela do portfela Brainwallet za pomocą jednej transakcji. + + Ten klucz prywatny jest chroniony hasłem. + + hasło + + + Skanowanie klucza prywatnego + + Sukces + + Pomyślnie zaimportowano portfel. + + Importuj portfel + + Klucz odblokowujący + + Import portfela nie obejmuje historii transakcji ani innych szczegółów. + + Błędne hasło, spróbuj ponownie. + + Ignorować + + ZNISZCZONE BEZPIECZEŃSTWO URZĄDZENIA\n Każda aplikacja po jailbreaku może uzyskać dostęp do danych pęku kluczy i wykraść twoje Litecoiny! Natychmiast wyczyść ten portfel i przywróć go na bezpiecznym urządzeniu. + + ZNISZCZONE BEZPIECZEŃSTWO URZĄDZENIA \n Każda aplikacja po jailbreaku może uzyskać dostęp do danych pęku kluczy i wykraść Litecoiny. Brainwallet należy używać wyłącznie na urządzeniach, które nie zostały uszkodzone przez więzienie. + + OSTRZEŻENIE + + Usługi lokalizacji są wyłączone. + + Brainwallet nie ma uprawnień dostępu do usług lokalizacyjnych. + + Utworzyłeś swój portfel na %1$s + + Nazwa portfela pojawia się tylko w historii transakcji na koncie i nie może być widoczna dla nikogo innego. + + Nazwa portfela + + Zarządzanie portfelem + + Kup + + Portfel z zamkiem + + Centrum bezpieczeństwa + + Ustawienia + + Obsługa klienta + + Utwórz nowy portfel + + Menu + + Odzyskaj portfel + + Przełączanie do trybu automatycznego + + Połączony + + Wprowadź adres IP i port węzła (opcjonalnie) + + Wprowadź węzeł + + Przełączanie do trybu ręcznego + + Bieżący węzeł główny + + Brak połączenia + + Status połączenia węzła + + Węzły Litecoin + + Niewłaściwy wniosek o płatność + + Nieobsługiwany lub uszkodzony dokument + + brakujący certyfikat + + żądanie wygasło + + Nie można dokonać płatności + + Płatności w litecoinach nie mogą być niższe niż %1$s. + + Wyniki transakcji Litecoin nie mogą być niższe niż %1$s. + + nieobsługiwany typ podpisu + + niezaufany certyfikat + + Do zabezpieczenia portfela wymagane jest hasło urządzenia. Przejdź do ustawień i włącz kod dostępu. + + Włączanie kodu urządzenia + + Blokada ekranu urządzenia jest niezbędna do ochrony portfela. Przejdź do "Ustawienia" > "Zabezpieczenia" > "Blokada ekranu" i włącz, aby kontynuować. + + Blokada ekranu wyłączona + + Klucz Paper Key należy zapisać na wypadek utraty lub zmiany telefonu. Stuknij tutaj, aby kontynuować. + + Wymagane działanie + + Twój portfel może być niezsynchronizowany. Często można to naprawić poprzez ponowne skanowanie łańcucha bloków. + + Transakcja odrzucona + + Pomóż ulepszyć Brainwallet, udostępniając nam swoje anonimowe dane + + Udostępnianie anonimowych danych + + Stuknij tutaj, aby włączyć Touch ID + + Stuknij tutaj, aby włączyć uwierzytelnianie odciskiem palca + + Włącz Touch ID + + Włącz uwierzytelnianie odciskiem palca + + PIN + + Brainwallet przeszedł na 6-cyfrowy kod PIN. Stuknij tutaj, aby dokonać aktualizacji. + + PIN aktualizacji + + Włącz powiadomienia, aby w przyszłości otrzymywać specjalne wiadomości od Brainwallet. + + Powiadomienia push + + Wył. + + Na + + Powiadomienia + + Skopiowano do schowka. + + E-mail + + Żądanie kwoty + + Udział + + Wiadomość tekstowa + + Odbiór + + Gotowe + + Odzyskaj portfel + + Reset PIN + + Klawisz Enter Paper + + Odzyskaj Brainwallet za pomocą papierowego klucza. + + Wprowadzony klucz papieru jest nieprawidłowy. Sprawdź każde słowo i spróbuj ponownie. + + Strzałka w lewo + + Następny + + Kliknij tutaj, aby uzyskać więcej informacji. + + Strzałka w prawo + + Wprowadź klucz papierowy dla portfela, który chcesz odzyskać. + + Aby zresetować kod PIN, wprowadź słowa z klucza papierowego w polach poniżej. + + Najpierw wprowadź kwotę. + + Żądanie kwoty + + Synchronizacja + + Nie będzie można wysyłać pieniędzy podczas synchronizacji. + + Synchronizacja z Blockchain? + + 20-45 minut + + Jeśli transakcja jest wyświetlana jako zakończona w sieci Litecoin, ale nie w portfelu Brainwallet. + + Wielokrotnie pojawia się błąd informujący, że transakcja została odrzucona. + + Rozpocznij synchronizację + + Nie będzie można wysyłać pieniędzy podczas synchronizacji z blockchainem. + + Synchronizacja łańcucha bloków + + Szacowany czas + + Kiedy synchronizować? + + Lampa błyskowa aparatu + + kompletny + + w toku + + otrzymany + + wysłany + + Włącz wszystkie funkcje bezpieczeństwa dla maksymalnej ochrony. + + Jedyny sposób na uzyskanie dostępu do Litecoin w przypadku utraty lub aktualizacji telefonu. + + Klucz do papieru + + Chroni Brainwallet przed nieautoryzowanymi użytkownikami. + + 4-cyfrowy kod PIN + + Centrum bezpieczeństwa + + Wygodnie odblokuj Brainwallet i wysyłaj pieniądze do ustalonego limitu. + + Touch ID + + Uwierzytelnianie odciskiem palca + + Kwota + + Równowaga: %1$s + + Zezwól na dostęp do kamery w "Ustawienia" > "Aplikacje" > "Brainwallet" > "Uprawnienia". + + Brainwallet nie ma dostępu do kamery + + Przejdź do Ustawień, aby zezwolić na dostęp do kamery. + + Brainwallet nie ma dostępu do kamery + + Miejscem docelowym jest własny adres. Nie można wysyłać do samego siebie. + + Nie można utworzyć transakcji. + + Memo + + Wklejka jest pusta + + Opłata sieciowa: %1$s + + Tożsamość odbiorcy płatności nie została potwierdzona. + + Adres docelowy nie jest prawidłowym adresem Litecoin. + + Pasteboard nie zawiera prawidłowego adresu Litecoin. + + Nieprawidłowy adres + + Wysyłanie jest wyłączone podczas pełnego ponownego skanowania. + + Żądanie załadowania + + Wprowadź adres odbiorcy. + + Wprowadź kwotę do wysłania. + + Pasta + + Nie można opublikować transakcji. + + Nie można załadować żądania płatności + + Skanowanie + + Wyślij + + Wyślij + + Wprowadź adres Litecoin + + Wprowadź domenę .crypto, .wallet, .zil, .nft, .blockchain, \n.bitcoin, .coin, .888, .dao lub .x. + + Lub + + Wyszukiwanie + + Twój adres został rozwiązany! + + Adresy Litecoin są przeznaczone wyłącznie do jednorazowego użytku. + + Ponowne użycie ogranicza prywatność zarówno użytkownika, jak i odbiorcy i może skutkować stratą, jeśli odbiorca nie kontroluje bezpośrednio adresu. + + Adres już używany + + O + + Ustawienia zaawansowane + + Wyświetlanie waluty + + Dołącz do wczesnego dostępu + + Korzystasz z Brainwallet? + + Importuj portfel + + Zarządzanie + + Powiadomienia + + Zostaw nam recenzję + + Udostępnianie anonimowych danych + + Synchronizacja łańcucha bloków + + Ustawienia + + Limit wydatków na Touch ID + + Limit wydatków na uwierzytelnianie odcisków palców + + Portfel + + Uruchamianie/odzyskiwanie innego portfela + + Pomóż ulepszyć Brainwallet, udostępniając nam swoje anonimowe dane. Nie obejmuje to żadnych informacji finansowych. Szanujemy Twoją prywatność finansową. + + Udostępniać dane? + + Udostępniać anonimowe dane? + + Zapisz ponownie klucz do papieru + + Klucz papierowy to jedyny sposób na przywrócenie Brainwallet w przypadku zgubienia, kradzieży, uszkodzenia lub aktualizacji telefonu. Pokażemy Ci listę słów, które należy zapisać na kartce papieru i przechowywać w bezpiecznym miejscu. + + Klucz do zapisywania dokumentów + + Ostatni raz zapisałeś swój papierowy klucz na %1$s + + Najbezpieczniejszy sposób korzystania z Litecoin. + + Łączenie + + Synchronizacja + + Ponów próbę + + Synchronizacja + + %1$s d + + %1$s h + + %1$s m + + %1$s s + + Limit wydatków na Touch ID można dostosować na stronie %1$s. + + Limit wydatków na uwierzytelnianie odcisków palców można dostosować na ekranie Limit wydatków na autoryzację odcisków palców + + Nie włączono uwierzytelniania odcisków palców na tym urządzeniu. Przejdź do Ustawienia -> Bezpieczeństwo, aby skonfigurować uwierzytelnianie odciskiem palca. + + Uwierzytelnianie odciskiem palca nie jest włączone + + Użyj odcisku palca, aby odblokować Brainwallet i wysłać pieniądze do ustalonego limitu. + + Ekran limitu wydatków Touch ID + + Limit wydatków: %1$s (%2$s) + + Włącz Touch ID dla Brainwallet + + Włącz uwierzytelnianie odciskiem palca + + Touch ID + + Uwierzytelnianie odciskiem palca + + Touch ID nie został skonfigurowany na tym urządzeniu. Przejdź do Ustawienia->Touch ID i kod dostępu, aby skonfigurować go teraz. + + Touch ID nie został skonfigurowany + + Zawsze wymagaj kodu dostępu + + Użytkownik zostanie poproszony o wprowadzenie 6-cyfrowego kodu PIN w celu wysłania każdej transakcji przekraczającej limit wydatków, a także co 48 godzin od ostatniego wprowadzenia 6-cyfrowego kodu PIN. + + Limit wydatków na Touch ID + + Limit wydatków na autoryzację odcisków palców + + Dostępne do wydania + + Kompletny + + Saldo końcowe: %1$s + + Kurs wymiany w momencie otrzymania: + + Kurs wymiany w momencie wysłania: + + (%1$s opłata) + + NIEPRAWIDŁOWY + + właśnie teraz + + W toku: %1$s + + W toku: %1$s + + Saldo początkowe: %1$s + + Czekam na potwierdzenie. Niektórzy sprzedawcy wymagają potwierdzenia w celu sfinalizowania transakcji. Szacowany czas: 1-2 godziny. + + konto + + Kwota + + Potwierdzone w bloku + + Memo + + Twoje transakcje pojawią się tutaj. + + na %1$s + + Więcej... + + Przeniesiony %1$s + + Przeniesiony %1$s + + Nie potwierdzono + + Otrzymano %1$s + + Otrzymano %1$s + + Wysłany %1$s + + Wysłany %1$s + + Status + + Szczegóły transakcji + + do %1$s + + Identyfikator transakcji Litecoin + + Odebrane pod tym adresem + + Wysłane na ten adres + + Wyłączone do: %1$s + + Mój adres + + Reset PIN + + Skanowanie + + Wprowadź kod PIN + + Czujnik dotykowy + + Odblokuj swój Brainwallet. + + Aby kontynuować, odblokuj urządzenie z systemem Android. + + Odblokowywanie za pomocą TouchID + + Widok na blockchain + + Wymagane uwierzytelnienie + + Odblokowany portfel + + Nie pamiętasz hasła seed lub kodu PIN? + + Zapamiętaj ten kod PIN. Jeśli go zapomnisz, nie będziesz mieć dostępu do swoich Litecoinów. + + Twój kod PIN zostanie użyty do odblokowania Brainwallet i wysłania pieniędzy. + + Ustaw PIN + + Ponowne wprowadzenie kodu PIN + + Wprowadź aktualny kod PIN. + + Wprowadź nowy kod PIN. + + Wprowadź ponownie nowy kod PIN. + + Przepraszamy, nie mogłem zaktualizować kodu PIN. + + Błąd aktualizacji kodu PIN + + Aktualizacja kodu PIN + + Skopiować adresy portfeli do schowka? + + Autoryzacja kopiowania adresu portfela do schowka + + Kopiowanie adresów portfela + + Kopia + + Wprowadź kod PIN, aby autoryzować tę transakcję. + + Wprowadź kod PIN, aby kontynuować. + + Wymagany kod PIN + + Autoryzuj tę transakcję + + Otwórz aplikację Brainwallet na iPhone\'a, aby skonfigurować portfel. + + Odrzucić + + Wystąpił błąd podczas ładowania zawartości. Spróbuj ponownie. + + Aktualizacja... + + Brainwallet został właśnie zaktualizowany! \Jeśli potrzebujesz pomocy, poszukaj (?) w prawym górnym rogu większości ekranów. + + Witamy w Brainwallet! + + Czy na pewno chcesz usunąć ten portfel? + + Wymazać portfel? + + Nie udało się wyczyścić portfela. + + Nie powiodło się + + Aby uruchomić nowy portfel lub przywrócić istniejący portfel, należy najpierw usunąć aktualnie zainstalowany portfel. Aby kontynuować, wprowadź klucz papieru bieżącego portfela. + + Uruchomienie lub odzyskanie innego portfela umożliwia dostęp do innego portfela Brainwallet i zarządzanie nim na tym urządzeniu. + + Obecny portfel zostanie usunięty z tego urządzenia. Aby przywrócić ją w przyszłości, należy wprowadzić klucz Paper Key. + + Uruchomienie lub odzyskanie innego portfela + + Wycieranie + + Wycieranie... + + Zapisz każde słowo w kolejności i przechowuj je w bezpiecznym miejscu. + + Następny + + Poprzedni + + %1$dz%2$d + Czas przetwarzania: Przetworzenie tych transakcji zajmie %1$s minut. + Adres: + Luksus + 2,5 - 5+ minut + Ta opcja praktycznie gwarantuje akceptację transakcji, mimo że płacisz premię. + + Moonpay + "- Kup LTC za pomocą wielu par walutowych - Płać wieloma metodami - Globalny dostawca płatności" + Bitrefill + "- Kupuj karty podarunkowe \n- Doładuj telefony przedpłacone \n- Steam, Amazon, Hotels.com \n- Działa w 170 krajach" + AUD + GBP + HKD + IDR + RUB + SGD + CAD + EUR + JPY + USD + Historia + + Równowaga + 1 LTC = %1$s + Aktualna wartość LTC w %1$s + Języki + Czy na pewno chcesz zmienić język na angielski? + Zamknij + + Instagram + 1: %s 2: %s 3: %s 4: %s \\n5: %s 6: %s 7: %s 8: %s%s \\n9: %s 10: %s 11: %s 12: %s %s + Pokaż + Pokaż moje nasiona + Preferencje synchronizacji: %1$s fałszywe alarmy + Niski poziom prywatności (~45 minut) + Półprywatnie (~60 minut) + Anonimowy (~77 minut) + WAŻNE: Aplikacja zsynchronizuje się, aby zezwolić na adresy 1ltc. Poczekaj ~1 godzinę na synchronizację! + + Nie przegap niczego! + Zamknij + Zarejestruj się, aby otrzymywać informacje o aktualizacjach i konkursach od zespołu Brainwallet! Zaakceptuj powiadomienia, aby otrzymywać wiadomości na żywo, ceny i informacje rynkowe! + Nie, dzięki! + Usługa + Opłaty: + Ogólne + Wiadomości Litecoin + Aktualizacja Brainwallet + Anuluj + Ok + Prosimy o zezwolenie na powiadomienie + Informacje o zezwoleniu + Powiadomienie Przyznane zezwolenie + + + Powrót + Twoje słowa zalążkowe + "Tylko dla ciebie. \To jest klucz prywatny która umożliwia wysyłanie". + Blockchain: Litecoin + Zapisałem go na papierze lub metalu + Uratowałeś go, prawda? + Udowodnij to! \nPrzeciągnij słowa w odpowiedniej kolejności. + Gra i synchronizacja + Gotowy? + Zrób to dla siebie. Proszę, zrób to + sam + Weź długopis, papier i 5 minut + Konfiguracja kodu aplikacji + Wybierz hasło, aby odblokować Brainwallet + Nie kod blokady telefonu! + Spraw, by było inaczej. Niech będzie fajnie. + Korzystanie z danych biometrycznych + Zachowałeś swoje klucze. + Przejdź na następny poziom. + Stuknij słowo i przeciągnij je na miejsce + Doładować? + W tej chwili twój mózg jest pusty... + Zdobądź Litecoin w 5 minut + Zdobądź trochę Litecoina! + Może później. + Pomiń + Przywróć swoją moc + Możesz wrócić z miejsca, w którym zacząłeś + Przywróć mój Brainwallet + Wyczyść + Nie zgaduj. Zajęłoby ci to 5 444 517 950 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 prób. + Potwierdzenie + Nie zapomniałeś, prawda? Wprowadź go ponownie. Albo wrócić i zacząć od nowa. + Gotowy + Przywracanie + Nieprawidłowe hasło, spróbuj ponownie! + strzałka w dół-lewo + logo + toggle-dark-mode + toggle-lock-mode + Bezpieczeństwo + Język + Waluta + Gry + Wsparcie + Media społecznościowe + Blokada + Odblokowanie + Temat + Wersja aplikacji: + Synchronizacja metadanych: + Synchronizacja + Czas trwania synchronizacji: >20 minut + Gra %1$d: + %s + %s + %s + %s + PIN + Fraza seed + Zwrot Brainwallet + Udostępnianie danych analitycznych + Aktualizacja kodu PIN + Pokaż + Kup LTC + Powered by Moonpay + Ładowanie... + Opłata sieciowa (za kb): Wyższa wartość oznacza szybsze zakończenie transakcji + Top + Średni + Niski + Kwota poniżej minimalnego limitu (%f) + Kwota przekracza maksymalny limit (%f) + Kup Litecoin + Wpłaty należy dokonywać na adres LTC: + Kupuj z Moonpay + Nowy adres + Kup / Odbierz + Niestandardowe + Reset / Rozpocznij od nowa + \ No newline at end of file diff --git a/app/src/test/java/com/brainwallet/tools/util/LocaleHelperTest.kt b/app/src/test/java/com/brainwallet/tools/util/LocaleHelperTest.kt index 62ecd6c5..52cab56b 100644 --- a/app/src/test/java/com/brainwallet/tools/util/LocaleHelperTest.kt +++ b/app/src/test/java/com/brainwallet/tools/util/LocaleHelperTest.kt @@ -56,30 +56,18 @@ class LocaleHelperTest { fun `check all language codes given the subjective business logic which prioritizes localization popularity`() { Language.entries .also { languages -> - assertEquals(16, languages.size) + assertEquals(20, languages.size) } .map { it.code } - .also { langCodes -> + .also { assertEquals( listOf( - "en", - "es", - "in", - "ar", - "uk", - "ru", - "pt", - "hi", - "de", - "ko", - "fr", - "zh-TW", - "tr", - "ja", - "zh-CN", - "it", + "en", "es", "in", "ar", "uk", + "ru", "pt", "hi", "de", "fa", + "pa", "pl", "ko", "fr", "zh-TW", + "tr", "ja", "zh-CN", "it", "sv" ), - langCodes + it ) } diff --git a/fast_follow_asset_pack_01/.DS_Store b/fast_follow_asset_pack_01/.DS_Store deleted file mode 100644 index 4c042faf8a4273d44f0430988725dc059be5ede1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 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 R{x9SE-)8yW|KtC+{~v%HY3%?2 diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/coinflip.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/coinflip.mp3 deleted file mode 100644 index 976a06f5ba29db578e9497766dc1700baf0a3cc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23680 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 C1S38G diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/hindi.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/hindi.mp3 deleted file mode 100644 index 7ba1ad66b8a76602c541525030faaaa6cf72a0ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6912 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 diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/japanese.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/japanese.mp3 deleted file mode 100644 index 379a6938050723055096af20025fa6d452f4032b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4320 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 BkHP=| diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/korean.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/korean.mp3 deleted file mode 100644 index f17488e15429e9f3e4bd9a27b3b9ec0b577cb9e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4416 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 D^BFm+ diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/portugues.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/portugues.mp3 deleted file mode 100644 index f7d54262bd996b2956365b7e60914d3d83cb7fda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5280 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 diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/simplifiedchinese.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/simplifiedchinese.mp3 deleted file mode 100644 index b9f00f6cbbfa304d949fd2a280ff21de1a1789d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5088 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 z 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 JSKYtb{~P66Pfh>; diff --git a/fast_follow_asset_pack_01/src/main/assets/audio/traditionalchinese.mp3 b/fast_follow_asset_pack_01/src/main/assets/audio/traditionalchinese.mp3 deleted file mode 100644 index b9f00f6cbbfa304d949fd2a280ff21de1a1789d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5088 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 F{{ilF$iM&q diff --git a/settings.gradle.kts b/settings.gradle.kts index 504b5ee8..b3356345 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,5 +22,4 @@ dependencyResolutionManagement { rootProject.name = "Brainwallet Android" include(":app") include(":install_time_asset_pack") -include(":fast_follow_asset_pack_01") From 4ff50b82fcd882439a3b24f859233320668dfa81 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Sun, 29 Jun 2025 13:50:10 +0700 Subject: [PATCH 49/65] fix: fix YourSeedProveItState.isWordUsedCorrectly (#111) --- .../screens/yourseedproveit/YourSeedProveItScreen.kt | 10 ++-------- .../ui/screens/yourseedproveit/YourSeedProveItState.kt | 10 ++++++++-- .../yourseedproveit/YourSeedProveItViewModel.kt | 10 ++++++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt index 04fcf6f2..71d1c56e 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt @@ -187,14 +187,8 @@ fun YourSeedProveItScreen( Spacer(modifier = Modifier.weight(0.1f)) SeedWordsLayout { - itemsIndexed(items = state.shuffledSeedWords) { index, word -> - - val isWordUsedCorrectly = - state.correctSeedWords.values.any { (expectedWord, actualWord) -> - expectedWord == word && actualWord == word - } - - if (isWordUsedCorrectly) { + itemsIndexed(items = state.shuffledSeedWords) { index, (correctIndex, word) -> + if (state.isWordUsedCorrectly(correctIndex, word)) { Box(modifier = Modifier.fillMaxWidth()) } else { SeedWordItem( diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt index 1da5cc92..b69ac06b 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItState.kt @@ -2,11 +2,17 @@ package com.brainwallet.ui.screens.yourseedproveit data class YourSeedProveItState( val correctSeedWords: Map = emptyMap(), - val shuffledSeedWords: List = emptyList(), + val shuffledSeedWords: List> = emptyList(), val orderCorrected: Boolean = false, ) data class SeedWordItem( val expected: String, val actual: String = "" -) \ No newline at end of file +) + +fun YourSeedProveItState.isWordUsedCorrectly(currentIndex: Int, currentWord: String): Boolean { + return correctSeedWords[currentIndex]?.let { seedWordItem -> + seedWordItem.expected == currentWord && seedWordItem.actual == currentWord + } ?: false +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt index 998ddb00..c6406a2d 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt @@ -17,11 +17,13 @@ class YourSeedProveItViewModel : BrainwalletViewModel() { override fun onEvent(event: YourSeedProveItEvent) { when (event) { is YourSeedProveItEvent.OnLoad -> _state.update { + val correctSeedWords = event.seedWords.mapIndexed { index, word -> + index to SeedWordItem(expected = word) + }.toMap() + it.copy( - correctSeedWords = event.seedWords.mapIndexed { index, word -> - index to SeedWordItem(expected = word) - }.toMap(), - shuffledSeedWords = event.seedWords.shuffled() + correctSeedWords = correctSeedWords, + shuffledSeedWords = correctSeedWords.map { it.key to it.value.expected }.shuffled(), ) } From 2fd094f0819ff77412bbc356d36d4bbb397b05f2 Mon Sep 17 00:00:00 2001 From: Andhika Yuana Date: Tue, 5 Aug 2025 21:23:32 +0700 Subject: [PATCH 50/65] Upgrade targetSdk 36 (#113) * chore: change drawable with density for brainwallet_logotype_white * chore: adjustment WelcomeScreen.kt * chore: adjustment for targetSdk 36 also support 16KB page size --- app/CMakeLists.txt | 5 +- app/build.gradle.kts | 4 +- app/src/main/AndroidManifest.xml | 5 +- .../java/com/brainwallet/BrainwalletApp.kt | 5 -- .../main/java/com/brainwallet/di/Module.kt | 5 +- .../ui/screens/welcome/WelcomeScreen.kt | 67 ++++++++++-------- .../brainwallet_logotype_white.png | Bin 0 -> 62457 bytes .../brainwallet_logotype_white.png | Bin 0 -> 39557 bytes .../brainwallet_logotype_white.png | Bin 0 -> 85102 bytes .../brainwallet_logotype_white.png | Bin 0 -> 144825 bytes .../brainwallet_logotype_white.png | Bin 0 -> 141693 bytes .../drawable/brainwallet_logotype_black.png | Bin 122516 -> 0 bytes .../drawable/brainwallet_logotype_color.png | Bin 130982 -> 0 bytes .../drawable/brainwallet_logotype_white.png | Bin 126886 -> 0 bytes gradle/libs.versions.toml | 6 +- 15 files changed, 51 insertions(+), 46 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/brainwallet_logotype_white.png create mode 100644 app/src/main/res/drawable-mdpi/brainwallet_logotype_white.png create mode 100644 app/src/main/res/drawable-xhdpi/brainwallet_logotype_white.png create mode 100644 app/src/main/res/drawable-xxhdpi/brainwallet_logotype_white.png create mode 100644 app/src/main/res/drawable-xxxhdpi/brainwallet_logotype_white.png delete mode 100644 app/src/main/res/drawable/brainwallet_logotype_black.png delete mode 100644 app/src/main/res/drawable/brainwallet_logotype_color.png delete mode 100644 app/src/main/res/drawable/brainwallet_logotype_white.png diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 628e7234..d17111b0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -84,8 +84,11 @@ include_directories(src/main/secp/secp256k1/src/) include_directories(src/main/secp/secp256k1/) include_directories(src/main/secp/) +# support compiling 16 KB-aligned: https://developer.android.com/guide/practices/page-sizes#cmake +target_link_options(core-lib PRIVATE "-Wl,-z,max-page-size=16384") + # add lib dependencies target_link_libraries( core-lib android - log) + log) \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 802fe2e6..66c1b24e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,12 +14,12 @@ val localProperties = gradleLocalProperties(rootDir, providers) android { namespace = "com.brainwallet" - compileSdk = 34 + compileSdk = 36 defaultConfig { applicationId = "ltd.grunt.brainwallet" minSdk = 29 - targetSdk = 34 + targetSdk = 36 versionCode = 202506271 versionName = "v4.6.2" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index dd68f40a..303a4051 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,15 +51,16 @@ tools:ignore="GoogleAppIndexingWarning,UnusedAttribute" tools:replace="android:fullBackupContent,android:allowBackup"> + + - + - diff --git a/app/src/main/java/com/brainwallet/BrainwalletApp.kt b/app/src/main/java/com/brainwallet/BrainwalletApp.kt index 03fd029e..8a55523b 100644 --- a/app/src/main/java/com/brainwallet/BrainwalletApp.kt +++ b/app/src/main/java/com/brainwallet/BrainwalletApp.kt @@ -16,11 +16,6 @@ import com.brainwallet.tools.listeners.SyncReceiver import com.brainwallet.tools.manager.AnalyticsManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.tools.util.Utils -import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.analytics.ktx.analytics -import com.google.firebase.analytics.setConsent -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.google.firebase.ktx.Firebase import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.GlobalContext.startKoin diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index b95bbeec..d8f47bd3 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -23,8 +23,8 @@ import com.brainwallet.ui.screens.yourseedwords.YourSeedWordsViewModel import com.brainwallet.util.cryptography.KeyStoreKeyGenerator import com.brainwallet.util.cryptography.KeyStoreManager import com.brainwallet.worker.CurrencyUpdateWorker -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig +import com.google.firebase.Firebase +import com.google.firebase.remoteconfig.remoteConfig import kotlinx.serialization.json.Json import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient @@ -35,7 +35,6 @@ import org.koin.core.component.inject import org.koin.core.module.dsl.viewModel import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module -import retrofit2.HttpException import retrofit2.Retrofit import retrofit2.converter.kotlinx.serialization.asConverterFactory diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index 845a9073..cec6d05a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -7,12 +7,14 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape @@ -93,39 +95,44 @@ fun WelcomeScreen( modifier = Modifier .fillMaxSize() .background(BrainwalletTheme.colors.surface) - .verticalScroll(rememberScrollState()), + .verticalScroll(rememberScrollState()) + .padding(WindowInsets.systemBars.asPaddingValues()), ) { - Image( - painterResource(R.drawable.brainwallet_logotype_white), - contentDescription = "brainwallet_logotype_white", - contentScale = ContentScale.Fit, - colorFilter = ColorFilter.tint( - BrainwalletTheme.colors.content, - ), + Column( modifier = Modifier .align(Alignment.TopCenter) - .fillMaxWidth() - .padding(horizontal = 55.dp) - .padding(vertical = 30.dp) - ) + .padding(vertical = 20.dp) + ) { + Image( + painterResource(R.drawable.brainwallet_logotype_white), + contentDescription = "brainwallet_logotype_white", + contentScale = ContentScale.Fit, + colorFilter = ColorFilter.tint( + BrainwalletTheme.colors.content, + ), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 55.dp) + ) + + // Animation Placeholder + LottieAnimation( + modifier = Modifier + .fillMaxWidth() + .padding(leadTrailPadding.dp) + .background( + BrainwalletTheme.colors.surface, + BrainwalletTheme.shapes.large + ) + .height(thirdOfScreenHeight.dp) + .clip(BrainwalletTheme.shapes.large), + composition = composition, + contentScale = ContentScale.FillWidth, + alignment = Alignment.Center, + progress = { progress } + ) + } - // Animation Placeholder - LottieAnimation( - modifier = Modifier - .offset(y = 120.dp) - .fillMaxWidth() - .padding(leadTrailPadding.dp) - .background( - BrainwalletTheme.colors.surface, - BrainwalletTheme.shapes.large - ) - .height(thirdOfScreenHeight.dp) - .clip(BrainwalletTheme.shapes.large), - composition = composition, - contentScale = ContentScale.FillWidth, - alignment = Alignment.Center, - progress = { progress } - ) Column( modifier = Modifier.align(Alignment.BottomCenter), diff --git a/app/src/main/res/drawable-hdpi/brainwallet_logotype_white.png b/app/src/main/res/drawable-hdpi/brainwallet_logotype_white.png new file mode 100644 index 0000000000000000000000000000000000000000..673e585927cf814ef31cb37eca64e03d08cf7d6e GIT binary patch literal 62457 zcmZ6ybyQSs_diTKNDbXF(j_G!&Cno?64KpBGk_p4fHVSvbO{FC4I(WmlG2jW-SNBb zXRYt^-p{+vTFM_foH=J-dw*(2YN{*ZJ*0Ywf`WpltR$z6f`T>zey)LFfj=D~9hu-S zR1a-MI7-Tt-Z84R-{2qGRB@!TRegB-@G}D%c52`2uve>XMaA1vuh+==B<3efTfbgyP53W%_T6Aap(sE)2%ZN`-@3cI!*z6YR-o`*D7+O4?}y~6 zL-O>IniTN95Gau#0V@PX3DXUOa=;<9@{qNe-7{md=(UTjiQnnHp7rt3`ndm$VN;!8x@SCkjSQ01O1Wl z*Skzv$QmP32!;$asJ0n$6`uF}#ZLYR@7}XceqVNQ`+qDRf6t03QsZ_ATJ5wizK9^uiNc^ z6{!^{#+SXI_Cd`PzVllb{{R05ao9hR$~KWVjuqJ-NY+^ml%M&&cWAyxWZy-;|@z`#K2#`=00rGU*K;&gfRt)V&7mFcgR zF}ZL5dohg!&!EKHE4a3vzPO2@6eyF0%tu41q#==5-(&dJt=6Ea2F^BYU16SC!wsr|B{w%q}n30v^k{p9~6#1j`}02nD{4=r|sg8s$ga(?%L-K zbv}CAM`r)MMgs_W`>QwFy!7^D5jGMg)`l`e!VdE-^Oc!M5n^&QE!mh6v&O58P z(DS5Nqb$5-WI7z3f7kR2w2lt>pk%n({P)Am9%;5iE@a2I>cjAkpD1KLcRgl8jus#j z0-?WRp!|RAy;Tzt4Po2G_TQ!ET5Gf0{^T*Db;(8NL%J^4c6N5+$A0~CguI2S;SEN!gXE85pdoSXeMjv_#MC1 zh$UfrQOSt>_MY~kR25hCzBC2aXRpswRriH=o7jZrA8D0DVINfzKL(W=RIkfFUr^@> z_I|A);N4_DTRY=NjQZazn1Nv_8iKV$BYn3d;kmfn;qhD8}|$swo{2H8oD<_@RS2 zsgjaa*mK^VJn5q6mtw68t_^Yid3xleq!NVWIr${XWOa8?bBQl&3`M4n2M1>viIrE`sJweMTg(bs5 zym^erljnr%|oAmw~iGPWrpPvG;mwuRguW+r?>cyj%r?bh)BxRL@ z%8g_`jBcHDt&OvF&e5$mM*|NYA@?*%thstb4DmLWx^=}3#ID5(PoO;%Eq|~fd2&ci zM|mv^Y?%2gdXu5i(vBMw!Air#kB^X=sPIh;_@vWAeK^vy~1)|-Gl1&QOeptvr{k}SoEWEA$HOmG0u7Dg}taq7j5@Kd9)USQ0 zPPUw*&{xG%@aHvVy8%RAU0vPE!NK8cC$)IIwjX!T2dUYY?fhtX4m9AjbWG~JPw18` zhH(tPe47u+wx1TEk%5#x=H|Y&=?KAWb{3j_diuy`!P|7->2CgiI$o|8Z1h8ab)ECx z?=Q?ncL};=U$u;l=M|yI!Vm^rC`K@$C67c`G|KA;e(Cp_f@B~xLH`s#Z$bczR#w^gm~|U<5B;{r+Q*nDT{4c z!WIP{*^8@PR^`O(4vKOI47v$JrgZIx%3+jI`M5vRb|{{`EGb+-#V|Z|;Y?(5_DJTx zZz(C+k$U&;UGsBy)0~W0v$jtNp8s|TRN~-his0}^BYxwQ2hluj6zl`;BA-nVFedOK9M}rpAcbeb7+4;G|Z8LaQ_cp-&?3`js?OB=p%_ z5bgO;7sZC--Xewg=i!96U=Eh?@$qR8!uLpm;=2z>9~kSc?DSlR zUXOp$px=uWY8~~OKwp3T@A(}PC;d8U!!TR>PKco(B_m^2Iq~BvI18Syx(Iu}^gHFE z{3L>rgh3x_MMv7br)S7Mt4VM04(traV=eyr)!U$S^42B!am_LXbVEE8dPJZ_(%A}q zrXWr#pBKW=qGe)o_sq(QiK$=kMLGMd5skPnZ=J`+aL{|}OY^_y9GrJhJ0H=JJBr-m zJ3%w-M1kD3;!IQ&&Ivfu$a1qt{7$dps6>X4L-I2Lyo#3M>~!;MuO~X4eLulOV2dSPJdmR zo4ZtXad8okA+uQ+F6f%E}tVa5_@? zpE{42l%`PgN+)zx*l!5#q%fcNcOvkd42>Sviku6GF3cEQYC@656f5NC`-}HEd-Khq z77+_a%c69aCKmr{D`tKG)RdhA52IyTT})iJc7NjfVW4paYRQ19qEN)ep69XJ?>b-aYAW({GaTCV@JBjl)Y#8ud7H2oo-gc>*P^YX`D}qz zKKl#ppz=IiiF?F-3x2gE{R`ko7sxVv=$iPOHs9>ydacUSdh!@KYK%-US*jJ(RA?%b z9#fe{JTy1UwlheHS516EYT438nIJOBldKI%P1~C8bCQAF*0`_z2svEo_2($wEhTvT z_O(fcnang}yg1szCMqQFC5;7(9ud6hbDqFL^0S%+hlDzGu^CNm?IXKq&jvNrMrTd+ z>KqrQ{?$@*-!VYBjs_uyU@i-Cb33EKH&Nkzf*goH3-Uh7c5P;(esL1rG7q+Cefg;g zF_y94b~yR?`8KLf}tXwg&q9-`Sa9pBvPDd;K(?H zLGD`Xqpa$J{vbb;Rq*i?cNdf{H?neqNIqyGI^-cn&qdHD^{l2+fN9nEhG)qCdc_{% zr#QSNbKQ^tc)lD$K+tZSVm+GaQt+3@7~{9ro*?=IPoCH?L7koYN)x^&`t}(IBa-j+NX~5 zoP;@1n`+r=XpfZP1Zq!Lrp2T@W)*X&SJeAU@7({k*+b`jQW9ffQ4ziZWQZ9V10du{ z)9d##5pa>wkql5W63rSpl48%$Xf=aAmSn8<8 zh8<(b*lp*hFPBD2XY2Q&Bv`-a)lp8wXFz&CLdJb1@?ZtW0*AI+G73ZHbAIvm(k`{w*J0m@0zuUNp+d7Fdwck@08|` z^{)-ZIF(0G+vZzqX=xdO0(#Osk017up>mWp_=T*Km`4b9vHPuVFfEG*(|Z{FW-b2Kk^ z#Ay>f(W&%h{a(O~b*dK}aw-Ff{gix$m00>!>f7xcq0stmiZvw%>4HtAzWXztPq59` z#zv~aVcMdDZVm@%g(oWX8Qf&5cyx9EiGWkK9}2J`QU@Y{^_%?9`r^Oa_!cf|!D<@e zMpRT(S3*KUDv5kr$=0>snCd#7569y-Z50fV2;Lrsq_acNRO_v*tTKm(hbL7&HmW{8 zc_FffhWQqZlaw!CzGyZ=iKfEYqsFM;re^3nWq&;D=ucv`t#zC#({}c(_!GQca-2RL zTYGpYp?ghP@D9(@HoAlWz%;AkiS&0_SrSqb62`@A^IZ(Q8IJ#I*`woxyzp#Fw=w`r zh=_=eI0`*8hd)XyluU4hT+3@2?Lo@>u=<~zZf0BdS$^bU_%13lNwjCUcBG=B@;Ejs z3XL>Dxr&Qml;i~E`(utMZ8&=tOnEFwZKO!O=C(a%hR{wUA|m2mO)L2eG-9RD3@=_$ zN*Kgd#UrmC67vm(+mhS7jO}0FDqLe|K~eK#U^GJmZJVDaXia8*;7BXpLbN2nPn-*LY-)6)$9_BHfOrp+GG42 z91kHU&t#x2%9Q-fBr?#p@{*DkZgFuMi$59KQh#Y}{VH%))6L>5rGHxl*1JGQ9UY6f z$MNpgjWdMNyd>IA<`!w1+nh^=-Nuhm6tqFnzXY?Ot%yw}ear3a%y`eaD4*?)09L~* zB^C4<=q9mO!>7iTBZ7Nm7Ww-Mka*v#)zsGvcIh%aB_e+9Mvf^#JdfodvB!KDTV+ zzNszf)la(?pJQr8(|^jV+IB>tx2LD=4YX-WF@{6BD}E-LS=kRAc0v$y$c|@!Cd|c1 zaWM60_x=0#QxW0eCZ+}kmwvv!7j8-756~@S&zJa4Xt~J-+G!^+%a8NFcl;>QQNiKh z;BbkLin?kdJlEqc_x%U=tEs7pB!3b{s=pzBS^A<+g8>GERoItO2|0b(SxX5Bok>^` z_$J)e(C$(_^AP~UnuBn(X}G?=zJZF$L#3c24IR<$#s;yOfNLyS22M`ZXG%(M(Z3kM z-_GK(7S=di94s?Gj$<&+&|%}B0)+BIdOB4-fBV7U+qZ9jfRD4|M9;9C>VAaMi$o&r z;BPmF^-&bzN)wwu3slk4&|A6JcU%n&4B&=_zZt8zqzb+|e7iq8ke3l+et=qO?;n#J?>Xq2@%Ut7GGydE?>GrUE{WD>v<*@`R8>?YU4G_w z^U+#H&*y0SVZ!Ys;cSLk_4D)eG_Z{w?`v`}=5iDi6>}!s?u(*ZDpRTv2M5cYw_@Hq zAM#WvINl5BTOQlwSS?yiwVTeI|BNX0t+St8|g^?ZxG z!Gw7-!!VRQ3a-BWCG2USfni96LGtJc;f?r+Ugxy5G(ZWd&ozbDD`!9RIxqE990EDb z1I)jSJdR?+pznYZ*W~~D+6+N5;#~oo3J&cphDe!Dz`1>GdgY$r2r*(^td!2p&29gwXwVx5$U>B11)~?d@199H zeOsw*w$S{#=zQy3eJ#gOg&`d;T zP7AlQc5!iuqgv0a9mo~zY0=UoTv|oE>9)9x)8_cn+mpTSv$qMAb~PpG)~Iut7i9#T zz2RLurXpw!Nl|>!lMvf{AgWkZJHaoNHj4i)?@<=1{V_4^r)>0C`T}z|EhTl42v_ zy+aY*i;A}b2C%~l!6p8~z-GqZsKe;7XWId2f6A1Bso`2D3^KUsb61p(_Uvoh*uzM zk8dKmOV?DqBQ|W{G{JV5bNrEoX{l*@;16(Wa2_8W4y<>yw6vH5>a_nCHqw$qB2UQI zQyg@6x$&2so!$0iX){tBU8WHLk-|i#Fa-9L*~fJ4CPGVbbjy}rrs3fWD%PKUeSMoE zmOU}Uk&%&_>Mfk`&p2?1cPca-VKNA+H%;YwxtOEwffF~=rY zL?<*mmhca*%A(eNza$yV7ihAkeIUGhaTFnb>@R&pEh7Hy-H8l(St#C&)XmIYf-QGk z7ferFkEC1P&$omVVUzVCHFc^I)ZINm@(w(`K{uPO^(vXm)46TTn^dw9_OnY&Z1Iv{zR5ZE#_8q)i;w(aAclokmL!(0Gv_p8xkjczAC%Uk--?9T#4*WK|i#9dRu$-9S_?B}$=*zB7 zbz7wpT#b5acic%#_RGQO4@~|}mS!MI7DfE|%#OIC{=`e&9CW@dE^njaA01NDUfHp& zevTI^&9F*IBaskVaoc*nKrQLDrR#$oc$a9aa3lR4&?XCjlk0(ijhz_GGkLhpgRoJ@ zFi62vPP|J3fJ;C^V&0bM6m!*p**nN<$Hoch3zl<;Pn2#f$V`Cf5Dent;>D=_s-3u> zaB_Z#x&R3WHf7?!i?_VItV7$aSN6`jk=ckN>XF7DH^n!UJ-mHO4fV;fOJl`_~yjKg!gBT^sKDgnrvm}(TMa#;TUP&K92>T#n(Q+M)PFjjk==C&6kFF zj7T6Da@nva4=n@AzJBFk=HlAP&8X!7j}7uYcy4a47)WA8oU6HMXNC-`X+NrBn3aE+ zf>%>2U^_f`+|6Fo^})*w4CTdy1nAqRySwb`ByU)eZ24@GIayiGsu~&_m5oF50$cs- z6y6W;X*PcXsV0IDo`el^`}!5Nw@2@$_;@Mly zBk|kw&B7SBi>ok$_q%`u-uV5@m-i7r_=cX#ykI8gqViW;(N)KP?1A=hPEG%lpSVE&}HF62G4u+9#Fc};9VK7wp z??%0P(%@xoC<4m&Ku$ryWYBE{{0mme>z!)l`Z@RL5v3@@)ft=W<(Qb5X9g+v9Lhv7 z6s{&4JV5&@GG5K<<_lrm)53pnED)7{^1z)CiR5FLe?}@Z^!EN_uF*rI*6t@-m1D;B zpPqgc-9V$&4l-1agK<5e>bPrLSo|Sx^N#Xr#L!fc%1>U{D(q7=mTW8A9}*v};v!f1 zhsWdU3;R%)I6ezS1OZq_tafa|f>uiiAw#rrz+mRC6%r#H2+0@v`Xaf{i(lYv$vK#H zV!stH79mScNl}l9i#wxy_@kfC-wx=g+P=ObU81ZAHrA%|d?hAOItsf+46nb1=8#(HJRi9-^;bn{Zvk*%y z949C-a{AMFT_BwTjRoOCMLP-3W3kD`1JLhd4dYF0LEBXN(vqH&bMNc!&Y!C92>m|x z?Y2MOkcB?*QW?Lj2_u0D{YE3`?apxf8#)m)mULpRL48Er?Mh6?QcoV6&q5jcFvdJw7)KPc|E41>K^ExBzPnsm%*c2{^sv`gC(1RmyCO_Xa#J28^5)0bg*98> zg3(#QK-o2{P@Z}{82t<*o$o(Ik@a$aHLU{}DDM5U7of@tOT{CB{Xn<=alW0^HI+Pqc0$3bWG21}-9T@}MV+eF}t7)Mr47euEB^U)kI+lmV5q!SG->z{Z%jyMn!=6a> z3v4SYrX8XKQZN+}7DoHK&cIJJ%^?VV6&oP^jJ8PR|6E^ZGKZ@HFVA4-^{9Mi?{ zbzuni@>0;W=5660GSw9)_ zkDt&5zEm@NVeT~A+Vbt8w8!^*OTgJafB5j>YLadPr^#D;y^CiQbM6=KxMcKp-Bi;g zuq**uA!_#C-D08vVv-85zbvX}<^mO4QF-Jrr^cUO8!zJg?$Z!ysU3>9|1zoPxeV+P zP9`QM5oM_*@T02uQl7KFG4Y-BVmo_a&bjPsv*H0sGzz^rW$0!@6Y#x8B!RR*Oh6;T zaL~99s@-#Ey0UAarFZJkY*xRb@0k1N&!3XAL^E>xZ>fhoNhA{F6d;3#6v&lq@)ew z?(S|&3rov9ix2xwC+;_RTBMGTAKte-edoF+c_>q6U7<4~( zcYCcdoFhelS9EK1@T@g9{5(D`4*#j&30qWTWCwT}i8}opSh2euZ}IeYNjVa!93Ir~e)vG~YW+EmSe;+k7>hLkIez1>g{ke8! zYYw!T=*iNT5294fSV?6nh<7RSKvLuH7)YGZ$ZLsGzREmopj5J@u}%>}9+9$j&9=laPy5Wr|d|J`*CGdqWYHDh_kx)&+SLE#jj)79U2P(GXhj7ZJ7UNH* zwitQ&`G2&EC$2KtqRiOteD^{ol+M5qA7+o@U$CeQn8LjdPuf^OCQRhBc^|^F&q0w| zez#6F#(H$(rMy0OX3EGsQs!*!>$2D;@#yJON_9>af5@*Rn}SSndXC4Bvq`9_n``k8 z))(S%#EGHkrq7>Gyw~=#2eMfPu+ciY@DAstzb!rJgLJ(P^+6|_?xtAD!L6%Ixh;8F z|F{T<*i$u*Q+p4QnmkD8XG2d0q}-R0F|nfM*I(tekQ6=)!J5ua_n=9h=ZLsjtN>d2 zpl+Ms%NpyG+$(gCnr33EKvM>~iqEvh?SZd{0jcxZbZ&{;cF0l+1eC%Jh`H@WUfYwY zFr*)v3o_v>j{oduvUc03Un_SeQd@-+cnsPYtO8=B@-xRn!ixb?PSX{%TgvRLK?k#} z!PPTPlVJ2WL*bo-@QQ?OuQ%VWD59WOSg;zUBxEsqx?yU?ohW$W6NiU~)z2;Lthj?6 z^WssH$a#Bu@qX7k`ZwM#0Z9U{@nlT(0VDD^Bht(XfrE}FZbpn|(lo`}qn^KvnqYWV z>Am~=g`Tn3L@gg5-|Gp!iD>8;nI(-fyLF|tpXAqAX?&=YCMphv;x%v%8_O#y4z9P$ z+v&cZTnUubEH(mT`;+8WLEQ2}RDMlCGF95O*>GqZs^Wk;5*o9pmOPdNFnv#C&7wNG z+9DP_`_kEL1%HJ)v#ZR5gubBSseXvC)AXn-5Yy?|qQ-s=xkT-zlgP7w{qiM^l8)}K zzkA1PxWE6MwvLWevh`E7#E)0%B%WgNeN`n&iOG?C;Z}`)tg(J9^(bZL`yNZ*g4K9_Xd8a4!4&xdG&wDuUwa<49}hEpbNzuCsg=40vB(dFns8p%oqu zBWU^Ju|C-NgoOp`RkM0GHystm$cvTT2|_i^ z`m843dX~o&IXO8uUUHGiJ`^5xO=P+~nb0#W1i?2o=^r;8F=CkOy3e2A5?_7)`~%+% zTX_YDuq$X>FM56lf#Zn3J6nH`4riNpsjokNQe=dOb0r5wPL;ga4wbAh8wqB-18C?x zDmpqN3fe>lN#h!j?z*WZID78GI4ae$OBRjUGSV)ZiP1cgBXz$FG^=(Huc1f~Xi$zU-{4jF2;zWx9YqFewzK*^ zHT7PYmDTnX^oiI(pX~K|vjkgjSA&$+IAxW;S-kJ&kkBjXd27EY)?36>nQ;wu3kG`F@2K9WVQ_NnYM!$Z&Ri64Vdm&{_ZRQATD{hnA^V8D%6( zY>MykV|?+XUxe^^GZ}A0%B0ShDaXGq9p)<}7H0@^Vj1Y0u01sEX6Mgb}69@mI;J2YQB?1xl}4HH8ad1FYO7Ony-xk=f@!xfbK+CsO*k`_)!b zzhNSMilLuuNBVg@Y6u2(xcueir6~(5Yo}YKaLKmQvpX!W07;|pz3 ztmFe8yD$OdHNn7P!B>AcpJj?1x<=)TulE{$-+k#lJ&?oOgL9i%N~tb&cVU@a9Uw zBFz5&AS_vog-6xpA$a1nnl6U0*?&O22wGq0xIgJu)PNV=~vJM9JggM40G zsPij$1886Gg%^Aa-UYe|UYotM)i@iuBY@qn|-UO6Y9W^A4INgm+N_nOoi-G?!<-3YownWG0WuAl3w_%K3B~)H;*6| zaCP>)+dcXFtALn@=t=`ZV726|0Q^{`R zF&mq2;Xj1cEj3arO%lUgq?_h4_u0tf-_gVGBv{SjMzZJeAH6057{JTYOFxf_nK9k`;Ve z_xSoPp{`o{G_&$mOI6j;`-6j55SdeZj1d`+34~iC$SJVpWw; z_c@9cMO^g~(cLO#qn`K~msIOZXJEq&7i%ThKHqY3RZ|=K2$UoJCtLH|h7l5dSanpX z?Yb#z*d~3)jagzo!<)19Ji7fQKDg;r2uaX>t>EzQ?kayzvBX_RC&bq;ft>NT)UPV> zH6i7N7}KAg-rhwG_SQ7$m^xncD`pJ8{$j$TK_{ny6z&v&I71niN0PN4%k;Azh(0;Q zaT!{qY!Rqv$b83SA82E^1%E}vaf1<;gna&fg30?DRLe6Osb(wjyqFyIwPfJyaG z`0#$X|3*A{f4!dJs-7j`FO-R5=eD%M(E>8PL0}vs`YbBD8X~oX&D>Fq4F}X2*6Fv< ztZZ!Bc4hH;mH(t0Oow|oX{szE_w5Z*%5^r38S1#X64c*0zioFYl@~>$!$zK|DU)>X|I;<$8-E|= z5D>E$mUBk&zc@7%VsaT&#Zo+t%BKNJ_z1*nGR`ohwxZF$;Q5n=#~dc@Rxweoh^BWMAHW>~#9M^O_sViSDZg8N=|`TV{) z43stc%%nVr9)#)^-nH8H`dX54;7IoCpq=dR2m8i0tV^DckjbJ8*I$63I`t3uN`lTI z4l*(}X6(0<$6m4(@@T5?Xhqt{ir`)Z6z!&BzN~l2$^oyYiTzkeWxMkjcVuK^^%BIt z*RuPnIVzuETH=1}>RTEYCKZe=zCfPmat+*T_E#_T*F9cLpr0pAe*b>HjK!5Qt#7-^ zxuZe2x*nj}>eInAfyE?i1d{y7C?Pe~CzbMehuAyZ-rU@L76fg}@{&zl61a}!uTzhX zjxg6fkoC_QBlF1AW-1PwLPG-Ht;R&_3vHp zzLX#aCZ<&Zjb#kb(zc1o$gsX8 zZ@y~a8lX&M3U-hwpw=6;fh$F_MS1Y{>?10#*OjvK2!2@`1WvpY!8fOhEez5ZGixK3 zcMEiJ*<1Wa1{XGJDC-x%@#v&zM*t|+$cw_TU0IMp8A)LG;aQ%@4+0iM(fL5tjUOY^ zNN&KZmq2|{Dxpa0d(AC}ck3f$zx%tkSf|{iHQ=lB&Rpa1Bq$UY2Z)%ngE{raNRCEq zWaQ=OyU(b^pWb!PB8*CgaTLVS=ZZU$l1-AW5mD=(H8n~K=`zM;v(ub|;b9XFxB5`z zaI77w+iS(}r?Ax$Cgpn2z1=Gh&3vfrz^7eiBM-H?I*S$+7Uz# zHvNRjEWA4!&;~(P^#tMPW;1-OBixx-Hum^h-~ z;GSdG+NmheX{7XB^+0%^YOcXV`p(LLj7b^okGKXg;*TTO5#kifAVumOnBIg6lLG45 z_u+hj-`|VSOZe5i23m(y7lkSD>W5!VytG1PxhnghlGl9?+=a-G26xL-|6?nG=s%I| zLhp`eDAYX@%Fp=ZiDzk?mxTW6jMq)Y(@B?lJs@J+@(T#$Jm4otdeAj`sC*EDsWd?! z=49wf7um$S)#Ir#$sU1E+w{e$6J zrK1lyAj2;>FKxuq33946dO&?$r8ctowzBKu=|Oa@?CpIP19B##O_Kt22vbRrGF%i) zU-MhHw~0vB_P4fP+W}L>#|SR8w0~@65GWJtf#0vkDtgl>a!hl)meDCa>XK%7=r{_A_ zXpLhaoBT}oVz2l?o+$wMDkp{6{ncf^iFdA#lmkP!24?8Q?=r=M@G_{g zur)edSh-l}wNzXM8z_#3MmhjZf9Iv2O}&t+j6N|wZe(AnzwnCb;rV&zc6a~rI(Voj z2L}fQSUa)gpM1Mq>ZNQe^>c|B0?@L|=1&WS0TSB+u6O+PubjJ+vIm#4t!EwN_(i{V zwhO)}ZMgbA)DyWlX}`a9Z8G%E||+m?HJ;=?h(zY|^e*tqE=1;C5WKgF>_nE4Md8D6L+j?ce2pP(euHZl^Ql#cYX z@n2h8TiW!c&g2b@=`f_mc<$qO{g1J{4~*r_&}&hIm9y{aJH_v0T>2;uj5@L5PHz;! zDoG1q9~yfLtzzQ8>_c;c?hv0q82@z%+m8v56cJjGcyUiyjrfpo@(ewzS-InCe z>j6(TUMx42GFiqq$$i`}&5RC5Xip*~nQ6EM^a_Pe{pyJ=K< zf}LjX=GJkG%8%wT%XTlx5k<)%T?}3R)bny4w%rdSwot^A1|s>Wb(2OV-E~_}dl?58 z6eo7WB|~-GDD*VLX?jRm)t7ccHHqJT3U{-{_B8sEST03QLh_BKTRi$P_Mlptc(u>v zUi1EMJgO&nKH1NMm_X*HP@J5VyAvvmP+Fjdk>n?837kRXq*|QueuL+=iK9KNGqqyyeMcl1- zi%TLL7)0}#E$Is6R%d(G*4887Ey80mrEtoA+WIwT`=grY%Kmw{NiF>8&V1kfWbDJL2dQ1X9dg?}bU{{Ea~jY9_75KF<#I5=Cx_9H%b=RfOcm2G4W8&)1bd7mE6 z5(5N?xil`a+WULh!_eQ4*mqntABk{s;xIL3p9o*-)i!5AU=ZVe9(MK_+xppf_9*Sl zgoJN>$7uq#(rDbjEh=l`-@e^siF)KK96=1nx>U}*P^feQNiYEr6o61G*owp%npdcc zj|gSp*;-kNmt|93s9szYg}?s|@_R8LL+#-GTkA2kXVfx!M(hi)3GgQah3VP++{Nv) z_nR&zU~MgyQ6XkDT<8_Q7`g5P+-bBN|43QJE9IEOW4{fPTDGosY*>e=kfL`ptpQic z7m5{Y(H^Grz)#4Ch|pnAYIJJYLQulTizhu7_Cr_+!|8&Y0U&+AU@S6(l2Th_@EpFX zh#XCYT5B2^-4rt^_i}P@{4g`374ybbl#_c?&7+X`vFr0^w!Y9{X#P8p3fRE(iy53x zKVW3os(?*T)AS1zlI+}&DkolKntS3cc@t1)a6|G&Xq8vmfoZ>2HM{%i&&rD9LmV9D z=U#boc;bk#L=ekpE)y@FOr~Xu3#FERN$d~;Dw&qyD?V}?m1AVWv z90d|=6HbDSKeHYM(5MJn#032mlc9JrSLFUQ!&4oIXlj5?2hm;?VPmmmHTf#qXi}_X zfiX@s101^$n@OnvbH`6~87SDEv6ZXtYD@3mD32)Nx@cZ^X#i}7qAfoAeE%W+$GbX$ zHiFfsxMUP;7q9{M21D;DWiGshOtthXu2iK&Px>ATUC|SlabGF*y4l_PI(@DVb$*Zf zpQC=+dE&z5ynPGz5%hs}d}iNJ-ae(>jCg>x{!FaLR}1j7ZQumumKR@p05!xLM5^jR zo>9t>D@AVJRF`Mfr5)($5>o|=1WGSf76zJ*#H;USD=ig`+})3+G-2w@Y=PV@pfJL* zI9NlFMuA{sBaN6-(^uQ1Gf16`gHr8&-WqTGf}U@wmBTkg%<~CcCjswv-K9wt$5_vY2%?GA4xsW%_pvWCgp?q>#b;U z9hGt&k~N^}-oPpY1gfdUQ-EV_`m5F7M`Z8x@~PV&IbQ&x%L|f2BF z8Tk2+w1z}`HasEre(_NESXB5xzsK;8_niB>(S^Q@rB3EjekYsnX+=GKbF_cYYY=&K z_-YP>l{ensUGE#!*!@IEtfpySrRTE|P|(C@io5nw$VNWpM*qJofIF?PL)PkyOMU1n zy>B(+=~U+Btrv-WC9n++tfV%u$Tf~*j%V6=NK0yNWs}D)DJ*>uMhiQ!tft?OFN=~j z`oOR{*0+V&8$E)ANXa7_j#oc2DOWVUA?Dfj`%@Mq0$VlI~34 zWfuWY+ZIYa#UMn5aWuGc84@dCYIf7eGgYSxxTge=jd=R|`xSnmRJVODD{Gr^sBM#F zk3AA-`%s@%`vA^zp@1&*z+sLVY9JZe=}JKlP4wpJq4*2gD zx8iGHroKKPN%jflMnu;!mE7sA?%>jWb^CL$)(v#1QCr!YSB9_hoBe>BRd3=wV_j=u zI8lK=YTP!0f>;lOtG{tjg~QQ&&0E9x+<4AukuJ$Kc zf_1qEe4p-OIM1@c3duCsNF*SYr?ftpe>?9&P8*g;CM~~a^9Nz`y4rex>udhCg^DYKPE!s6mPlH6# zDli2&HL}IAMR)G$mQt3Ec*y3b#*S8=sF@=7NAXD@b8Xp~zX4GLF`E@+tjG9P{U6)$JGa-*%~q|Ene zYjpCM%-1dTm!Z)-QiZeC4ijI+fZzY1n^&a6svU#|=^;2cFHz)%QJzL5V80d44(7Y7 zS3kP>z!>AuM$gofgm8};c^L94%kXeC2|f7s9tdP#6v5sEiQ-?&H)cm_P^XXP#2AMY zwb|8RdpS>Wpp*wI&>8VzM!P{UR=uo68GrpK|f zhvi`5a*~iy;oHrAlX8jA(M>YC*@ZdftH<>CbIt#crmK#M`ib^*mvnbacPuRkNT)PN zcM40V2uOD>-3S7b(jCG|H`1x(4-rLp!+YoP7sti3dv?AvbML2aV*JDx{Vl4YW_usm z#qFEA$V6&!fg&L2qmyJ!sYhcivK0F8;jtld=;P6m!*aD~oAh?tmJa}9^oXc=mdk5i zit7VKSHXOZ{__~WU!&H5D7rMP;bDi@m*x@3k0q6`^NdYRnbl_;&D=p2-vh||R50kb zN6h7qpKSgIdkB1+KeSGuUw~ra8VE*upS-w`pcnROlvB2rl^y{;d0dlpLcUi)0CUm+ zJ;pmo5;0hs+qjS>@by)Tu6rQwv67oXw*!=l77{d~H{9S_A5M>MOg(u$S3oE8bnD>` zKz|QR9!!J2brPudTnIWTp)U_`z0;RN{^Z!h#{X+7egg+etzrra3T#`W9z(XqNK=g8 z;aU`$bkfpAJKHWQsa+X4cIT#MW>QAPiWdm-;sF*gS2lk{{O;14y;y*wVge3dMp!Q< zpN#8wMY(WCnro);*z5!T<|XLf=-J(Z*414@Ss8rQ?WJmzmG=8CJ`m?M@;lM zN-N|0d2x@Be?J}e=+NE4)M68G@N?+_YSF2y{mIJjUX$Esn=K5ZB$6{vUB5gT*XxT4 zu1P=gpk4q5hyRl=yjRTJx5ssxUAeD?c_{25M(v7;>V$A*2APq83#5HEC1on1St^2_ zE0^DTq|0y9A6+DK_0r%RcBuE#;QD3FPW0){L42iz*WMTnKpmq`B$ddtWjx#nE&2f- zo>^8__GBcl8Ihr4L02+QA1#EXF=LVy)D4Xt$WSJ%{ZY7;B6$L}~=4=5O#50NY6 z9HF&L+9|>MOY;udeJ=LFT`KKcrSOAKxhThs$GmGiovP&2jjJMbx{{WOrD)}?)1_I z1W^MS&kYj`_^gnIB+vzva@4DxNIq55T3;{^9<%sTQ`ooXNHQ>E>~ua_7U_wGjz&Bk zC!O1a?*k{Ktj>dh+v@=o?57;%{L+LsV$}%v;$szZ5$U45l73#n8F_huY43Fze`f#3 z_K+d@oIXfUfr)N8**dO)ER1(jstQOjgoT9uQ;%=desAE-1b4x4+w2nmQ&U@Stb{?~ z&ZigQNg+Rm`AxR%HCNA@KR3&WROnBgOGb9~?`O=fsPg}|vjts0@io9l7-3zxJ$4;O z@|=f4)NNfdD!HGw@7)GEp#AD66V32nPu)>2I)W8R0oISuw`0&LundHB@n;o5Rzp(u zTb|Lsb;qujGGE->{HyrSFPeir_rLS+p};glB*i5F@!8)42Z|ej_n!~-pf&NK$7>5R z!HpqB1f#w1eDP~LPzl_g{bj7L<28qFze{|Q!OEoC`X~2W`}&3oKXbYRAJd+hl~sP- zEAm$(KGUU=TYe>jNS=Bw5C&(HavR?Rhvg>P0$vd&5FvAvgXo?6Tsb%in@L__(AD@F zPzV~u=;He{!!_^CnW7+D-(I5)?D4FBGc&x5Dpdq}Q~Wg-5m#Y@5Q}eH<{WX1V~`Wi zsEcGwF$%<+@<)GN#G>@g7Z`VH#ERXchwz$VN_rS&Y8|8{Htn$RsYPf7hvk{gtCi&( znb45iQQAP9n!R6w-wGi=%DVuqZU=51F}D+Et`i!=6wtuuQIn9|5SM>0mD3p+$;jnf zHhlwIp*A)$TH#=3MoFKgr&dW)ziu2HJk^C>D9F4`PTyJ;Lh4wh~>^qlzU&i zGS}cfsC$@kJpcwkN9iWa_k>lHuUDeC_zW-tQh5VQf zFh-3-FHwp#0g&pmR3sN!M5tecELn8x6up;ItySfjNFRq^1A*6|ga-ye-i>`ysRJ&d zP=H`L#W$wN<7m7&%TCkKRh*_}K`bX;S6JyXg5ps{m{#1o*a~kcfzHzJk$~ zovP#K{^9uV4btO+G6#=D48XqxGZ#C^Vs_le=I!G92@ic}=EW42+D&RZ^cOxJiz$sr zJ4_N36to8`$W38+I|YaLmVt{^HjE)h4}WHBk7D(*PT>w!pv`O)CCQHz1|A5t_ex^< zI)50WE^awnd_?kpMW6?Sk&WWuuZe{Kx`6|9B?wJ>s%|U2Ak0go4yX>aSY~5-1lbPP zK+%;619Iiw!~>Hh&wXJC)2Ur zWrk@SYn(r6TK?7I*6>eJNQ6bV94e__u3Dy1UlBx&Qj@IHEA;fsOeI4k*|bOOIBX?D zVj_X(I^;R9>*T$lq9fX+j*T!XVUH%yZ)Y%i7I)E|Q&=d&2BeH}WGIC8)K$SAO@m~~ z*sHU>p`oupER%voz;SspsMaG61y)ni7kGfRn0Zl$KwfLF^8JQeQnbKz2+ze=g^Cl% zQswGMvy($ELsL!aVIAn;;X(J8qZ=x(D1MS@z+9t}aY}8>Gdhh6a&p8s?3x{kK8p7z zfYoB_ua#QpQ^CyY|9evScz@Xbo;Dz6vdxol>YN6alF}GKAh14qDbDt@l0d$+I3mwj z3vH29(_F%w)4aaEK17U>ap$e*DGFVhA2=4Imy5#jLtoNg9y`gGhc^Uvr8gw3UwZbp z1Nm_?2&H<@W!@zw1a{$wJ`n!W0A3*wv^l#q?@Rlp%Hv9+&?V|~IsBusLLc8c{HL(5 zAw?zsw$r|Gb|0wFZ-+)l6<)h*$)wN95XoB(I!4iX!Uc(|170UYIkbPmm9+s3Ze(g& zT7Lqbq+1(NS?<0V=oMPy-b6Cnp|+q$`U&>54=^tRQ5jJxM2{h;7gmzl@Gkzq4;bjB z<3D_O?sPCj;ju#$Bv9@nKGL4|9uY3Z{l9riXF#48Gvj&!JM1La+=Q4a{Y>Rv2Wao| zn?^`VUf$mZtHEebq@S%nweT_tn!d^6RD17?kQ)MM=WAkYEMo9o^fI4QW9>}{5cf(j zGM4O?CQ0Wal$X(%6IT&0V=~M?W04Sp^`#TMm>x{EQQZy!aVR}mQ+ zc}q+z|GWJS+ZRNMn)Z*vm7j2X#?egzk_npnEHy~m`mce8TeAzqP?^x6x}Yd(M>Hy7 z8q{V$9)9myqsaY^WO7^`!^CJ)C{`Scv3h7gtp3?g0*+Mm^{?;7uAfu*1iK)c`S zZZqg7l%=QT(kXYYW7b3I2-V#0dJDh+P7Ob z0+*`pvEkO)%(j3iyY6n5I|Dxfw+bQ7Cu}{-d9^K0u^vy1YhE|{^RnvAz_f zo={U$gHDrLQIxw~i-CQc4DTmb_>CH+CN~B*OrL$hYwmpJ|8Sh9DcxZWI;7stiA!zO z@cakO?xaor@$m^>pd9h3eJv>7Q-D@|wwu+E-_Vo~pqRD0=ZESk}KY?|`2?J>iKfUwGEsK3Kc zuw5kRgNoi!8h^_mn5D6HK@@P^VjkM?ZZCLX0`OZSP;FhP&Bt9v>8vNl85HWMzCZnM z>+;a!3dhseZ&BBZ^$<;;+lGI>xIvO)Ow#fthE-TURFBB?Gwq%wp|wu#t(oVIu?At$u^TJ&z%(%6^Hi#XfJBzLP?&+<*7yxm398*yr-ATsA)(! zCf{4P+jcTD8=z?lZ@#-?6rWm|BjI}dmi4O0^QZ`*Gn`6?G%!cSXv5^Y54$WtRGkWP9#>qG1ryz+Gu4=RepylmT~fQxYQw6)BG?^lz8{wW%=O zY0K$9W_VXGK1eab!^X#7B1OP7{`(ZxRUq-UlNktu30>TDi1%6L2nPu9RRG1l!8FOMH?sxNf!|T9Yva%k%8*fbZoBSx%?W?I4`)1Q1`Q)6IA3e zpgo6}5k*VUD^j*b(W&cgmhpz_)e1Ojipo>x9^$Z_=6aFrPm(*Am zT4FE_R8wasPaOkc=AR=DnZo`!>@Xji^8frl43`*ACXbRE0Qvj|5eSKD^usmqT7~=J zk1SUdVen+>3ZD zs3*!Eh(=wN5msvEXZ;sOT~N>8z@u0sux4tMDOvL}4$?Ke0U>v2{@i%&NJ(IsY?UqDf{5wf6f=-I$~dI&Bw7_gPo5z5zJ$ic)h;nP!7 z-GLxx2{KM7Qsa%m5Nep_F6A1~;rA~VKz@fHcB9Rz>ZPT+s_GvAwGqYZY3b?v;^l)3 zxlF(kBjhZlb)7<_y6z70tdJol+UY1aL(ji`;&)eIDe_!UlY*ZDysMrf^{^1179!RO zf{2XOuLEu&*Tdn4?#5WmtJur3#>C$~gZB!Wwrjq8C;l3{C;V-hw)q5WBCu<`<2CPs zHg34}&RM<{ru~A(!Y?PP2e(;Z5639d#u*$K7^nh8wH?UIqs8{4A~-9L(%HxDoWVfy zr+o&}gG^`&4m{v^_jdN>>9Y*JU;bH;ei*hu!i_?7YqV?Mn;+E&rsy_VinDx1D~&%(y8qebTQwh z_z8`B)1)2FRcgKj0Y0*0GZ+PXIX8tHZdo8JX9F*z=vF9JYXUrJFWa1#+$cuc-z7En zF;mi1(qe-@fc%tVFBg>PYu%=Xe2Fpe%gmYu3L@< z+rEeV-2|b)M=4Y`@F#|H35c0x@9tER>qt>DC^W6h7TY7V2w=NbHd?~Xj2s%%vK+4U zKt>6yW1I8f?_GD?Ba`jf!g+XjdIW*Ct;~~g!TQw_6YUv|1Q4hWF&~(gp}^;sZD`sZ zW=i$~&%6CvxF!pHqFpZjiVF+(0@~?VAsS~!(263TEq7=iV&D;5!Y=EwUej0g@?J9x z&o{ZdHConbZ_ns2PduDXupfXeniP^u4Y`mVV?f=Z@KP7&vz%RmLK zpIin+FF!x&v;DUiGcL%)`+I4w;#1W8mNUcI4m@8Wlz z&KFn97_e)O)s(*5^L}!R>>lMG%G~=Ne9id}ge?`eHt^zYZ6Vr4_HZ|Aqs`gu*OrKGAgav&v{kyjk zogBWth`+r0kPh*Nd)FxFlBHS{jfI^ujtq+UZg|6`M7wSlO+LjsCnqQoF~L_GLo9$O z_!M+JYxU2N#xFx(a!2)RqEkxxqrKq+Pclm?GsVY{*OO~icj$u&&oRQXjEIMkKszHa z{SqVC`)Y6e94z@;FF-{Uy$&-6&{gf@?@^g2+_}H+I9&yH8V&)Xia)7<;?f7${XB*5 z&;hHWHXg`ZV&nf(oCHpRpHU#S_tE5LAmF*cpi2J%=rguK$_U4jM49a05I|<|K99Tl z)RwH80a;2-f0wWWMB5hnA4-q7eRf^oVBJ|el8ODE(?4}X;CiJ6mqLzvi$p<>(g9J( zcjIF6`dwgMqn{+$X(eJv_Xa5J6fgqqI-1}3T<#1LJw0A2T$9C0Bl>~~{tty*lS}9X z*I#$X{vD5YZh2c~6+K){K5a3dv-P_&yL_SS!<7!Esqt}46?OGsRJ6RT-|Ti8^=)ozu@2#Rn=p@0-}afrgq4;YdGZkE79r@KC-LhNtV|Y4hfaq zHCf0Pjr$;EzZ2l8Q7~?E!zHRwf!*9d29JkgiI~2!&O{_^(~A3;kw?ciwOGyZt7cI9|NkrJ@Cw-cm&8c66=|n zfs9W=y;tw{6x?ZD>OZFd8Apf-ka6s>iWTtJJluicG2RP#j5|kyJ!YvvZ?sLYqC;Rs zdDCpg7Z751yiX-DiYcU-nT#ZX87bHwGz?Z7uW&}%bwrCUG?IzY*gpAlI&NN0^7j7d z+=+W$bW;DzS`K3zBr~41bLdtCxun`>u3fzg{=oU`|Fr-~b6ACuysstT(sX6lNG*Q^ zqFm!$a4;iR?V7_sf%a$<84V|_G>O^bN(@xeVrcui0HVO=y+VlP$p zL&hA;&fb%<%Q!up-QQhX13?mlOT|o@z3TC9`fRV9iPYX(s6w(NZr|iVvc8mG z60i53jC*N@7QwC%jkW)c}8&28@{j5C-+TlX)$HzuLnk{V-v%jqy zLK4OAv?A!a=?S$uG0g&A9nDIT5_2%xA#xxwDq<+c`CwwipvWB)7&Gd~6Uk!~$kNLy zub4bYT~GZ8ZFcGK^HV_D{0o7w2Tp=5W4|fxJslXYv@0*XMNvqeSn5dWu)P&k3hY=W zG*O`hTevJpy=9I8^@`-oPH<2ItljzFE~A z9UTpI3QzEwzgGLB8voKg|H$$~C*IjhRrqyKoa0OCr{3rt&@R#cpho0h;d||59*gsJ zDo-@<&)>hi8O-BrMi=qBDhwP%0zJI<=++aM&}saI7WTLRI384kpE5!HCP0eWYCmSP zyWWZl>z|bPV6AJh~p+H6R0O8T$fE+ZCMqQHmR>t}%NOW5>-+%Z9j+TKThE1 zeEcWOz);MlCnGpahc7(ynHxpOnRf<1a-kAu@N>B%B|<56UCCo&Vq(1>NCHh@<$Fk^ z*E*eKdPMf!D~A$yMrGW@X@EteWfz~)}-`~D-Q z@>TtGxUS8^{hj4^aymM?S5%b&NMCltfeJ|1|7!0U4jOX4&%|2#^FG1V832MFn|yY- zEMSk*qQHC@Uv$&KE3yaGWK~JvI`lyv`h9j^>B4mD->`-ySm*0H{V}qySVJLC#!i`GKcF-M_q1bXkIOmKprng>E1oXpKq<0 zGp2I0Fl^oZ2TFrg5Kt{EZ|ZgfDfN{KxoT4m@Wnrot9N_jMC|z@ONbe;mJZoe>cSbJe}mvW4FydTtDb3#NCWlCTND_0=apg* z2Ds(_OG~g}^Ha9{=MKJ=2zOMuYy_WhPM#*r`=#{CnRz&z*Cfub+97Gy#2XdLDoYV% zky}!=-~P3}+XlHQ5T&o}2ROvO8`K)8Ygm5NLufb+9&6un+2!8C)E_^0S#eK|Z;7gK zWZ$|dM1i+UEZNBs7#s0Fpg?2}{d-C^DkJ4N#2G7}*63!*VmMdGu?g^`6&lbtQQf2zI&Y$cgdHq^jEPPV^g%#~ z#*w(29-Tzcn$RJnp48Op-{EttBMU@%w;xJgD=Dgp8kOqMN(cQ8NnunBgU!xXE06p_ z*8ROMl4%=WC5JhPP5GR<6AB`|s(pcU_I$kiI+gi`423~{zhWf+l@A~croluLl;|RA zBSRXTo_#ycr7(N(u==U%dpOsmfv+s3CW4Sn?n^1){nP=QRI_I0Vd=NIkjGPWBX}zO zBbikYHK;Adzi1|Y#{a!rTePJ^Uw|5|m75oe0;B9dR)AbOF!rvhuy$G`>B&Avo@5LK16gMz( zWAmc45uzkJ_L1ruRO(9+4y zDtM#A4qL&?gxKCM;N}V!@jl1kmR7GZZ0Ip39xmbR;&?$9b9i?IP$-kbohZ37A|P$y zxgI97sN41L>4{T>K}VG_7K}yH!`WI(WZ>76`kzt7Pd*)rM^qedQ$nYG;ojmgmO@kK zaagsusdFp-%e&Y@dGDx)C8-jWv@7RsN*x1Qa3zy`euIF78-PWJQFXN=UECvUbgrEg z;qv*zbmc{_ShF?{|2DlC=yzeiHWzSCBnxu4ExYSOO`ERV(OSp>iCB z72UpJNUx|zgH`ALOLF7mIs4)5+lxI;oOQIxqM{T0`~#VI6H-HvcW#B|-aOjwTU2-| zbHAN?tOh!lrieGCOM);W{ENDt4vj-DYcWno!eLHSDhdgwo&&b}oYQL$WjZ*JtFq58 zEs-UfrTC4EV}|_)9;^ONus3Dj4kj&dUB&FBSLA?JaRr>~e|3=IE7&k#T0Fl5chx!2 zrN$1Vy?Arme~Qy}T{tH1Tvv@VPS!c-Y3i5H<$zn4S{f{)OCD3&bX$fC1T7l~HR7hO znkwuF)tv1?3pM&oKunD8z3SE_n9hIbFP*w8rhH~_g`12lZnO~yTp;zy%SVh#vaZyU zzAg{oc4$C~#w59p`)UgvCC{y}?>?}ivV(hr*rvj)EVAW8SrRHLA!!I)kb3lIVto7$ zN>b8H8q~3|YJ{U&$$C>v*#0QOKTsR06=>MIvoUGzQC`w1Llq)hL8(IsE@oq14Eaw) zFSi!cN7D}(`l`=@if{%#8&C7Bo@q@R-r+U94qLLLQ`A0RF0B!yOkfD;rfnMV9+G^_ z4Yw!OZ3j)uJzda6KR|{gYm`}=4$6(GNJ$sTMwJdmvh87ta1HU5SdQBkmPG679DGK{F1n~7)Kzvb98h-c#6`uWe$65E13fZpK z!v+}>+J#q%LadnKcY$yTrTqgkU;;#)7jaUX>%#R31Jc<5Vv@S8eC!-(F3C=h*jH9o zsx%q$QUc8HN-02n2Zc2jfdV)l3 zFhe?PrwpM}p8Kyt6cw_YW)ib@{&9As^c!x`_bzZ7z-#ntBh)rpT5~U%;~B*W!Qg`+ z5PnG=P$VcI;Gn6gX|>+&$!CyRBxx97-)uNx$@dKi)uq7I-QUFZBjTevDGH25CE}~k z@;Kt}$&_6mL%Y&A``BmIU|&d)^y}hKd^ga{Nd4%p2Ix zX{#1~xXn~#3m3|00+Ma5&KI6rJI=<-=b1ca62yjupD|$oJ6-{1>F5t7V$TFER|4B+ zMY0ct@Y=f4fFwyfN5GaEk+tdUX3Ib1W85C31IRn}p0!(;j5nUPp4E|M%? zAn4Q2V<#se{yAS_x6<15`}Q3Ug+0nC>NFYAdF&k30ruk(NLo?qI(Pa6CvO1W-vWxm zO;F~val}P1tGwKz=)o?QdW@$OcKQQ?C&MSSq%}H7A$f>G(-$thDugIY3Ib93k#B@3 zSqd~nX+{Y;nzq`bU78*p=S5+MR_NVmX+vLjYoi3%cL5Nf{(+P`U{8j)Q!d^Lms%2o z{twFqjyYkbtveUEXd{7NY~We>7vIsE5#Fpw`#0&bB3rnn0Q;Q@+if4F9@W=J+-!mt z@RQwnXWD-GCWI?H{X<(>RrTun=H{(WmkWnA(ilrxmb*Z8a)lFp-FG!of5X1(6m)!A z9}a`M?B_W0%9Wb=V%lQt><-V>=Wz8$a?+;$TL3ab;gIw0+c7&z*Jz=OAHJYjVU?2l z$6cV&R#4$+e;8*LhRw2Jl=&~W;@A;Os+-0m8|7k@6ZKlPA_X{bnM=K zQdToa112!}AD16NB8mp!h(&HiXh`I~0|&amWuP{3OLhsnvpF4O9ur`WPP*Qn8nDl9*CF}};r%kSQ$dQ( zaKlQA8~YMtcpadmq~s0u;6UT)#PlX5z3?NI^vEf@%Bc>$DDZ^FL!&81`3aBjYU=7gGkGnf<=4tYH1PfJtwddFmQk$`www46 zUeb~^_h3Zyec}q-10}7xZI}WwJkh>k4t5Cc4k!q`^QdQ!i_E{+TtS`Aw&S{cVs3(h zgToD`X~pDvL2z}I1}N+N`Y|ihs4Pre8Li}AIp)%q^kouKZM-|Y!(D$g-B#^~^rQ2O zx^Mn4==5={npZ){+nu?8luVxL2>I9fvRbD+1i{#lZPB7BQI_H+@%Msz#34lj92go@ zQPI%c!1V+hX#dCMOIxVq5*r^+9cEp)faGxP$X35b;3h=bi}JSr&#PtIAJZhiXNHVi zZH!t))#s9REm!dTps;f={-N#_7`K%uvC7UayqZ~nv?R`TPjHG7i?o=iJhrz?OGZY9 zW-CvkrX-xk+P41TPvQr4>I~-U)GxS{)CHfosKh~0n1q8C*^QF8&Pe35UN3a{7aQtXB_w0!l67g^?F# z3vngvyd>BKEg~tX_ETjlY0*?TXoT4DqBCGjS9wei?FBWw3* zGB!YHPRU}f{t~<7Pdnf#9xG?1eUQ<%v&cgKebzj+AhX#9H$x#RZN#6Px9r zKg{CD?m|rj?g`BDXM5-8_`}*iTpwn{;5mYo>s8vNVWYpLL|f61ftjYd0@qV!E>^EB z;wE?bD3ct$Y9&4O#W)%Ds9Zk(kaTU1p`C2BBeRTPfxN~WqeXLJn_6F-KjYV3W1j1l zxfS87a4#J5rBAqJz00*9VsP@uh8bNHWX;45f%dy_z17v^;%naE@DHxn2mBF%Kzlm@ z4G0L~j@vXk>oc;g8ya~R!n8CqChMzIY={h z4)#HXU;|wU_x-#amOtP2xY}W3tX`v=xMZl{LE9otrHDHVTa+i1IPn$>qVvXftDdhlb+Py z+Mb2Q_y~$d9D)ibi%Qgu8j+?3N0bZ91cLEtLlMCYL?uRaBwFUlG^96%@Uc4Ew-5BI0+ah%)H9SX*( zeb*KsY|r)l@X(%u=OR@drQ4{W z7}@~nG+F)1=wYIZ2QMxY4Fpt)oRfve=bsO@h=_1y1fg4xO?wFmNl;mRw1l z@sqzo92kF9Iz#?rd)sry;91%d-$70tYG3|Lt`)gh2hWeFht!J%HTJNV+Vd`H8=8Gc zQH}Jn#`V@0I890I-;BJsq{$Q;5v3{UsdQfkIKrOyJ;-Sji_t2r&}(|2LI(Y|_E6=k z25iM4t*U}0E~@rC^J4(KTsryQ`^c(`n1S$I(h>>g4&+oVe($hI!nn*oe)*o$+I?b= z0Tlse8uXpTK60_=hR&{RaevcoSA2!kBdKX9S`4|7{X+4N$AJ~H29U*geS$-ux>0;B zU%IO1KikSKx9pEt(+l8PU$tZFZ|=hF1No&Q45dnX&yejtTU!0|RD3xVTL;?I4J2gb zeH_G&XOL163LLa^AlXLxqHM?}i#{%GK|)6-Qz8Ej>xyu|cN9zvXsKvxyCr}f26|H; z){W93a%&Ug11GB#acJQ(;?(sI=)u#H#+%g*IX1s7Vb{SKM6kcbSc#r6UnZqICF3=Z zUpT!<{@h?kpvNs`Zc7A+Qnc@kMH>V@GnkV@uEhz zIyyR?Kxm%~eYY{*8r~;J8|d+$Mkio}NJB$Ii?lumh<^!VjBEnN9Y*kvs2alt2CP6B zM+AxdWbJR=4^USVa3+_{LdAp#_t3;d?8xmXnKSRv`vfI=UcGvCiXM+b{@dt;^HRbh z4%mw&Kwf9Fc(sKa0zB@m+>8Z%sy;2^6C5nVoi=pbK`h~B4klOwLh0z@iburSqGl7ffM;kK_&lv&U_19U0 z$o{@~a{iL`h6Z;*-F>BO6K;=2a`6jo>op7|l|wPS9S1~H<3aWY@8xLI&_Jq$kwTyB zd5g@gk9u}Cb>IGFXP~5FY!4A@;BM`qi17F2BUU zmV9AZr5a_&!a zCZ|eBLQ?(+#v*Jxcva!%q^deofd}N3O{?vT3icXu z>YsUuWZ3fUz&Y-3Yb9XApevbZ^Y9o9dj9Drbk2s;Vow;}Y#rN)1WO45V+H>NLZJvh zYm$gwf;ptjTjDF9l|=zqU31Cl$y0nsLPVs?4XV;edJO#ygaeiPOTolli8&$Mg@^Rd z!;l6Pxv+1s=bp1gx&e6R&@^=E*a}DG{AhpFQ2J4}1`fwAF__6aMQxn0t39Z>_^u+0 zb+}6o=9XeN^s>YclthRK#wH4z7#H!^O(7&G+sI_1rh7vO!@7fXYI!juNDp)abe2JU z*V)f23-(Mj$)gbs*sAU6jFJwSJaZ-v4Tdg{};S^0G3=h<%JgH6~7&rq)c?2hx^0e7T@vnE1$?yN0Eq`UksaN%BmKZyIbiChd zp2#~xuqgiWzyI_IlMapwI&S=sylP0=|hK$*H)1I{#6M-gq4 zU+3S?DX6J&0@epmr9>i?gSbL=0M;u7ASS%8WU5P!^Dqzx*r!vj>I#NzmJr3`9r*V7 zVLCL5G}vt0pJf}S&o~6t%pHe~PvmklsY5sVoBh+$zcF9zX zccrUt@^}W#>lw045i&lohY;$%K4`O6ap#$^qk zimA5hl`Gy?&G_ew^lSAmnYTreVJ0bbNEKoUveE<{<` zQO(@eBApCnx^R`?_md*ZgWo!rMR1&0uoEjC&qnhw*t!#p? z{1E}l`Z7N`LmB{BwR2z@5pX0jqq*85?3=U@Vsagfqj1G`*H%!6jKy&HKcC^GF;x2X zjtmdq^z#>IQjy|9Bw@!qk%u4{`Mjv8$hCxB#5*!AiVyW8IhZZP29UW{QfKE{!@YUG za(ay54MdnH$3YCxBfx>KXP(cxxK&np7_hkvzEtGTxqi0n&fGmpj&(6EM;&!i4~>QA z=K4*ZvxpnXfVT{OMo#YV8F^w8HIXkD+44R2plb4n)N#ED@* z$oSpf-oD2g_@$9G;|?qkAN2skhFikE=z$1X8?yQ>R8|O{6=5N9adDaS91_LG`j63X z-Z&3}3b}$DCt8$c58PHqwzqPiG8BosnNL)m65 z`eF;dW!eLwZ=METq;LjzO+7um44~b5U{#qlal24jcBYICT&JX>T5AB}2-T+Ijrj$` zUz7qJ=wSS0QiY?Y^A^RZ5#lHEhPh+Ao~Ff>yKhuDFzpzmii^8DfL@gTyTAW2wY`o5 zo5Jp<#~73weVxgo_oBnK_$781v&wC}lC?W%V3l<~zfFIzxQ2vAiU%(Yed*lsN9$&& zjPH-2{{aHAcGe2e;9@;lkDy;r0BmbjCI`k;BM5I&g27;UEGnEkNKjTE&m|!CT&uMi zPo2?-u;&yKN?-ZxNJQM1T{U;S{_~wrR?f@o2?rtb8BjwpLv;{o{fQuOFLaV44TVfw zLr-c$9x^0{GD)#I$LWPy!`>#(2}fNvHKc zP9Mcb@e>xGIWFdr&mX}kRCP7-0K@p|2$2+>4NQP9I9gO`6;s=0X?-(qX`?TIUhXKW zfO9UzDjQ9NRhVa1X`{rEk9|=8|Fr;}xaxEC@2Qt6MF}8G?t&Us;V%ENfb^_wEcQBc z^b0lM+ZG4~g$fxUjLueq-jw;$(swA})PQU_6ghHCb1(F;gI+WkptC|mG(ahK?1>Ep zyep3d2qR~Y3H0qZlHU>Ibz5uw_!1Zt9on@L|deN^G2udPvc`iVSe26@8M5;jBI_5YQ4g*pUg%wNh9*k+97u{;jjZTvU;`l z$Z>HGlq{_P0DA6_YoMDvp%1XA0HC-sFI7s&wSJGP9BZDeJ2VBhQXrjaqj~~z7{US) zP$~aYBpyDfNAM3yMW;UzB%vQRmeKw~3xR44E-m?iS>nPQ1W6xXz!J|=;LpdtMEIkc z4y!J~MR6fSlIXA8>{U{GO4;L}Mc%V$C7uK6`Oc-KrM*=ay${G45-NS(pl>Z&59Sti z!&%3N;i5%8Ns9!TRVZzdUobXQ$HK3CL9ki_qhj11G$N~X4JG zmn=Rjw<4K2ty;H2?d||Kj*iXz-Var7`D>GlIF)%&RD*gQ@;H#V{4@vIi^A!uPJ4BK zHkYU&d1*eDF!>lXMeQVpkW0X|UJtsV!6>_RG? zStg$=tieRp`p9NL%Qs1zwJG97-6jrB!QA)nM*;M9ABqYo<$tBFesg_su{^@3=9*iP z5g=-Y3b#u#b8XjP-~wojQkh#0{6lC)JzG_62v(E$#0BawSD@@o%IuS98BQ zaS428BsR$R9wel$af-?N{gQ0B5@((S$#8eX96C1Q>T_m4ht5;V#&3Y1gyMeYB^}~l z4AVpev)0=~VI=qqgDY#bJ=bAk=f1aCAC7ndN*rjLbE~?4F9C(cN*AFL^TvIb- zi4`57r~54>$7GI;r~1YF;^z;~|YsD6y}Xn_bnXiR3tloz%0qJDoQPx1}1 z6Bj}!?!{aNcF!q_9Q!s(m=ZP^aC*!&8FKcbi9Q7}*Iuh-Rxb?wjp4^eLh)HMLM-Sm z=o1pKNI01rh)<4;0((naH@f_rb9;Lq)wGFC-mJZmUhvxA_k{&Jnp<^_4H7GIKaC1$ z1^0-!F8-GKHDppT<`0nLlWrX!i>s!VNmrze1VN=d(6>H|&f9&9??u1gY__(xHr(CO zRsC7mqK^3XaGIupkVQ2<`i(g_dPF6cjb6EFJF_KZKC)T}Zi|YAzvZyvn`D;uInqi2 z?#vRWNRdRRL9KT8Ej%{;iZgY+re zLYOA6eiM{v(ZDy1KqfsCTAn8_4wYt9A*_@?7{U(VkdWv!`}gO@3X$pG3t}5kwtSb= zHcE2wVFI5-=$j>9pPlSS9wREv{}O@2ixk*Y2IGOsTh3C@WAkvbZ0+$8O&t0#X4H!N z`xo$8V56X;BSYPeUzqZ4|Ih@{#35}v!ygoWhY5NyRKCUahkc*$q$b|irjm%EHs+dq zkN{X{h#NIi^TWu{&~HGo;EJwf^+VuUC9gHC)DXs zpEN#FbR|$xo2zuEjDn1%To;HAUbiWyFn+Q#iICsnaAn3AFvzqmmM@%bWIpfB0BOb{ zfZQ&2$S@9;{~3-E0dfgP2qYZi${Xxg^8*IEQV})YkmWZ<(ob?FQjML44H+fw!nBB6 zo-E_v0W*q0{w|+}t)p93;B|*rx&2e`za_1I;J-PTtKI*PS;lD9Y~DiWepv4!snW4C zsagKhy)zCo}8F- z{Gz1Z;RMOg#s!STUCU{f?HVZ1az6wD19~^;?jAwZ>tXc|@ttuUtgR+4A$&S%F5ugK z_$QX5lA*@eJgNtTB;`jI!?xxwJQh8s$6(qXt+Mv~d!^DwEb|{J_R9kXD`_7V6r;f` zxZMh`J_H?203^upTJ+rKxp?|1ojK5gCUqycK*KLzZ%Btz%zV z*ECi&%AP~u3RU=ei~6iMD`wE3X$W8l{6RytFyfOcTFn2w*z;R(EM4@2nIeCM9B0dLC!30i6&F%m1LhOS)*olH$3?`n$d4|- z>r0e4(ZR2>cu?zIn}2H0`~MZq`56!t6x0Y{zn1YrnNTTH#6@6Fj7bf9!*5Qk=zjsh zPosF~+G~%j9`K~TC{&>8UlE!xdoJa)2kZcQ1jSXcF>ImUZCUSTv!gCJ$QoY3|AnyBkbYF zpJWDwzHi3n^;`l&uLq#vY%VzIRU<#OteyKbT!7G$P}+PUW7y$*t*rq}e^lmE)CTo2 zQje!hT#3&jCzi1@{V&tB!oDx}F(vHmhq$)ca2g;+`3khV5B>hwMhGcHG^~04VYOh0#Dj{=eaOnj68KVjqMV%T*X796#cP)hx%3@RLh`JrSJ&GkNlhs4n44Mi5 zZr>Gx8}^Zy0{ z-A>yp4xOa;h({jpi@CGH$zp&L%T)RLfp1AkNeq-w2xaq;kf9;nrjim49@0?)1`mTYf+uWF-0{tQK_Z{_4d@WLQoI`y-4eXKgII?%Z?ua_O6Xv@ zD+_1PSbAgoPp~HNs(HX>JQTSd-Y7Pz+mSGvZs(=b7aGi~=Yupj5Ff1AX! znp9cJkqUdHu77Mg-RfApdiuuG8W>}zcKvC3N%^G$lu8Dz{SKBCF}jpEnQMG&-KN27 z2v_-a#+9K~qqc}umdSRtSL|~_)I@wK`+EXg5fr}+_M>Jz<;OycTN6S~rdnY5AzOe; z$t;3#wd3!b(uhFh)AgZLfKiV(UvppWf7gf?5(k!R>2h*%Sq6T-v%}gy>b@KR9`_Nw z&wD(Hy5a1$dIMX`aM71RU_9(b2SLH4T8gcxijorXlhNY1S_W3T>9b;_0#PKr(-)ko zrdyabBc!MDmj7s|NkCx)k1#WS%@=Z|A{{%R1N^M4VG~>~RuOGfGEdTBBGRb9%4kcQC!{O_xsFd&whJOS!F!jU{iDWcJP-dez|Pwg&R8|@9k(7 z{bG9U(Ze%SqD-?JD!)!AR4^T!iUkS#w^#|vi_)=YIWU~f>vU2oe`q;$ZW*}bS}0vo z;S|1e#@~}xxc>`9-$nJgD;I$*fv1Wmg+!i>3f;I&$FTocb6Pof=S1Y(vOa$p2Fm-d zrPM{SC1RCX0a7X^rV+5&1hl&6>K9zqe~u3dj|^W0vtwvsreg~ctgsN2&Pj1TmhdZS zv$O;eO0g+QA?Xw=YX9n+EB5~;V7F)q$gE*b{oCDV1|wd-7*14!eSRj|nI;u_b4JtN zj<%+5=Oepr%YALWQ6W6dC&f1P8=!ut5tLzWFKs@4wkIEA%T<&8?^hJ(3fV@WhM0dm zi*TA2PD|-zC#FFLbFY;*z$mK(>Jr(lLX35K1L85pRF?!Y`+pF!W0Ik+lB6`Uq+Y#E zqY-htNue5+AY?-=SHR{>Ihj)rlhY?b`t6g%mM?UDa^E9uz(I6}5@Q7d#X!@NsiVX^Q{*21pfsVEJFU~mfCh6@FLSW=4Q?#pzJ z5%B>fcR(zNN4Ac*#pA;$f{pII-4fKjSObMnUHhM(%qv?AL5sU2&0oAP73TOkk;`9L zgtSrvz^5)okMifsKF?;@_qdf_++_3mS{v)HsNRjUmuyH5{IAbaY=bnlwX@}c?S3oPg2Mbzp9R^V!h)3x1+#hfV5&Y+Zv}WAG zP+{uIYEpKq0hKM`HmuwD^3GI<2bRXiq7=ayTBA=t^b=kv>zBEeB$PK2_FN3*DJanj z*;fHSnBD02D)l4P@A{*-h(3Xx4^p)9eG|P+1G?^>sRThfd5_PMuca3}!v5ed{C{3B zm^~yjDVS?$B|@2{(i-R-=a3know7~{BP034w*N>y3A^XHC{V;UppA6|4jl=O!D3DC zpT&qz&9^F<%-2BgceaC%$S2{pZwf)FXGb$L={Ma1$(1HuelqLn%4(hlG1&fAGBPr% zNufL|E=?aN{hwR2yQ(2ejBrmCio&Z;sjS=ykR#jdMdo=u?niK9{jsLTMZR{lX!NMHeRqwp+NR=ko1lJm!lcU^%@RxK^Nw*;s3|5e~w>=_p>$a zZKziPp{9dGM*VYZ>-^4YVno+fqgu}QOWp4rbh_O^EFjy7PL=MC@-J;It@5Q`zit4- z*iF)O=C?z}o8Kg|f=*sy@%~O+$+e8K2e6Mwf|hU5A{=#1{qphTKi~F$#j47?nBq9u z1g%tPS}TlnT_sQlb7JwV=Bk*1&OKiMlfR+Ilq7f+ta8eA)YMM7`S|!K zM70k@T6&Euo@x9~3a}@4&A^@|F8nS+6jGWY>T+%Wm8J5tvNiRd&R6|2;LICh}FaM(MAeca4la z$IzB&K?53OMO|D~aOGu9r}1XEsn`A`?iB0ks~9V4>aYV!C8aFbx^D$fuXtJ_+`F3J z-0$sk{mlD+-{TP5Vhy%CEs}MYu+{5-Gq0cKb2@}F;g9jzRk2D)`pna_Bfg0sy4x5d ztg?rMo{{>*@~1V+>QU0^o{WFw991+BzgOAmTKsySB5lv$3?4 z2u-F%bbjxf#%W#b!m<~4iH&5MVZ{L<;qbYSH9_i*taC%aY0VDYVPYb>0sT%16L2XY zm@4efh!y2o+`!wp{ABt3!}Gyynuov2(ShebU%f1eDwAlionUY$ zqCCB);XHiUe!I8kJqPZy6$TZSqRJ{b@OBrqb{x}3}+}k$G-1hc%4hT0Gk&Z@$;c`7; z;5VQD_zaf&!a*;hm@~STOvqKb#El-0en_pjLxHmlGx)T4*gh6Key3%Gv^ez3^wrF( z6M`Rk5V)v>m0VQ(-yzhVy!#h<_w7Yvl6bTu+fM>wVq#&cZE75Id(IVR4P5={)l_S@ z9!s(vA%tTeVNeX^KRy}x#{LBCEHu?W%6820j76HpccMze36SFCVOX}r)P zY(V&&EB+h2NftWXzmf<$RwcbV;4E=&10!5gFen+BZ_TtCIH(9&ot57Dc>MVPE-$n- zWN(pqo?&St?QshLP~kEJIC+Uu34@FW19;9qFUlXAIk04KNPqz=827~D zGg1-~_+*%vn4}^RAExfzQM=2nN16BB*H*HXri1;**PGnX3rpo&v;>k7lBBMR2R82OtIAWo=+nS{n;RRJ_h+-;nYsmR6^Fy)-t&bE4kV}ef2*IZ4f4AkoBd8MxJ{RPKj-za(yuRXomISE=9M4Ag!%3WKF$df zz3oqFJKOwYGv19i(;@enUOLr%BO>FEs!-R{cZ|-T)}=I1BYXartc!@@u`zXc0Z#8& zM1BZtNyXVtDS_r{Mj~*lRP+1De=KdPY$IJrMx*|lWPBu89il1p`VL4k`kI(du~a2N zTu8|;tq{_(=>6HxJjE&hYphNebG0s;aOT+J3Hc<2^-Qbr(l+KvnGL@4O%bwvk!`a= zm%-y0=hdnemHE*SZ8_mjOTeI(D1FePc?W=^{Y7F|p!DG%T6}e05x0Tte1-X=N_I zT4Pwl6nOpiW&B9$t8;9*T(A&2g~W0h0FC3_yws)efA9tH4c9>%QNNbleD`m#3-Q|zcd z$OX!bwgg>X0Xhh;vYx)49_7;K71;6YfKsFrJig_B2tUZK%KG$H5IP5Qm@j4~@z+dr z5?<$(jl)u6s`WeClm?X*%boyCv#0KwWYCwl{Yg3ou%Q<4&D@!k`edb5pe}IDf;#C4 zm{kQPvHhe{(zB*!{|WlxXl0)ipQB9!%U+gLaw$bG`N|2_ZOeA;$r}!*nHY6Q|6@(4 zp-CobPrn(wHyYO1NCR&!+Mfq^i|L{}`|gKPeHz<$V^cXz3(1saTvTT9@SZH}@7G)f z%1P<5G9aV}KK}k0M{=KVOEKC@?*Jt;@<>r*qpM@KYt?vrqf%-MRu=f31y_hO4T z@^fj4+L54utcnD+T+gXVqpZqG3Lo|hQGe5)1(zU(^ZGH!dz9xZ#WZW_=|79kFS|!+ zKvt_#HJ&C+Nv+&bzm!`jED&s&0BdvF8;n}ZU#@v*w(Ar&RnU_rdAFV?V8Ew|_kKZs zb6St`=nZG|4wgm~@qOYEErMzMZ1?!(&S4=bi=R)lUVQoBFGL`ggs{2T2hs^6Ej>LF zYEaDxE6c#Im}=lU=---Z5$KD+A~K1=_v=DyyYzta7A&VqhZR4*(N}W|7V_=CSbw{c ztEqURnITgC8z938!ce9fo_EvpYDsJ(LIY-vK6|e4?fAhqaP2?%eFU=`mb)Q-Dxbmj z#wC)7W}o7;m=$AjA@BA!obf;uWcHiU`S-o0{{Dvxkb73ld;9jU0NAFL#25li5ET?4 zg_>B1_Fi%+%4WtZDj0W~0zrYGui@ziCc)sM5#KxC8JEU?I*88Xu<^Wv|{0IAFsGg^-=UAWx;X!B!mBVnz+S%~pLYPy z`w9IVu-+q}H3&Pv<26|hKkT;TBO)dxWxP{M@fhZ3j*SjuT%}k`s*%GDIa2~lIhJO80+Vok7JGYt|b z{H{)KapU(-ec<`-fNSs+&SwKyBfEG919TVWzN@w0#lQapW0^yH@MfZHRp80}VBy&DJ5<-}p4Vou-Cc?1y16eqxo&p}1G9flgX>ehOckN^CJjmt>5^~XBl z2V^Te#MFGbhaekw*l^29n6y1Oi0nv?UOK=h1K`uX8u44;eVW1`@pOF`7KuJ^>X(u& zD)v=l#(Mq)W>*mW`o~A0IInF|>s@x8f`j;hm(($N>2p%_Zyk!I5riF&XBx6@6s9ZK z)`fZN1e7w&Po1jLx^YzOr)1w+MH0QDZxut@aZ5)Y#`$WXFh%`mJ|%trcdF0DB^iw#Qx!ByZCw&k+zg=mM_QV$FRSuGv)$tgMiKIbTYu z3<(MXAuJ0x(Ig^x@d%+!ZyTExI}jdxqpGLR{O1~iWYVZ@p?gt~$fwTgp-Otv-h@Ta z0HcuokSK6s5;z_bB;)%?|Jc|tUYO!%dARWQUP%Px(Qt=`__MG;88AVw2ma$xFn?P- z>n1Ef_c?wq<=1VK9P-D_)l1X;HR?npzC zY*3)JDpI*w6zyNoK{lX5+;? z4vyB=KO)ePiq*Nvd&fKg5(1(t7!lN1FHF00)$AFdJpBN}IU*Af&g%kfFN^e2d$k)>L{LBrs~is}yly$V(Y+Bh4T2Ia zB1}xV9BxVSjPVd)zW^D!z3NG>Yc9xV5N(aUOU2NR*zPwJ+hg`>^8qTd68J)FUAOx1&FD!yCKDNQ-YCGt6n_Y&5#m_vg9{9K@@-DaT`L=3q zAMxbp4=hnM9x&pUg6H5wfZCa=U26d2%=m~;mphbcf*?M?=L&$0Ar-HmDlS};3lVUM z<*uSiVymX_+Cyu6+rjl)yp;zYup))<9RO#3ZHd)LStyO`CR{XUI0bUhRLQ&!S+f8g zigDNjVrbk%4EbcMFwhffDJ@16KgMtw$_wRgccY)p_ymC3F{?_v{w6a^WlGqZm>#7D zpk3K^b5PG*2Zq<0AguH}Pz(Zju{%I>eYEuaNiL<5IcI=CVv+wBYc4TL#4d{~uH_B{ zF$-b)AJN{wkWZq?xQ?^=LG5}WJ&;CVNRtavblo`q?| z;t*t7h3=?XIr-KDX&oIDw1b#awS22$*z$?BVQapHJ8)|s|AFpYjx!Gw1n?XRP%q7NesWm|#6=w_^AOI#V9py5miJWIj6-;T zva8^+x&R^~jqwtP=FYC{*QU8ahC^YbfwU{sO%>rJI;KPU|}ZmK6ENZ;M`QGUiK z=9+s6mo5GPX^~`W{J}AV;vGm4YHF#Al~(ga~f zj3)C1#5Pg?%_`5Ji=&Ayr~$(61w@{Sz(#chbd!?!qz~tUIfENuLN)g9bd9l9VwWTk z{#F503c`daLk7N_rqgKAK#8d}RWBajpr%K;-ErqGbwys=(*5hz`?eJLK`i(JNPUHpQ#SS^3+uM3 z*z`_1w!V5Wh(HmOkYqFCp~zS;az$YI)uHy$z`VHEHgzV#IHQHlX*q*{f?cx)fx@^C zCkm6@)#L@<-4_>O{&hfvpM#4U!e;9*lq>fUzBoU6Suq~fs-a8p=gj$RKl}qPyp`1X z5DJ^)moH!HFd?`R-oTuQgtlfTs&N@|#0|6v9sa3&k-%I0)}|+*WkLutjN;M3Yfv=1 za6v)HiGeceJeIdfn5??aFis!Ek4KjF{lnu?2RL`((FN`^b~-m#7Ekl(k(DrY|EI$E z44cWKe2wOI6}tSIfGoEGlOPs^j1wL6A!7PK2-K_N^Gp4yW3LSWZ9<8D8gKEM2m#_6 zvsbpb_wQNs0&1j*apUmkKoDM!hn0puR6p*6+)=Q}epUvQXX14rA=BX3lP;lqDI*4}TM zfRauH=H-^E>ThI&Si3NFD4`#U94mtx)_dRb0AHtiz4$H%LaX#ZbvxD&0 zgieAFNV4|=ZX%3%MTS@l(|kPe1|@H?vMPX2>msbKPrG#|Fwf`%sTtzHyy>rquqBY-8t;KQ4w%Z@;`!$U~5RoIEu0`>Ov1t{K8 zd6ytD`Sv4}TMvy45rQGSQcj>+V)^u`Py%1V-Y0#@cK=~EH#Zjn!Eu})%8z$E4CKD$VD@lrK35J)*sb?BE~-=qlzE*a zz_YpCUTA;FjwoX3b3+Sg!yn!@`6P?1MLv&r00!L)_;#wsV3gDXLd;x|F&6yPv+i&a z2+y}`Q7pC+s!qIYELlIqDsXuwT^$fXF0)_uw$KIYT%AV=5+iYQvijjLbWtZEK6jJY zVrJfg*#qtOdQZowR1Uvv(5B(9hlBM3mLiYu3H;u7`wN9crHPtTZIKARE)E`^AUwoj zI1L!&)E-0V^2&Q_v;=iWWR=a~63%;2g>K$g73!$GHK?wn(au>9Z9ihSO3qb6X5dB) zZ9bI{y9hod*!fZ)aOzH7c>@q&^(4^`5RZ${>Cvh+7-N|x;uZ-?)+lz^{`mm8AZQS? zgYU|7UoD$A_ZDfav#px%g5JO{cPK{)cP~4}7hjR!-?%+hqLU*5ga-xJNz!RW3?EG$ zotMC0A??_F=l1U{21-?AqSC^`5Sk5!s>FzDJhN5bfA)~&($QkG47jJ#^>E4N9>0Rh z_0K~nWmH-pUG1dbw}k)xf?h{v{k35NrFttQRUTGzJNruj07$O$no_H>;g2Um>FYN+ zGt!*-%G~s4X z`QT3>$N)S$fV18UjswABn#q%PILHG~py3X>IP*m84VoIa3hrs%WMlhFK}NP)QE(mH zYMKtfa-GTeu8RC5u<6O}fdn%?hr*+-Vae{$h=}V) ztquf>`fX@!B_X%S=#BFxgv^d=KpmI6h!$=*-ro;B!&r1yVkW2WlCp>HcMRt9No>46 zabj?XTcKwbbR`Ye5c7?Si@RtBJiTDgyWd=Cn_21DAHE7_`1CDT5kmA6VIIp6-c!Ru zLmhxENfmshj>(G5H@k=W0xGT`P>x8%7RIsmI=fcL3g$RUVPFi#_%%;oHJhm26t=xL zCE*M(4KfJKufGAK<}pT)XhdRBV1{G5(Wg#A=f4Rj9FyZ}dKbvX9K`_W2nsd6ORDsp zgf@Fn#5F;UyZyJ?~S~ z9IR|Ru?;0=Y9QmjbN~0(SIq5`ujl&EQaN06Wr%BrtzuZMS=G>Ejd^cRVw_UN%WHHu zybiTvONDzw1MLV^yv`-!POEn%2&U)H1OCMG>Xvhe-M{kB^L~WXwwd3>C^PQC-WMha zo3G)>ak5KRFG9*QmjtC_d(WTRl!uzonO%Xb&bUiNIT&^ie@OCiZ}KhA=F?R=RaZr? z53q^g0((lEn5Y9k1WF7ezzyClGei11LEBe8!{Gq4mcVDVux;dW6}yeFRb<^BC}b=? z9l#y8uwR_oi(+l{1&k)t;NAU;Oc0b}FTSEmqKB3J)1vy*tK`VE?wy;L6*iee{?(sp z{w?R;dhSB5HCjaxsev^Z-}Rt@_57wKArc1UTvc}vOgNRDaH8!Xc)hHq>iYv=RT;sI zY*!;98w#JfM^LUd=rgXNao%EsR5IFbGfYqs1lZ!)>15iBW%DwRQ7W{m=Nv4h`-f$P`$ zU}U{Jk#!L#LMge*JFR_l1;H&Oq~8L!1q%RZPpgN)Qx=m@?`S(rRxz_t=TYDP0~sYu z0(2Um3euy(n#MMs9zw)l$PxEo=b0Rm(I_VSBdR*y9~BdmVFJ-l$L%k#dhZ$J4(T+g zIGBxD<}?;h0hl@m++bKACxJ!K_-%Z*opjO`P!dy9K@wHQiPQB4j@S(Xv`c%YPgE_+S~zGn7BC46`?9q;}tRdkCFlcH90Ttx`!i8*Maos577)ylR4##T~S5l zau@7jgCay5yG_vicO^9cz3|~dz%K}yeQ=?FVRqgedMH+uCiM7jRGX#PwtX`|iGd~% zO$qoc+NKCHn&3PHi9PI$l}Qe+*|yO3*twn%U~O&P2tvc`grR)u%s2z@wiBmDW0#*X z{d2vkq(}HTJ;KPb#>4OjmEY@M)n1MPSkSD%17;)`WjO z969=<4jSECdy*a#Stga}t(Og33Zh%7ike4By@iSqOD(QjqCB8wPu6s7~* zLi)$EyF;RZP<|S$^}q2*TJv4pRLZu>UZa5i(TvJ&nst%iraQqLYB%NTa>QQ*65ZGz zJwjza8|kzr%2AoGf$sYLEL;r|vGQR4N7TybUb6?RvzYWFqpZG;90Wkg{tS&?2p*#Q=T!@R0|Ado0;CGdt-qa6T7&kI@1T&>;GS$_q{5Eh(HK=;At)AfVqt-iY zA#3db${*M=Y=0O$8w|smE7pUsi9GxWs-Q*vDiK@}DHPNPrGBgZG#?kI?y3yG7=q%J z6b3n19*N?CQ!M}Jrusodyl@juq{5MtHC_Lcye#*UK?+mUX%a!_ODRL@ho+ur14tJ( zz}x?rw)FtAPDTV+sz1Cc&h=iCTF3(MLo+W(iVeZp3H=k0HwGX_jA0TZXG8_NLHbf? z#9nA{WaBAW%=-JTDT6TfAnCq%dPeW|>V-iNTZ#f9{cT}tA~rQStbyOjjmNx(H!Z1< z;1SFshnrA_1{RUi8hDK^EwboX|`+4K~ zr*F#(?jOzqXeC?#tk;LkHdu{=MD1)Jou+D%`u$^Kn}tyxB%yZp6v1oRkUdRVu}~-w zt~Mj?3gZ?x_qy)GzJwEpJ~?F9luhYF09Bm#f~77JE?K;FA=(UJil46mnt8&iDT-%q z`v^uXx3vP6WG(Or?K^==KMiK_PFOnE5ME;WFJHWPW76Q|tlG=A!;;5*XUgJkEOysj z0caNA)X0;lN{hpqtn4<7oapAEdJRt#A-On*7iee(L{sWT$!u~)0(x%X8t@x0gM_H& zr^;^|1K)6-LonTTqr zsc%B^a?iA)#&-+#@#@A}LgV0#@aI>(nvb|zYY{Js03?kxC9`aiTat&*WC#+fm`h>_ zvhgC0FdAAgC{(>_DI*ZJjmE3DffwOE^&n(r7(mrW@b5gR(q}uWN?)9xDz0Q4u@5KjlVZ8V0UV-apJ8ZPH??OMdb+-zT9TT7hyqgq0#n@ z2!nJ3CInSI3Dl#VP_zs9ybmGYgvTm_hRiB$^Ir+?ngXH28~CYtoqen)Wn#;|>>@cQ8wmj?bBCoe<`HBiYb{ zPgzFNe0|U`wAyOP_xyQeyjAYGC5;k+#Z6|A#w^vl$_|Ps@aM!Lx^y{E|Zdq zN@NhY(aFdn3%9X`Ec(P8{Yi-5Ez(3f3mGo?M!0;r`*x7N;#EqDmuAW6RS~QNekpi6 zq@A%eSbv9M;+6Uc#>8$y7?TNqyrESR2hE&+U+NKNE# z5Pv;ZhAr9);^{iB>OM9fiL5I`${e^mHVfreK`;28to_{u~l7>iJ-$$>)k^5Y8+QqDwa{ zN5S_7w_<^MUOVgT0sdO3SPy3EJ-MH= z|5;+y{0&8F7ck>;^WTjO)Hk#WZuE^qNiW}aos~_XhUfgfQp`1jlkF)5`SIk=zxiHJ zQ(?7-2+3$=1k5dSUc{x`>D@QlPDP@?R@oosoy65SmHYAn*)l1g#n~{;UGRq;@)z< z)`Ttj18_5fJ{CySq|e;@VRN5kvnXD zW&ox;WWeC!qR{3Px(3MFUG%`sa(y#g#0fSrZ&5=eA)z)9i&vn2V>?v>YKP`Op`XI= zWRCUrHBL)8tajN6`VSZ2XR5_G8muMYrXv=b0IS@(I#4;tYSUgmjaHW@3?&1Tyas28 zWkFxr@oLF?&aFI}C9u{_sfM<8k>r2iV7;Tf{opB{)+k0A#ZY>qE;SzRCmJBzHxg$$ zgo<*>AUWRg7D=oq;HHIq)>M=@S1*c z^#E+~Co2n!HlPMdvARpia1uWLo~UGeaZj1Q&4B`!KZdv#)L=rG=_a0S8$$#&{DF$9Hcm zaR}`Yk$DRg(1_`*Ezu+ZA1Jz*;fQ3isf}EI^uFmTT>R|Z=~mg>YN4b1#Y+16QL4=9 zQw8j{HxzEiU{oT2|tlwrn?Yidw0whj_>Hz7>_!t#0jO|;@rm_2H z?_t81c%~bCOo^&&zV-F>Rg#rD^|WSRb$4REy&6eZ68JrH+uGWe`~!gP0~ArU@MK)71OTuJZtMWIl5;?4@y zW$)i3iz+KgQ}5Q?+hu1(0hSgI74!YFPgc;De}_;P2`MD-Vkwf5#HLHomGX6J>hf}I zdawN%#ve@IVu47Q2V94B%%+8J-)u1?pY)jO-oNiPJuxwH4vR*U!bx`)?~Rk1v!LF) zy&Crz0WcJ3;OeDkpsUHggC2hAL=w||iqqO@i+sxm$|~oOAT3V7<5`Y5&c3#(>B5G} zgKSCZVORXcA7~icd@hUzd~Sd9xqau3%ne4y9I*KbWM^i^IFObyr>>;;z29t|5OV9a zdRWoj4egcg(mu~e)T=47OsyhTeu063J%Cx?1iem7Uy-#vpC?ELlp)vaz<%utPjSo< z4*AGVLyqSci3-N9P}aYLeX=?jkbO0jkfLNYrI%VJ^U1iXtCsz1dwZMk$`z)uPV_4H zCS?Vj3xD_s*;SQGoz;IXEy#33c10^~C48xYXA zH0ew4%>zcUcCt0GV^Zg=>t0b%@UQ?-Pt%c!i7t7ayCNWTt;bJN8=M;T>B=k0a)uUI zr}zYN?Fwy0JUjY>Y~d@WwSEVa4^m_}H$qpDh2k%=ZcE-t!ZGKhoVWa3wDd#iUvXQz zFq`i~b0s>AU4?~g zoBh$=mQWt8RRN&6fP;x~x@+k?{%%T$B<&f3^>iy04V9GutGocc&JtsgqRTdPC&5nq z6(w=*#pOMS%_*~hRYh>}v8@!0Q@7gy;>fw~7~yR#Gf4JD?y@ZsE4uo*fq?<%pUv`w zP`UY@@$qps*f}(0A`4KR*@A{82=Jk=oXVr$pQpMes25ee*pVNIsCu-28t?$Y?TfWy zyvo;|p1-vGx)^iF4afTO>WJK){QG*s=o9L+t@oyNBcQ%)nvqOws+@>?l|@l#!fcT< zkA;&WEG%q1B&MUSJ>Fq^b>hBK_Q%asu{vM?iojf8Vr)ClOi4XcC~Ad>&b5Y`mdrc#^PEkI%CJ_<2E< zmke`ZZiCl|`_4AbwX``C-L<)Jtp}!>c}QQy7Y6Qiy( zF#N8DZEc=^w25}rMw;EmH=Nt|MFVXiu}Rw4*vQhz(fG1Q)1-e8j9xZkQT=pZ?hB}t zFKofkT#2_{*)p)E^3N<&lgZw<^l7sjwCidJYwagv|q zzL%46=i=fzrlzCAdt9nqkb-m+=aBjZcvWO(CVgR6*=ELy)aqc?%vBFo6O-V%XEhCB zzEQ_=li{Q^0*bG)?zrE<=99ksd*B9raAt00<$_*zWFF~561y($h{Q&vfZr{b7dzol zNk$i=E}Fsnt>7a7x8!K4Xwe8OdHqB)FF9kQ2E^@$D)<-m$&7q8ck&?n9tsHye;a?{ zZH7&o)g%&0G-1y5`Dd9(NK?g&*XNRvttP?2>??05hYO2~2Y(M2bU7rLB_JcLqQT9K zq6E5EyCc<^QtuVtj;O2601n-aMPjK7^gv(z2jasD-zrwD!O8|01$stBNB2HLwFO{3 zq_kGiyeHy=GzY;=?-B@`4?nQmuFPQcMCG3wttj8b)=?Roy@nBSx>BJ3j*>? zCy3*eR2o(Pu#xIE4okEnB#h|SG z7s{-t_sD6DFE!udunnJ*Du%-aFos=*A7FuWbVO}fa~d`6F)DOze3<&TT&Ghn6{Yoa z7|Iw4L234lw#-+^Xk`klNmro}++;!3c#8vEMf&8)6TvF1_F~0EQUrCqDqGT1Gc&Wo zwM8b0f1X6g*SpVvs*;(Nndt{r+D!Z4U{vHs&>}tm@q`pIj1S3b~INJfC=adbR-U$~s{jI5Pf7ZgKD@q*k(_=g3ztbqx&-n?N&6 zGf&sPuUB*99AJqIwWQ;4i(j1Wbl>i2cf!H8a8XpzZ&6@bqqDhPi;1DHJ|D>Q3tY-~KcCnsHz zpRHdv^k&)>Qi6Yv>RfH@aZ9(a^6+pf#I4AObY`Wt;;7aS@!hq58zXTDkrE96?_>cK zeMj+VlVZ$?Z=Yzkx3`xU^w-**A{zUk;o;4A^XB6_yGRbyeRK0{Cwu$Jm?XQm`hIh8 zQl&XK@E%`@KByuxJoSfSQl$FxXP2$5t(kAo1*OKt5g)c_O@^nDA?)c3EYXH>7XV)< z5-JlAO6lh50=*p9@G=D!CxVBE_a&gbOLcnR{|BjWe=P4C_F zAlYPky4{46Xjk+%B+#%rM4$%{@`lLBNbcYAk4Ik{P!VNosj0o7ho05kOO*KRXX(wW zzh^$*u>mSem1(60yRPkEZHmX;*BKcze;XT-5*%+?8f_wDJg@dAtFk4Gv)-z78cKQr z;;=NJ#$Nn0GIeBc^Y`!h$?56oVJIG<4S&)EWmfJiMmz6!{)F5jBc7Da^>ut`F2se9 z$iFf>6uv21ey?A@UImycLYe7Lg%Y56tVQl?ERimGHI_IoVGalJafjS_2!Li&5)I) z*yqvUH-cs;3g&!QIe0WPSrXTW(SRZ74qk^SWW5AcX&u?j)MN$K3q@PNI4! zW=De$y5cE0DJdx#@sDx-Ad^!At9%$QMs2iWmEa%^rSKwb2Pvs4S$~d@%dIvGdSGann!c65nVvuB;pOF( z|LPUR_`gnzF?*5D>g|Jg2vzdo0bl%l7FoK>CtvOE>be zT+2W4cxR-jPsMdMS-prYJ?^jqhVY&Kety=@9QCsot1=qv>LSE7VmTf| z(Z0CK0pntKpnGkLC}zIZy9*%3As}EE-N()b?oT$SEpGWX`=2}sftJ+_c;}gb#*`;{ zQ+*#E_62w`=jabeH0RD1@$Q%wO-BIz>KjZzem6zLt7UU=aXH9?xjgFq0n;$<9Zt?k zD?2+;Wvm~u(ns=3A*RU>e)=3895`<7>|FLhaMfjVj*gN#Z;O!*Xq%Y$ymc<0-IHr` zk3WI*L`h344v$U4h$`;vgQTa*SvG1-f!<;?LalcLe;wgOX z0sWJcUrM5*GSv5HVY49>T2|aK-)5)`l^h)%i;icZ_jQJ*c2NLNAUNQG6Do+*-Ef5EGkR0+d~niws}Wh|YDkq#jDCU*Jn$J={<{>O1~<~kBY3igTEo{*W9HAg0a>OCV8 z^jOtI5Al*7T$R9s=;9Oz0pYQ^&ogNu${i(^Id}0Pn??}NpWL4Q$Zepa(v_*@%e*Yi z#@6xc857E8U&3`U_z6Ti*>pR?@UPc+9;Zy?>MJqmTPc1bgMD-cD?|>etHW?YwnM7> zXfiz~{9}$_x8r@~>=#lzIVhQbyG!jMK;Im_k9Uy6qA>eR4Euwe?7e+W17S8g5vN_W z|2Mf!3@1M^RAiIAy$&ns!jAVJYh=^4W}9quoWqaT!YK8|Mm}0QEDkod1?=qB*a4OA zbpl8F5s9cld(Z;^o}0_0_$K+P!0VM$VF@CxB)j^A@5!%U-w+TG2ptgk&Y@^s{iOo} zw7D8d75haloJD3~czxca0hrE~PHCD#5=i_261W3F{*WBDQs+&1X ze*v&P1Wu5|c1Mp#BMwPeS+~akKxK(ZAM~@4mF7+LD3~PdwdHg9sm(jW7xM~UG0?hT zd~%5lfd3#WdiqBBzGIdXaCx2k4)Z&;eH2;`q8WBk62;|}6%`j1{9hUIu)mdJNmNBz zci^u90Q%M)^L3DSO)<<{eHQQ-1NegDe*pwnC@vu}GKY_hxw}7Gph7wUxCeK7A%buZ z5Qh?&*OYTy^F=bS{0RjvGSL}$v>uNgwCfwJh);md9Kp^o_)%s7zHIYWKibsFT0Yc& z4y2*da&jzkph+Rqv#s&u>hZvu@_6@``VahcBS`D;U-oq$0P=OsYir#3MY^=YD$TYg zP)&;~|N5ZkaXlR!ikxrWo*TW2n*bKH4lKyYNOR?;z(67$-D_N-x7KTj1#EXa?%)`96A`&1iy_}(MS2(LOor4E{3YZ;kc*5& zAN5mfsoiOFhC*q8f}FfUm5p4rG;vNgL{|6ymh5=*ctxu6wJrB)*2nU|=NOg&&%G3V zE~N{?H$gazL@8BWDL*_++A5+t?+hrP0Pc$#?~dx!_)5wMWBl8pX%$e zvrDjgBnM^3`6XTV0epSU41AWY0={3%LO#$MAIK{xIP0qR)i>qs6Aq(TTwHdJq0`Sz ziu5ePOk`<*bCLlnD|UiJ4`WLOE57md|AM`3aZ{j6?YkDbz=R_9(Bcc(k7YU^C=1WW zSE&`Q#1|U8O(WWvq?87N_Xr%uMOB%=gM)*Uk5A^(%jy?>lauT~D3k<%wdj>MrvIy~ z>yD@T|Gy<=Z&}&bN>&+VWbcuYEh~g{Q%3eKTU??-HpyNoyGSm{t!v+G*U0)9sqEkL z{`c+i>;Bt=>wRDM^*qmW&htFq0mu`8u)HQYIXNy9wH%nAKLcCE&qz^zx|lH3&KMA_ zdCi7I8Jhs|mJ_`H--EYn$A}g^?@`w-L+@@ZBO~LuqPPr6ov(-bn2ur5fB}EdBz}*u z*S8HO|5o;O9(6!>wQB(PHFrtg-D94kbuhhnk3m~6^~a?LkmGR=4j0&3GVhB=qwYf& ztkBK$xNz)wE{riR+6rQd(sYZl`M^>st*)%dcq-576QNmxVMvmRlz0}fWCGdKX5Mf3 z|A0Jtn*jbZx`b{qU3SWg0b>3zrj!CR9>NKjs~VB-54=c+NFoAJOSs$2OEAci>y-XJ zCH!|$UEOvhP;Vw&d==R!O<7EJghJYu0=N!F2xc|YOAq5n5hznO$vcUJ@f#&?KR=r1 z+I*NNs`*opo5fI3S$VXI<2Ad3IbuU#`p}Z@_W0AFLCBC;@77d&F1TrJoe2g~3Pu;> zg2JCN-f9{-E?njSA1Cj5cqHIxRU=bOLP3Fb0~ETFT_Se%0+Ph!(f|fy@9E(oPnCZ3 z;z#XnDEJ7bL6MS86>BgzHxGm+{y7-+DrkRd4%Agu-6tzQlQgMf=1$=+^(*8Kd|2&Z zChoHL5j;y70@X4H?Yn`Beo+U!lk;7tET1Vc05T+ zG#cmK4=z$v{(`QTk;P=vs$G%!(%1Ktg_U(zGgPMEmQykKy)H!O*jQM+L-74k=S2+= zT>F?;^31!`&b6jQb#RbuZuy!eG$|jC+Y7N2(QSh@-40frn`q?p)&t2cUI#6(eeI8R zb@y4|^>$%iThWB7!3w|1i?Mg3r7MV_ppT%WqC#?7DSu5+4n=JoCTf3a^`8wkC!4i$aBye= z@JFP@CM~e2{(#ZN>@5o*&W!*#-L~Me2_K?reXd~FkegEbGB@`m7rdr>^LC~@{0a)K z(?ENds*>MG6Z#ThP8U#ODFOM2E6q>{(<<)BOldrO_39`Ji1U(p<@Nw+9!yb3!GGXK zPUL`jKk<8~^HYQ$3@siW006zL;>cd6{{!}{y88i|N3KXny)<+=D$YTG{FQeml|5E%YrGrFgb2jR7K7YW*0c`L? z2-fk?=!yuyYKSn&%0t)5wi?Ti#Ytd@A3wgSq;<{}t z0R|`;sF&!9H*efO-90Rr3o(RSh;DCivCxh`fUsl!58wd}DWj~Y)^%L|_pM_lqdEML;mgFryR6 zluX}QshuM!DVf~hIn9aRGvKV&&DmNjs=fu=!UO?h_exPk8gS6&vG{`{0|n5X`-3%*_T#!BDlWy=J;0L|;Cw#KB^N8FT7JP@We>!`b>O0BiS(y+Y_|2odde#*^alqA zqgFZMD4m|VL8!dijT=v!WmU%!9=bW-d$esJRJ6+H(W7Wx+Go1N!^6Xept+kpe)1#$ z{d4FG??@jn26_}EeEEf@-OJZ0<2E19#F&WT}mFWQo;-oEKQ5)?8cr@SR_}LK@jVI2iV!+P8QtJT%qm>}AV* zYkt&$;-*ardq!*R%MnHE#y7LG7mVIoJA`9IV{K_Uldx7?*xEWlaEMKl6BA+N$j@D_ zAsG=4H1e=C=)kenF?f&8(Ygr{uc+lb^t^%stIvbD+}vrR6^U-eX99Ru=XfDUcxHkf z1qE|-yyg|A&-(nFn7?X5LA-t$!U*wi%Xs7QCm`OmjDz>u3nDVZ(-8=7kpj-xXglzP z1%ZzuFQ-t<`hY$_Go3-~rm5+(BM>^5G8N<#u5T>LpE|{0ucNMFin0UFZ2&wS75O$p zLpe5G==#J>Mkc0>`o_kMWKwqRTqB`iPI~&e1|T6s6f^0UpQ9z2_!*}_V4ZFOKx|NS zxzvL>!%aFqIXPF>b4o#*njHM+V4H)Dv|p{8QC*$2JMQZtf1i1FK}U^ zT14s^8;?uDjD5ePq=dVYt7gfhi-sU1Gb({24sNYKd(!|_6Ly(rV3<|wItmV9?^^~2p06H?ww@#?Wh)1A|%;&+C_MP`~ zu^a{f(gHY%Tg!A>3O_FQbOBW9ddhh{9^F*3UU)zIDsh13!43%(TM;uzw*3;6cy?p; zO9wNvTmB0GCUk&<`3Wwp$ib?rsHiS2cuyN(=#pIiuQQ*vJO9Dovp)xWzkW^feemG# zV-Ab$XjXhw&+zcuaoA;3Bky>Q0l`E=|B0}I`8ITQwLlx*e(>=U3 zycJVKDEwSi7*-^y&72z}Q|1huilsv|L)}TQvqYJ)25cV+dt(7D`w^_8-*_zkgu?gV zWmOYCe|0FbU*YMd!Z*rsN-#a_fvyJIB$yn1e}R|SLWB3acbxh*3YOvRg5x`em5nVB zon(O>1xh6vo=bP@Abt-niAPLKOe8GP?oakC&HB#ilMoY~7EzofjmC#iE;oJ)HCMT3 zW+34lsi98ke2b5sXP9X8lguS{Uk4EfY8Ahc;BL*Y`Wo@}e}j+3L8bg%Jn@ldQ;gfl zep{c(R!~r|5U{ID@AyPow{aBOyN%=A>3x{+xw*c+zIw%*J1xY~ahB7=WA#+?^4y=H zYzOdehQRbgY^h%e{BN8R507ISWXV6X;Kmev9jUfgat4R%!wPe0<3G>LNq#pz=kV4jI>5UYD=*YC@pjp0OWEB@HZ0l-DOWg*0xWW<} z^YIxo2-nm|jqs90x5;C;X|Dsrd4^0Dsr{ntK#Dlv^V?o|!XjHfxc?(COMWW3sviYC zu8Vsn9Cp^9^3W#b)#gWO)9x)TEG~YAT}jcU#_`-^s&vlqV@S%&%TbRW|0as-)XKyD zIqR+}UucVB!j>8%jLpqQ9=W=@YPa>yTfx(Pu=)G#wf z%QYq8$yE{%=coo`EJ<>fSB<)qTq(fN23k#9*BFw$%|M*>a{ zrM-g##IBC*z(chZSJntcxcAp!5V%6KrH+f7E!iSCan5NLE>(GG;Pb>q{a^Qb8ylml zi;EX-L_1mwT}JSrZo_FSHUAq1OGmIdfV9lPTDOvT;c6AD2a?=I`>H6J)GX$idcBE6 zY`B8U(!ghvH;gv9v5^i=yjW}z#w#M2CUF-Cd2Xn79wy-j2{CP)05vbm8duY?n{Q32z*!Fe5x4M zSG8-=l)S#Kj=HJ2nYscIsYRX$ho1Qw64&rzW#umZ8UwS8h$ej;zNE4e`D1SG_E^QEXWNi*C<;eSgq!=6*-1&o*{k$U-IjTD20c{JRTQB}iHSILN60BCu7dbcpnc== zw8=hPpa?kk*Nt1XdnIH2Y{$NJ3?6ebGU8!ZVRa=%mi2aaO3J1g)Zgdma-_12&6h*J zNLal6{39@GM)<1{N8!fz#J3+NhPee9pGmdeN?QWuX>Q=A}Gf)&(Wk zfovhpW?yLf4d+!WiCxw! zt976re%mUH3=U}=_j&@t2!k%@73Ck}U#|TZ;JNP-r1Z$Z%+S9nI|M7-*NKT>Mvm#& z(#)(Zgo75}7UN0{+H(=sm%oR}mNYmfnyNe{!epkRKJaO@Q17)5RnlqnLk{TFW|=n@ zOg1AhxD?6ss0`~afRTY>V+WkSQU$l!yHcnZeG^t@yS857pLmo6T0(>fZ{!Q-m~+?O zuvBY*cUS*$0!PXiCNf^aauLfC7x2ks5}N8o-FR0Kn+}8y->Te&ur59wkY@FVy7X!kjQC)C=W&Moep? z9)fIOUT2X#)Jz$ULh?8cS9V1@|GA*k5D=NmP?E;nJH;~Au7N+Yqs4di9DTVME^?=L znt_4g^}+srRnV|2#BQG~f;0I>34RYCG1>n9{#dGj7O*WUFf6*h@}4H31nfm3KHlCo zd|?|vO)6cu_F%@4t(7@cQ(|SbdYS~(Waaxc4@0K^gDh}THi(3W%oCn0L{B2?JmHzk zLXwb1&L+ir9zHagoSgjWA!Mm|zz}m_{85X*j;K`%kE{%sMt_0)Y7;uv6fqkyc)Lip|c>20&L}PUwL?nbN62 zhCWL_Bs!T{T8@cmX=yPgN|(>uNfSKggw4FWknZ809pA1})dEfYw+|nbX}!lkt|)XV z-WrZ!+1rFxH)j=Q1!8;*#|hJVY7oNnAf1oPflZ1%;3=f0Eki~|0aFC~!otEkkVGoX zQe3lDalSx&pK%4t(CfJnFK_Q9c@Q*G)H7eaxCXm~{*X}RXsloKYH{?{%<0%$%u*x_ zy-cTafaLcDf@w$*+0Bb4d%1MM6O)r!1MnrjtE~LN4M@S!)|iGIhJ)Yh2ZR;wK??^s zc>}^_CjGIqbB-k1k?j%>CeczPx@F)qjN)Rf8r&Ts#b zpv!o5X!eGHad1SudVz#uZbuqopjytfX}Uv$H0AQ*$_fq(S87Iy40mTnc6M;I0n$Y4 z7J3@I43!}KRc-|p>C|>d&4EoLgS`8t z%NFo_01VUn@GGcuUQykE`!%T+`RN=*@5X!Rj(>qyskH4j{JMTZV!^)ILGeVk>C&xf zNC}|-?oF2&$kn7xhB-_-Mt`pl3K&9Q@&O_I_E@-P-K%pL32LfW7F-)$9hbAx9)pUeQS z%X67C=CD&+j-ZtYu&}XJ&F}05?j|aG#8a@oNWp@zuXLW78PnL%P;|b{S8ObE>al#X z+Dr%gX{0tT%YXRY(cToXz{#)cKkw&4Kwj%*8{8_m9gpm^f$V%BZlWX0XMM8)Zv%s`2$VMC zr==Z7(Xz1sQbp){??7J;tLVmt=|arYyDD^Icmu-F-xy_SzQIl% z@s9Ph98a%OVMzjO5|L0=2V-^qn&R$9jjSiO!#lm@r`)zFt5?S_V=mr)eeri+j*iW} z<(APF+NW*d0{&RP;{Pt?a;ik}?}mhS%M^{Foi23xuq;N|dV^AG<+R{3How*NeHZJalH; z>%Kc`I8xC(rZ{!<>j`Tkqs?;ANcFlCs`J;I^t?zP{PS{)`_Q7BLl)*zo)H6{kpyM# zZ)PdNfv1HVw_U=_%!V`I-4wxjQwbz{!XF6Dn52g z&nVha2AJ68iz%iW?_>RBJ!%b(qfZ8`eaj=wg_#m~F72$tR`)}~o_nMIP1V#BKsdg+ ziXphtva)!Z`Ny!N^aUT93)hEmAMc;|$xig|iz?znkV+0r^xOq4GMS4tnpKQG&J^cU zACB!a3Akr^{scu@tIqqz9|qgQ!TL!j`^v~_pdnuSO66T-Y2R%0GR=haHR69?L)@EH zX|AnuUqkMHk?5}uR_s8CtXriXl)XA*UO|*^^nM47f;S-`g@ochd%Qby{55ZP*6Mf# z$T2|!K+(rFAr&xYHr{OJqJ zpC&|Q|9KzB7m25sw<#6kPRE-H@6sl8dz>YT$THHF>ZN-!60Lp{c}E3K&>36XNvmMR zFcPiolQ&{tCS(3R^Iv&36;ZBxqzz}1dniEOi2%obxF~5+m0@43ltKN64jmPqE{Ut) z{+P3Nmn(`C+Gz>%uI!t9`Ol9DSDSguz1fa}<`6Dv8B%g`w!ZnT&s+Yj1N3p9!jsg? ziP=WR6*&KkGZNBY-17GTccF05mFHDk*3E)`#{ct7PQxWc5kYYLkxCuwfo+}w2mnRZ z{2KY>p4ISRH_l{Nq1Q`^rQ6<|$rc~xx3J(=MnSW4=z>HZ#p(_Fx5!EUk^1)xR9}er zldf=+C@C!MSt3j)k-@Mg($m4=TZXjEch}y_vEDkMYz#o1s|Pa+-(tbn>J}TX(IwiM f|9Sb#)BUxNvdNiRrHC~-1^;w3Zm3tOIz;{-(T;hr literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/brainwallet_logotype_white.png b/app/src/main/res/drawable-mdpi/brainwallet_logotype_white.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1ddde1c1455a82c9aa83c961eab2b1dbc78560 GIT binary patch literal 39557 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 B;b#B< literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/brainwallet_logotype_white.png b/app/src/main/res/drawable-xhdpi/brainwallet_logotype_white.png new file mode 100644 index 0000000000000000000000000000000000000000..fbeb2b26e5a19bddfcb69f11101090f6f1e00ab3 GIT binary patch literal 85102 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 YGwQ~>#~|+Mi30y9%Bsm!NtyZo9|tQ8lK=n! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/brainwallet_logotype_white.png b/app/src/main/res/drawable-xxhdpi/brainwallet_logotype_white.png new file mode 100644 index 0000000000000000000000000000000000000000..dc83ec4363fd943c8cbc7490effb0c93d357fcee GIT binary patch literal 144825 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 lcEpqaJplA{Fe*mfq!vz2U literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/brainwallet_logotype_white.png b/app/src/main/res/drawable-xxxhdpi/brainwallet_logotype_white.png new file mode 100644 index 0000000000000000000000000000000000000000..83c8c67ac1b3aa6092e0ce14bd5cb741d61184dd GIT binary patch literal 141693 zcma%DcQ~7U+eU)~)dV$KE3v9ZqN?_e5wqyiiBN5$Ra@;XMr(%_wUyF^J~fMoRkQ@* zsn&|1M(r6R_|o_N-tTz-YQN*SkAuTF?)$!e*YCQ{^SsVq9$&UFI>~m1je&vTB+3|R z&A`AK#=yWh31p%Fq@<zj#jt~s@f)jw8csnT;sUG*-J)r! z04`(TU1++up6Uz2_x+GiVaoyXK`8ma_u8XtkH~W$iT}9ImzVG7zP2ePhOEpu=$Cxk|8$in~w2E#6M$gVDGs6k>} zVqvFDJ000{jT9oM>;GlWRJ#7~{`#)Bqyy6*FBfp-?&4r8fEOtWu*Yi}jQFg>CbeX+ zV>>e1Vrwg0r(5_aex+r50b}@wALRClUhgV?0O|K0hBLuWGwu?f@dr1HKX}r9%J{)G z!L}>ycg_f5HP+O}QOL))DvaAn+}A(_MOVhp zkNR%iQ<>ul9EIj8+WO#qAEmpfMtU;U3bjbj)Sw~3kO=puKJmq8i#9f0*R?02WWG5T zHaw7X?*y0;etS9m0A8or)k{(t;gLGPCScXfR7Z>H?(AE2(;_Y9^Gt|Vcr*7@7F7(4 z!A}?nwq7J>QHlmB@iMzf;BZJJh}+!Xxz*6d^Az`aHKDc{p3ot;$@~2Wihq3RH^zji z)$=tUlLN{Ddb>YvnhyAdp;!$yMK^X}8(b?{{kF@16WGSk6Gfx92 zU_TAJFjxvtbj4Gj#Nsy+cBdoPG&xx{hX?;b-}}=#BW^P}apMdVMjG(v0T13~x$r6Q z`N7NWH@0y3879}~=1fO!k+jys=+8iZit^8o9*dgw=CmlAengSBapmk82n$EsmN-IP zWI#ome#PgGndys++=$;^-*_Vaf@ED{?r^^paRWGXQ?YR~6lX8GfIt};k0{#WXI2gP zLj%81zFMRn=+pI(uk>-{i? z_2JSeP>*rJ*XNE|o>W|E?edyLyCM_f(KXb`C=f0Ec;5~+XB=3N9(n6q$8Qt!Uuk>wd3Xo;savQB?IPf& z1=f zW_w(!Rqf#UbCwOC{O+~>eS zLpSRUN!{71A!r^-E+o>AEdw49w!D$+zByA%0lb`$TChivlLKptSCRP1SQBY!Uidxu z;k!TXSjm1x#`tE<6Fak=Mxp>Tb_`=WVnDK|ENSX-wZfr!r_%4V_+9UfuQP4B^fMYq zOcrdJ0pV|v?667lC19Vp*C9FLx|V~AiZ#WyHaRIf zKlay^hM2cjY9e+`wHzKiX(B)MNh*$)u!AiOSbugJ4=Jg=^XDznCh9Bp+SAYq=2WF3`x>(BaUN7Ko7 z{~vdda#;7x84(H}8Kk4QWB=g7Bi2rqib=OJF>)?p4rhvM1q3Ls;6d3@aMet zh0nIaSI|hbo<`ci@NhTy%)^}!QNYF1kX>OEpRpR6l!YVWwvf_49)EBCbnEw}@z-x7 zI>41>)%+_*Uzxeesi&Rx;O>&iRkIr z2qy*F%rG4_ivMgX;mK){|KkEkBF;1M)*1d|JMsNjS@#1*Pzm5*OB|NLEORdR8KM@> zc@0Yp?pXfZm!|ZdBtjeVJ->RRCUlw+MKz_bwE!*@OphA=22nNa>!0cr0Wgbl_>Rm8 z_2O5SvDe98Tc_UTIN zZH)60E$iBmk;>9t?(nq1TwEDCDbPUr$7e|H?8IMxOoG$D60O5B{H_)a9IV=IC$4#o zM8PGw=^fyaq{oyUa|Q4Db0eG+JRTxAWC-G?7_LluNlUoM{ov6?7%*S@s1?RMx#Pmt zyjL4c9u(KK<4SsP9{M35hmGSrxdjc>oask9(kaRn6Vz3GZFFPU z9~VK!*nuOmhwW1Qsd{!M=n+gySaQK11$Pz9g=bWi7Gq-jRbyNjT2i0H#rvDa-EM`D z&oA6VWqsg{;F>#6?|=_&=5slYb4I@mx928JbPsbdkMoA)LyGq4J67&~zQ@(gO(OKI z7?YUb=H7dcn2x3v>S&^V&J(a%NKrbI>Hnkn)8VuN@In+|F87Rl#IyN^AYfXj39NZF zzV$HPL$%#oyW=|Y)>uYfN&h^H zQp;^zSdy^3aQd3k+gG%NN{bF=+S^?L-OPNyhpJJr=h-mocUH)X61fr!pUSjrfEr_q zQlxwu~&@)hk>XGrce9ZX<>29h0priq<3ML?4=gY zqh|69CJoj){)w;4t`Ab=@QLxer>+=}PYb^ZTPx=FzhFe~l#n>Tle6#?pOoT53C-po z97MrZ{fF#3()th3=N|7@OQN@iA+x5^m40--@rM!-p$nQn4F)nc4u4kQSq6kJ=}P{f7LswCD{36|25shU?!C?BF^q4+`0x?oQR zZniT=RbMvsz=m-~f|4TMYH^BYTPgbzwuFUU&38A_djPquD6*Qd(;<-i-v~5#dqq6Zwds4Mk_h@_@_3_=$a-&?@iqzH60Yhx$%N0mK zlwTTB0!dBTP#nBkB|yo4bq#6msT6GsSn)NdsC!G4wgqe`8IXg`Q!~B&G}kj$i5_I> z{d>fDI_vU2g1|KT^a0BpP$C)pq*mqgGMBKPA0^~Z3Df(l)EGRgxceX3wjNN#Dj*Wx9t zs2mFX5Femx=I!&YhQhO!mk#z8o^3vxF5n`mF+b!Lx#REB>R@9tWTBv9FwGOB`c-4r zRmkrNQQ&6)36xM^+B?=Edu~$0X`OKndi&B-GDtPg!dtNQ;ou*Uki#87jA&T`N0y)8 zIlxWTP|p-DJ^pp-$y79Ni|arVnTPBV&-Hn4woE{4_vNlSr`g8tJ^A56(Y!CALpKK( zJ_gl=f&MY?=r+eYYyfN^=8$;4ad&7DY$i-XkPx>GtN=E|HLDv*gKIrm4E-Imre|SSeO9!cfC``<) zbQ&J$I4%b#J-;3&E|Px!$TA#EU+1_{m}SSO;k-pByeXMoV?O%u=zxcANu{z8Ph^1GV*nd zwC!xEel~8}d6c%$o+F4m;g(No5?U}F=!`K{Gbfec%Hx7xWBWrcZnWWS9!cnHxK~x{ zPg)K?oc%nGCNZ8I9X1ZMt5TMy7(DH%&L-#A2kwQKg}B@T%x03l_v}5NyEvyb1#ewD zC2l9Vfb;*cdTKAne(3)Es?zT(dBm}M> zf+^TeiMN}3IAUVHr-jyo($y^~_c!B;Qfuoti#Xq~(7Gs3U~-GAx@KHQ@ZWMA7(3~o4dJ93$+iSUK-p#128D{j)1ibC?kUqocL?gS^%je zk5Z^;gt(1RiYBk3KI)Kuq{?JcAyZ@WRJYN#TZ(@O%p*|GEm?1yOu`VI@-(1EWLl5# zavO(JOp?PtHP{_JL63vtixJ35u0N0KV(#xH3w|h_<%vD4 z`fKb5@G!n@^EA$0;OXUNV92IcGQ@AyeS??>T`)~O@f1;47t$SOQg@5JSu?lHQ@(N= zV*;C_BWrL7ng28f@y}f?0C3sN0PqRav#tAWPDY>O6C~IQNU#;dYt0VIAMyUS_eY!- zN4O6>WQH81U?eWP&;>zxC=LG?mwaE8gl5QBSNEySxca!8ao1*4oAgNE6TkW2Qwd-7 z2^}==Us`)teU*6fC(24yxlEd=A%8K2%5o_hY}PfGEk4dq^e^Yj*}x*3omjD7`hvmPJR@i*c}2Q-&8PDD&7P&-sBGmbJ20rj{K@NJa%# zJ>||^TTof3ueomaUP7>n&*tq|J>|ru-|nUP6uNrA>1fgL>X~zN8OoqI(BzGlQmDoH zd2*-AM}g5oSIEtCz%*Kq%xS97o=Sj0T=x^vH0{mi;4nKZ*v6$JxBI=&h}R)rx^kOhc(9aO}n^v?`wskiD3qU-Xm%H)K1_lfkEy@OHtjt74tNX`rNXqCGe2R_!?UFTv;WyWK z0^M?2GjBW@pY;jDu^{6Z`Zt#{%JWL z9K9QKQ-#Z2zQm(ZUJM2vo?OB0r1<<@d<~_BB(=z89L6O%OZzfIr!{i7No3ol*= zFw67(@-o@t$&cPQWFwaH|0dTssBckcl)p@#G3e6WhfQ&ySOs@%q`&Wt9Pxs6;;_hFhp8=R(?TOqK+AB&Jj zxATwrNi%IKI^GRE&H)5Ex=}H=Aw@F^GIX3ok(zyvtH{$y+(w^*& zWeDc(ykSC7u{E?P`1-lN+B*lG6>l>hau$B=X6}I{teQ^kH>Sp& z@TI^FZXJmJo~s0k(qD(A>|G@hSgQgAT?@WE!)I^>X1ngKH`d$VxAz${LYzSH!GkXK z?cDexm$NeI(|&J$o+sAx5VkP|z+b}JV9x-~U~jiipJXRMR`!?^M_1(%*EaJeAFF>@ z_2^p&)v5-u(v+bpb|MGIb>lILw&ExDo!=>qZ`G}OP8szjD&IPAfR_)>sh87G7vQs)^&2RbN$&>XH2W&D*x09 zl(J@^5@;XSm{psB=(u8w2WE%Fy4mw|aR?-eWj^8NuZ2I&hdlIHhWx$V3XXN>WXwEv z2Z8Kd%;zrZja6X5tb_PAO-!g0l1x`&jk#L6+-8Xz{P5SFv?dqsxDFOzlWe~ztA|?n z;8S;>HfV}tK{so{H`8O!o4}SW8QDveo7;Mcl&UOh`)~C%hX^`$E@y21`UHV>j{g?_ zhCUOLx7Sm#p`-i;>YkM+!=^o55j@UO&%FG3h7GUJ1x*Kyn)uI;PPx-Gg<4b;s3}`7 zfz(FJwI!J`@0h0&8cMg}Q>%0OW%yy$&}-8?<<)9KZX{hRaj8F4%TjMlcFG#QG+G}HPeI<*1qDR7$Av~aGZFhV zD|pwbzfUL*9K8=JJumtClTLKLS@=phj#T1uo@!L$0}eoZFmh^z}D?&tE2B5WXlz{g7)U$fp_BS9U@mpr9g} zXY=9woz6#3*fWo&XU-U;iULHYcox^Tx?T8uNr;l@ZX*X3uD_T^qn>ZfZUQN(> zcN(L;y=($%U0&0zoz4`T8$Q1VT9B$|L(nmwXdS!cx|v{vU|>Cr@`*J zvIXQwwM|KE#~S1siouE#J?6C2+xHC3rGnWA(mNZUYetgD-I{$JQp=Tn3jm9O43D2z zT1hq_yS~#t1Lny7W%A#vroydXz)#uO%tCJylusCW7J2gU$R)?{$j7g-auCR za6b3rTBsS;lYfM|GWrgGb)b=u_LCdId7=x(sF_3Yw~AA&$9-d2`n+0KXOYX3I*{kx ziovPH6((wbaZyS|))!-M@+Y+f zvZ&lIRlLo;@po0`lsYDQ>-xn4b!+TLAvw1Z6-Zg<*vE#VFZ0C!7xfU7l^bh+qp|i< zfFQLfZ*_eQeNt~SJAZ}}W$eZ`U1O??sdUxj_}@aBaL`+hh^OE%mv_>klg@1vQ+aZT zcoU*keR}JMJFpoj9uh5NpT+Is!1^2}SWbYOsu__2>MqIAINz4=)~Q2_NK${Fo9X|A z+GjykxcnGuGUZarZK^YWHIr8Y)8hK6>P>^~!!{l$-gYAcZ+2z{L=Ns{*Ao}cE}Vj3 zU)4oHBKNX}ZTSbOE^ zr6x%yI;7L|HW1?3`3{g)qWvLkgF$g@6C)9VByD5KawVd~`b>f)eTIdb&Ni8!Q;t@D zrZt5tt2HU&vi5(s)|+)u%Zb{`eK-q_82rbSoIxq_)b?(aeb#c?tQmC&`{D%|DI3$* z&&GrpzNiOJTB=MO(9B zZlZzT7St!a{ci>3K^?o7<3}?*`p{1_-dbMgxJfk3-!6k$GlVeRmU`zV z{RjRLQ6f>9KIJaMDoLDZ%chk}nFLmgZ(M&l$fw(BK`zm(t`+2mfwwo!N5fPE!)E}8 zsnO&gZo4;<%d7pd%;NM;`xJYs^qvY`vM%Z2)1lpNad@MGGi>7beYp$p%!Kx?nyZG#iqCUu59jeZwRtnnV{MsN zH6-I_U2JfqoIkm%Gcc{VPid}&Y-s{d@D7;#u=%%r}}>PI9JmNFsWH}g9)#nP!qwk zduleBqGr;ZT3*NUy$XJ89;(W|g~jfu{lL28uEPVTc&#trziGWb0wJ|c+X4Hep2VJ_ zGg$I96E$hxiM0c;-p}ct&~t(WY)B`g8E{@i_Ez1>(JeCh_g*Cg3)2f;y;~L+bM9e< z#^GalqiQ7Z$f(OY;~%Jw@YU8$u9alQZ!s$@N22M?jHP}cbFBNVtT=2tm;Z(!j)3%~L7}2&S^$#HG)2qMN=MWL)pac`z$pPwjh&7KcV=cTe&-2;xd61QV z4>N_!a|(o-c~_z}64;wBl1yFGdJvlAG>2hxJ+OKAg!_z@V5i+xFDT}R`(B!OvX5P-S|FE4BK#rXk6L~Vv zFlPvy_ZA<&Wm0&`^H23U-|EQ1t_m_6f~4Ml*SbF#@aHIX(otUKeAq zx0p$o2}ygvFWuTrP~CgA`M0f-@PM1Yv5s$wk?F_g^UHX6I#ne&RzyaWmbvUnW z0||SDCBEFKt+||YjLFvL8lg8UYHNqz^Ws5M>A2Zn)&q9Qey)fGOK?bXLNHR4II*+NfP%Yt)lc!ZZO2~^j|*Q@ ze+KRVp2WHuHXas=3*H+x{dj2%LtCBzi_!Z?35*w$ImZ()D3MbnC1oEIV(*XZbFH{w9kI^~bF>A{A9(kMhF&H~;M~rY5c=q23kL?e ztSu0eXCRTq&JW3KT!tryMr(!SMdP>g=3|d*P-1HVsM-wcmApBN-G)DHI~gW@$ZF`6 z|IH#eG#3(z=4plNF|MGo-OzYEkWHl%?7fh#_@NSpyYICCLEV*g< zGO>EGzoUhJMH+~~qucoe@o|d{*l+RkrV$7Vu5zw!9EG$MCJz0h)B5*s8b9&-hX+n?Gnn*Svm8_H%=Gr|G5V+W>AtfT9CBVX})6EK!M! zwZ33`j*{C=4!S>W+n__Lr;jv11__xd@@PT)!b)!Zi&~e<^vV1a0ye-x8KEt<3j>I7 zyT)d(1`NE+@~-?RU28TKdR5yGD->KAqwu+MxPwxNYPv7xlC7;qPY<+B5yfp|cI zy1$z`JD#r(f&^8>Bl@lx=8=s|q*a15@Ks(H#U@ft@VDfp^aGW%;F&cB?NZu^NCj7| z#XX~>JGR4d7e#`j?+E6KyGrOxd~dNU~o=aAyIRnvTwj3+V)Da4s*T6uB& zG^SOv^b4P-zmH>X?Wplte|^(-qqn78J6V^+{WeWu!OByiY=jRrE^MpxXT>3j#7@DD zfD?&7YBLE8Af$-iiih5DvsUYo$Z7V7I`no(-)94@txYs;>k$fLx{p72%9w|kkobLS zyaR4&rsB^$QWRg7T9^cHfqs~jJJ_}WH5Qg8-g5J&N*eehpTj4+hYRMI#;wj(E)35)xI$7&6g( z-9e8hBIpcdPX=q6bx`PRgsoIx95Ph?>2f<#q-!$|&Eb6={DPtFN!fTk=j!^1Co zAz?H2M@Vk1{XPjhOXA(w;JhL$8ibo45pn$-a^An_MDdACME{mRhY0cD+;4r%3=vPiiV(-7>&%Ex;Gc;2x&xio~P6JddJ^N0-}IYFrzYxcS*4K&%LA z;&6MDQ*syM*j#x{n|7G2S3LQ$iKA}HpVS79Btl~cT5pewMEyp8Dl^g%g~1M)MCMpV z`D5BAyw51?o1uo0^K-Fndv{CSPnEj4C@{bfsuA=(WIR0G_9Ir*jMMojf9|~NP7|;# z@T2(85Z>7!XHj<&fJLw12ZN+F!9}7;4Q3?DLJbgci48k46w}E6T6|9BMY`S<;Gax- z{DKi$QoUhQ4*K)@V{PM)r>Q)s*w_!;p6+?f%EL|+{w6is;+ez}u8loTBsvz7hfZtX zTkla3>0&iYvb4V;sM8^oV4BGcK)VoyZ2jj@AB)l>jeq$ND%$}?$pxn-@t#*^9)|^B zv66Z^`OzuIGoj4|3)x!20payV9wL7P&@JH1_}x)2f85}9Zg2aZ%xxwS1%F5qS;T-7 zEm({OLQ*fc`k_W}!^5qsw7vlks;AZ@6Md^NH@eq_lLd(mylg3pR7;pF^^n-CdR()i z{G0#-B1Lq`l|kH$lR~(8zBn*}DOKxB^7MpG=sGo)A=q6yI-TKTj7CC zpl}nC3-jQO%=Uat3zR;9JS!fejU=xcf4qbxi>L;#X=FPsuRigP@#a=0m#2#C*QsE3 z&lc8ei!H>e)Q#VZcUN4E0QJP{$e1utD3(ChwZ{;Fg1&QH*zkK1{g~|e)99HaD-$TS z?u#*~YDGy_Ezs+Y{B5fdV`;bQQQ7p#o82i3dnWBqY3Kt@8XBJrH{Co?p_i>1qXMO* zg=y8yqo*eM2mXuIfsUIyH$NT!Uqzjd*ZIN|^F21s&F&{e!{)+H_qqIp2xD^BYSg*v ztF!#1rJ?P{)17?^7zw@H&d@05fYtU!5cYnYOG4F$E3hu#zcy~fyCi%pAq(sWU(Lu} zzAE~{du|oGDq%F;jqBQMur&MI_dCO=i?Ldpx>!DZiZTal-)y4H7rl2zW<-FU#{~uW z5xSA!gy~gZ6m~K6&OF~Yoy&pBW)81_Nb;I2Do8nGzrti+0M%e{w5yf;vc zduQSFDSD<k<6 z*<26elbCA|cHLIoQl}Abr^$KW)R(pMt+^$He)otK)t9<;8|D6ViwnhS@-OQ`+7n=7 zt?@@&k^yB`(}?7{F8Xl5Pxzfen_oLpbB>!2!N&)^#`@ujON{=ekvReIQWTt4y2V=Y zbn6TX`An40qr5EV_M6c|U~VUg zU9VE{O6oK|_$6LDDQmiPR;j0|L1dg zw@{CV+F1XwJj~ekhDp6=jo5nWfp|ZgLUh0BOls70MA|y2{zm|K+V-W=pCYyUR)wx6;5ae6XRFY8U}xmmG1kc`eQM<|oEf3ryKE7&J3wo_C zq;XOQ)vpar}eris`}yljC{Je}~zd9_GC6SIrU&e&XAAIlj!9 z=Wz%4Hky%6-JH%BWKA_p!E{ZS@@H|TY_;B7+Wyk3)l}=WUK_&kDt1OusfcHL#K9wk ze+tpIPNUCXObzJf01fh}Ub2S#EW?3{VYw2(VYUR3MXK!|wuSUv&%|EGZcG*_b=ga* zxxA}$@i@dcf~slpP}<+0OBai07nOvC_;XccvMo+pg4?`j_?&3oe$vtOD1OQ5APXMc{V9=@%N)v20k<}DNwV-By^o_Gt9tf? zAlO0Pss5yRH75LCIopf=?>PCS%0>1>`_WgsXNAtBm8rPIOq%Kl-tl3Ud{;eccA_1+G#|IffeL>HewcQ^ZbI)8^c;QjeV$k-w`;_Uv zEak!6_F8`@quk&nC$C%sXRMEwHCLg%J=ZHK70ccHFDk$)1NKiIK!WUy{#psl9(?8u zG^!cn4;P*Z$dnjni~RdvuPmEGh-@c!PrpR>c7tFUIo#|eds$Bxd>P<0vvtn@m7@t> zkn7>Q>Y$W4{qvC=Pl1Jey-rIX7}otZzGXE})eF4CI$@S#&plFYt+NT29j>nVX{3l* zuT4}>xo2Nim6y}Pvt>?e1`^_fkocfI#Dj*1Gr(f;+*_UMA&JMRl0iefnNweu zt~Za&VCJTuS+d~@(4u=DAxUT?SxBtbJ!9`QUvQPo=Js-M3*Fv#!sdo!RwTmFm;XBV z*C&7VYD~gzgGrxX(PxHN)+3%1JU|>s8uR5CfVdzGa#~ArVGyY#T~b;3>Ay_BbisvT zy*8I!WzIA6OMUg~ywnMBSO724mH;FSqxO+bBL|ViK_=49lJb(3JOJKvN3HM*CEk(S zyf9|DfLeu@Q^2pV*_Udk@3_2cFbUMf28CWzar5{l3Z&k+kZ{^W?aj6D_>MD`K6lJG z|M$?gtO9**S;*rVh;usPK}i|OXK7h;de~q{=?A@85Uses(q{y>^c8g5Tai zW-QqTs3nk{EbmEa_HS}wcf$Y|^0^D&Uf=CxGt~=F=$egq*1r_TkG)Xh)dT|^>@QWA zH{ShKcfkB9yV*hAiWk$k$q6V>UVd|;$`YPb`uBgtS)FSD7SW^G!aMxV0D<$Hs#jo! z+eJbgI<#J=xxK8pdxHIB;P^~qzm;+R3{RF_?%D*g6)1b1=8ATq8n=ofeI!UrImx<( z>8*`Jwx+{V@PO?Je(n{s#;L|EBY929Bacw<$I0o$!MPv>M&RYSu=+yrrk(pyo+iZo$D^vhFf4<4}7cAuGjkvlyX9rtd zU2J0xzP@x{irV&D{(@b0UP;|7z@10?vA4NW*7~r- z|C$9yWPv!0=?mV1G~D9W6S3(&HWeQrw*Ad%M(cf#erW;Q+MesTGLc61c_~C#asNsw zL6Bk?3YkEAICB>BzGIAc#P4uDG(KDp`|P+6edz1 znl&Vrz({$WGyQIkWo?#T2Fx6c0eZmTzz>0&lXZNDwljFj^DQA{+Dj*kB4zc?2{F@lk<5<3LAA=3+woKzgthq+kJ9g*@h zWW>TZZOwKUD>fbo-JP`=KYJbV>rZ=7klduTzA*WPi+U9q*8V%sO|wum*Lv5k&4cGa zD(!QoPwxHEQPq8p^^7F6nvB|c$sOUUX+Qb7q~<%KfSbe6DOOcE2)-)_^#haRPRs4! zuNRHdwXjIw{&;EAzJCwFP(acRxE(CIyfpqzB_h*SVr=yY7yAAN|5gp~xJR!<>vK~o zJUUxtKnkd6x`Kx5{EXUZza%!ixhdXsodib(MvJ$G4IbBL>cn7=9FZ~gvR8elS@3#X zG72KTNn-iu=$$%*o4<1ROX2j3n{E+e~_y3cW9F&0ctzy204V4@L4Okk7 zM7#{|e*59V<@JndCt^m|t74P=QE;=!hnJ)qgF*W2q6nRJ0Df!y`DmCjC3^1?F^PC>p{GQGCLxKCh^XWA zRMN5`aYDUPsa)&v*O1`zdk9G6;JZv1oT3G;$YdzxI-mCZxHeAd?&z*lJhY$fxJPO2 zLoaex+S~`Ir!B@pwW_wKv_T4j%(o4eET$o&Hq{<`W5o4m58x7bM~e@66F*8Q=SD-}C-${{}dc zmDT_j*`ry-DfC6dnr0+$MQytyyaSz=s=zeV8vD&J7FOnnP+yt zm}yl`6R>tDR{}yzkLJCCMDyAfPb+uWd%10Te+(ZK$Qg#PpR2o9_ueK8T*`GR_cPKz z=IY!r2e1s-(U`1Dn%?~R_StKz5JVGq++s`zc%}g3$h8+{$zfHw7{oKoq`V;`vEHw< zg1(wSluIyL)nVOd9w7F)kC|u-1%#s1->>TU4L2xpFpW{`E(xe}sm{`X+Z`}HUai!y zj`Bmts;AV}U&x3au6@l4zB*I}m!|681)_v5>v_?g`o_IR( zGu=I>;X51VshRdUVXWE0>FbTfApOl>f6AB0Y|hNxn*Ygm=*4E&q57L$)4I9g=-v3~ z7|?K5O?_?}6W{4m1wQS^;DXFXC(?KlIRI^Sgs%rXt1dyjK(~TYiuJQA1!IvN+n>mw zPJtp)DB-lKtGAK5^ox}2;V9b@(;l!+MK@ZOhO=FWB?9U^H}1ZNWWY|q8QWo6+PF*mZymLRnWD67%9d}Z*FA8=|hctT3_krJjDG?RyuV#L@2%1g(;2B zG_$h#bonswsndJ1gUb!qrscbcgJVHaT5wpUD`rBSAqfZMWq z$DP*!>s0f1v{}uNH_8o2K;6CiK2P_Clt!6ULjbEbwK`Uo32x-me&J^gH3qvKsjxctXelaoEzL4T*kS`@1LXv{;jLXa*@CjY(AF_$wx= zkBFtQ%|rkl!#S)gn**J*L^#*^N<&s(7T)hbOAdOT#s9q^dR$$cfporM8yk}D;{g6C z;KxGA>r3iZjm=$-s;jL>(5aT!ruC_ZQ-tP95H#rFhi{Z!a0Db=(a(K!A)7cMPgSo_ zm+bV8W{YCd)17A00pjH)dpyl3fsLwqy6Q;V3^|Icxw$CI2-ZZ3Z|UrGAne#(B$^pa zezx_l>);?)UgXUFH;RJ$hp#5a2bvPOq6^A&Q8fwk`h9Qa4S#Z}Bq2n8P-JpnQkov3WWth>K7%A$csSm)lb)JeS?~v~+^N1(nCI&)oK%C%g7#Q%U-@*Io|%IDRl|cPzqz zC`q?4lcWDjfUqGNx_^3#nm^iJNy=C(I~59;f(L?P3J0GXe@4rf6qIh=yd?3pW@Ay| z`~FI%PN#0PL-i|H*NrlUwmWJLS|Yc(QK_1RcvMR0!5R>0PbxLEw=S0haExtXUmA=V zm%7VW&TrlvJy*byf$~?eCB)g=mI9l_;ZhgXi4J=YJ6E`mJ+DaI;-1m>Q;4_^S|ju| zaj+uxuJNZ#Pt>j{$XSIE0cMj@KzbV7Z6vD9!X*w*PVZZ@u{-@MTK|@993K3N*#KW= z-=21M*UMw&fkG2$4H2TPA?(QOEq}1ek@gB{PeW11odCF`>p%~SW3!CCmvNZ&<@RQykrICG0ryw$v>}U5;Jw;GoSvIj|6Vdkb<2{bLR9jIo52Ni#}~9=*!kH18k5Pv(8Wo0R(VETEG#ncw0UeEW18@t|MzZbrXhM zYi7$h7f^*l_uuUX|1BFyP}=ll=`Z22U6U80Gr<-3f+mD`u+}vXa!JvU^9PCaECcMgR=Ha z&0%XV#3|R?Q@ ztl!I|k~?mbu@Y9GtZsms=TbATMP%$Uld!3`{Qr>k)=^Qm-5V$j-6 z9n#$}Lx*&C3W9`m3j;`ZBb^e`Im9rW@%`fWopaXW4;E`!>$zv|XV-P@>s|y7@JFV= zj8t_OTLzvg@yb~6a7tKd)JMt~jf|9NNt^$9QP?x@;|B8X)6p~3AKNp#tB_|9RVtFy zw_v}Gb(Gq?7jPc0;MGc{swub<2gjHXzgV2Wq>xN1m|;zN8v-Z4fC#^PS!cJ=psU{YvGRhqRbBhH}Tw z5b{P7f{ohdO0QIZF^*0>4Kh9Y?DU#5fsfGsUd6FubsEcyu=f(IZqIHKM-MO*HPrFd z2HorPao?~D-82CQYMbgC4aH}j8P+6V2n=pmYsSQBcCt_)SMS9pf_2aY=DC`i#CUrO z><4^EbO+bpqB6M{lSU3~U*$J7;cl=`;py>ui#?!(;B(sO zERJcesb4spr7!_!`KY(vNUf|Kr%8t0nO-2P-ODggQNXD}Hp6=Njf^gjPBFAZ2Xj|4 z*d5%`t#Bz2ftc>jeBioIjHF@AE^O`N%vql~6Y|gRXIAXS4@D))j871BD&+}cF5^Gv zvDg<7kmEyIi?W{=-pQ}6bw6!-hD6Oztu}Q&hdJZYNYa<9TlT(T)rUp`!H96>9MPb6 z=bZmN;aDC#zj0jkWa0zccrbsoFcbB%pC};@dcgFddEq4z9U1_70+2K21%xYt0k&OE zyUW+6NB~MmzutX?QdtS-RAwj**$}%%`Wqko-r*`pmsGiS=}fe_-hatVQ=~MUm)903 z*obbid`8{9pD9@;PTUrxwA=->(Blnd9Kj`Ubuzqb4(6 z@L$RwnJCUEYp@IYWOoDETFz}zPhqUpKh(+0njXZzDw>j3@NrgDH!5E3nr&2! z2p+hPxf=}=x#1BFD(g9%bV!#p%vl{Zrlj@84}N56d9w&D5QI#DQa#*Rf5(e=S$=4- zz3~2E06ZNWm&RqoB9fSAe<`dz6AsT3ssG9n5q}?yn+-huA85lg8Xhm2?mA@48t|;T z;iq<56Ivkx6%cOEN2}tlo7hXQcd8I>@eU{bvQm_%;biUYhKuPz?ZU6f%@>Jw z4=aRfFu?abiW?5O$r6bk33)*|64Ou7{ePFQZ+|Zj!?z3-=sZN?H@?^8^}jlH*npKY zux+h@UkpzSqd|RG``a{aERNKjLnURKOoIo+lVKJO=vyDR9~cC^GkyaVqvV88z#2+D zho>_Ha37`$zP1)ng8P$fnHkTZ$-9RT`9Sb8i#Yf%Cw#kR^1t+(;13LNKY~ja=0n8y z?*B@S@L!!ogZ*W{Yvsnk!EA2D0PBvn5W%G%yHX4RuZVW39ea24UmxP`Yp*cKfdh-+ zwIq6nI;J44FtE*OoyOK%Q4~(aY4CN?-Z}?Y3`avhD4IBtWaG0zbhx0p2ZukdOs2*_m{6B=j<3UET~|W!YP~*5m4JDQ`~8G3Tb#b^JriZvn%V$c@a|TEnd$VPX0yxzt1&Oz;cJX7qUq~15$Nz|E+;Nw zrcDsUBH>~!b&2cv2MY80>lmDL;GX~bJqG+QaK8^LYr?Y)`p55C>_5Y~2iv9rbtMo* z5n-l&@6%QzzC|uyd@zX1o_jy1(QRzmVN?4P{chS;IDUoQi6=cQ5_YCR9dqg1d<>TtgAhYjtAQ?3ff$F zGv)+Nqm4g(=6P)~@7z~hniE){@6mAgsA@|27b_*IWx3u^cxcL}vl|D5ipPIKEl8Jj za(`$suvsdUu>U{hI1&&C?17Ct*!Qo<8vpN`J`?zmg{P~Sz!WHGJZv_y(ax?C%ZH&h zp?+DmRoq&ddMTMXQ?KBvS4@BGu&;)D@tsxCELY#n%5N#Y=n=6~KgB3;3BONCYRJl()jPN* zh7IyTg1U0h4{(^fO%mbanI$x}w}Rsq>pLh6W9|U z?g+aWa&JZCW+o%>W0kuS?5*(!S9jF755s;2jg&kTDEh(iqrY$HL8_#XOa2R6oG7=8 znB@Fb*K)6k!z$7X-XIZYMKZfu?jV-M+nlp?UvwoZ9dp1y6K;QUH&a}N-XODK7Y~3v|+wx}GR;i%B z1v2&3D-WX`pHK4f+(a(YOl1c#NvVU>#6TMR70SbNCRo!d%f zbaz4r<^3mJ|7-oY`~06MAPQ}m^KZreCklLqTVqh5C?D8~(f0W+=KS&al^UFth;jD7 zob>U)D>Cg*aJ}FXMKC(~Xhq;^2pB%_Z_{bVO;}&y!S?vc8gIyc*o!|d{yQ-n$+4Q? zOy{);Bff_T_$)|CYQx@); zuIkE3q&9DpI9ef^vz-GQchvlH+g9RSZR&Z8yI9X24Z4>(b>%;Oc{1Ai10DW7s{PL} zKpQS^2DeTH(I7Q%uqxct9aI-Bzbyl7iM(z$;9)JygbC8lF7%j*%~-(fi$57X^*wCH z9gc9|!}m6JA%XrWS7&0hWWW0$Eb(TWqQ3s5u^YF#<2OPM2#Y&=g?;gX#nF5YP z^@Te`A8{3h0N_Pg^gDrgIP4oQl|lY@JOiit9&~ELH3`3?L%53G48EV47G(vL;pY}R zckx;Ww3krrbPbtf{=uas1v;4dO$e@&Z>0Ze^HY9eUkJWiDJ;As=Rj~(-2-dMAjPg)RPNwbP)S6S(D$^1 z9Z#8Vj!&&80gf1~{vP<~X#n@U!$B86zJ;Fq@jDv_;W6efeT{jY_k1-`;MQP_ye?(g zpF*-TMR27rsZ2-}xv#b5J}-n}hR{XqIke;`0Q6E1%g_72joH82Ge3A-S=@F$W6lD1 zBM;T-908Np7ue@Oc_ljxVjxpfZZw{Zuq1@)o#U?kBqsQP?>IA8W{wV-De)n*utS_u zLkOhKQEDh!8*zS`+1(Bg736;|%NU<3N=TKKUrU>18$ytE87|Y%@jy&!?Omb+r+7UE zl)P{-79vh(oCu~s%!IBPkrW%bxHG5T7brgbnA}>rh*yA$wGhZWb3fEQDzhex0k3~9 zOTP{i0dU8lw|#Y)li)f{SfwwZDCXW73*7eBVmyb54`c_*(2enZcXIOu(d4dmN!+Ne zt^Ai32gm#VLVhp)iRkj4y?!?G@LlY)1yw;-STf`szDowunK2V<64>Ix_}$KkZO$4V z5XH&FjS07%wB9yxKtT!Ub@b7|R{o=XCk2D11Tp94Abai&n*WOyLwiQqldZbV=pW#k zvrHshudw3L?DLlA4>QbqiF;Q*0weHjw6i!^CWAb|JuRD3WbN}Q%oy2pAWJsWSF@^j z7br5IF@>jS4t)q$Fbl!DyU-f>>jvNjx!fW&~ih*eBq{f!u^zFN>g zsh#isGAbhkm%bbE6cHFaZfi+r=TC6uQV$!}@Wjl2ALA1GYJRsuTyCa=j_a1pNcqbq z$6;4_7zn1U=ndakp&Fg=mxxrSS%roHq+%aF63~TFo&9NNy5`yf4&OhZ#ogVwDyr); zWS^|UBRB=v7bqfYM%l%l-+QCX@=02nNI0~P*>fL1rlbAzL0p#dDb_?C#|9D}b`4iE z>HMb<`hTk~=t8ZEt`IMdA4lU@H#>P2-<0edU%%Yb1F6qY_ZM4BEI$09qJrDYKyax9 zzQU1`kr*FUJL#da>u^+01Km!&)8`w8m_*rg9BQfuc}M?R`I7@5;I&>vb#Y-3kS!J} z!x4K3*EB$UCTzLu-OP=b>MdHpe6yi_e^#r1lqQ%XdWiJo$JYirGnzbK&@*_z3d%zw zou=i2+@Ycf_l?v|lIuEtX&EBImjs#p5za{-8oStgTRzy~N7?pd7a2SpZF$t^o?;PS z|9_i)V=+N_@S=3z^ZUKOPR`$mu>yjVUb7QLH3^9}m<3;pd8J&B#jBI|?j)U&UXYSf z-{a*`S6d9N8%iKc)A%W&gIkeYIg$qPw}wh30BKH2gl!=3>aHc@*_od4n;Gi!4=Zlf zX;Y1GAdi}GByVcc@Ce!&6QU5NoCv)Y0zC(ZYm}x^d)8fiSc~Z2aBT^wPUD{1eHN3R z8HLXfB=}&IGGw1ll?_)+>@F#u1r>L_y2?^}o8ahrD7<7Gx38dz7n7-X2agu;y%((s zU^?={DsDx+)Zg5%VqYEY_rD)8$6$*IzIwg~YS9W=J`_&8JX5jH52J2FU1$ehE^qN4 z`7NsZZv`3)-Y<7qU+NDZh1)Yd4?H#-3L2vyxzGKrgkf2duWxALwblQ_1yH%2U!raq z6iRuzem5W@Ov*33J}mCv*_9(MIw)~chr41h499o2&ob4a=}rR;n&Mol;>y*FgO>VL zlwZcCF!3+#O3h?K_Bv z!mcMtXqouBk^Pw-*tna9nb#XRE*Ef#EPvMDNvV_f1VqEVH}&WZvk22gBeUR23Nd?#X)w{Ej1HZt8VVBCs;Wfp zb-q!5C-^*pF*yBPSwb1C{H$z}XOVOJI?yxTlj-r#@sT^E9%N)sK(UiCTsN^RWK%zB zJv}iJG2H~u^ev-D!2FeLpY)MBnx`SZNv#ucYd15R2gE>S|1I<(#f)joTx4HTN_aBh;?-hpSM#S(DKd+V;$$^J@)>Kt} z4kc{eu%0ch#Jq*PZyan&`!|;EaDLC$)qdt-nb>HNR|+3Pe4Dyv=q%CNOg@{OkpG@Z zFkQ=s+x;*~QaNDw#q52yQ=G?ksgUr!_^oBN>q{cHw}yPK@|fAvm@GXkAM+a&l19X^ zy#v*Jc!hheUZoJ6WJ^06oU2Z^jC+X*!b)Z{HnPTsqA`qDh)RStM|R)AR$&y5(knDx zVpA2uw7s%}#u@o$WMM^AazCztQ;>+YSkG;}MG1>c0D z1>vSVW2HG?Hh#l%$Yy^w0!OB6a)#}#-3a6iX!dMQg?+16NhRE=F50G5u-_5q6I*Es zogJvnELnfz`_3wKMJdw$_^vwbD#cxd^bXsz$cQs>lM)O%h8%jLB{l7d(ewv5lVx40 z7;P{!J<Mf+Lj;}`)-x+-p z1u~O%I+ANQ4+si-4TG(o^DL$)k9O_jjt{*&D7BZ${^^)qWS38FVDF`^sb@m`BPh zq9jL&^*9WU$A!Sn&*|RpD43nN=zHdu)lmAFz(tiTKXd+(6xw@p^7bG1k zx3OA+wgh63zvED(PQP|^oAGy8aja}&f-?QA{yLOQRC*G5?8Wl^hDlXXPKJ6+Xd70C z`I$qURi8j9&{^^A_33Ndgdy96OgU9oM&BkG(ftM!-Wc!(-08A0XqiCCMB8U$E(H__(de@#-jHkI*D36)iu zQD?$p+Sz79RbpJI%!vGGYH-SX_KfR8-QUI|iuqb#AY@E+w}BX<`ao*;&TqKRRQyXb zDUGuwduuhYG*2nA;1JIZJ2M8>Dgomj2ofA1OZ@n7r5T6VARF>P*^7=N1S1ZyA$!&TF(joBOk0G<%oZ{=#Xx( zy7C!<8xgS#b>q|yll|3%T4V;B@(^XGi+H!X`>sZI_2cV|BmV3>NU|u@@t}}?FTLgO zW7yCyc3yb_77O-X29^e{?J}4eAUlcfwxO0UeOGzVY_s;Ua^q%3YD-7mXRB1Lm!9nmDRjbZVxGVzQwT!-wxpk zM--iHQI=5`PZr^gyum&}VG0y&;M+zZnkrMKs!e-qou6FhnkaVlwAnGZK#f zxB2t(-BN9+UeHb4pQJ?l&QD_bHgi&Ig#ydTUTXMF$FR+UpVtTv&68w2;vwGwg&X`= zIZisMI}7a09UyRz+^#Wj=$#pyNnv%YAThaJpuD}_G5vF8=#iI@^qUvCj8VomSBm5A zy&N>qF|2uQ2vzXmm6{svvHdv8t$Y#$B5$D=-98<9{g|F2Y0o$%nuC^Lk`NG9gvArqTbyzdHl4&pyE38x1fSf;N^gA>5;cZY-s0d1YXwynPgdzH@{=Zk*FPcgRg^b9i~ z$I!>8d$>d~9;T1xcAY3r3KZPv6i*)gVrFJ%&f`lV`r3BR)o;ecU!LJk9p|T~R)QO- z@(Zr-KutH^=SRzAW1HY5WXAN_2iJxU-HBAzY71$5{!?yI1Hx7V?GJh;m+IQ7Jf(PF z+1g|0g$^K7P0?!J$qiq_sTU9^_VH==Cix_f){wx>1!?wFg_8%PPj+^b@|qU&2g~VG zne6kz3ovI3(x60~Z?*qG>L1!uT6R;LqNCBBAJl)$Z;2VB$wcSAPTs`6V?A3xHke+FU>`|b*G;r* z*p)t&gI`$Ce2*;RxGZ&qxx44VfY-u#Z>jsp!rU`?2D#+3>%<3w8ge%%MFCr9;Z6^`5ad4x%FvB4Yh$&Cxr$-dX~DdsMs%aWqraP{Z|XEN2O_ijK7r#7-H zMQ9w)rq=!|>fpPalZ^P&@AP83WPe13Ba|*6i7s#GV7xTPZoN4Zk+@;_vQc2_sI*%T zhA)P7ZF~fr{XD^_;bgJHGy^cl>gEk35h#{6+Q*aBV3h~SQu&g$uQ|}Zk`;;^Qtex za3TgpQAMMkCOWOqv9&^1F0vI}!Z6K%&JVZ@CzCXvx7Oaz z6`iR0-L9la7o8r$@Zi)p`#7pl$KN7qufha(^HbF}pj1V<V@D#gfWCaq$lkIaIQtL)Vi>B2l!2+~5_;+&j94?Cngf8Zzwvje^G8Rf8 z$`qtq-~^V}tNxMg-JE$~SzOsvhLI5}nU0UnC0n6l5I4%I+?^;1y|#=i?}v(5b6!?s zr(OH6fp~$)(mQ22u*5n2Rf@fII#ZlFK~lh1`j_HlX=MB7EtI63E4s{QOX%I#{jr{( zC9a=7Fcn8a7kGICfPH>%*V+Yx2OeUhiiEzVo+qH!$yjDY1AtcYQ0w zNJ^+D4zMgvOcq`u&4Bq9etPu!By@#=FO;Zzp}W0l#&EkB3isWR%_eD5Oh}g|pI_Li5T6&m zX^fl}=fSpJIlQGAW8xgq#P*6ro_eh34<@7JMTaiE!}hUnt!Sn8(#xcgcDOT-lC9eI z%=#-D$l8N*XW>fqN{ApXLV-etGi<~{3T^9h!i)0^8YZO-*qxcp! z(E9m#AIVFUdPN_=m1AVT%73B@rxp)S(8hpWf=E;Pgtkp)M97fnP- z?IP-xTCj;q$wiV-Lgtje5H34#SFSMknXH1dsH?aJQi?+Pm|Y?O*6dHi_#e`(x0GI2 zQTHNR2!E%N<$@1^!mvSII(K`vkEvbDE)6Sr4p+CHA@pI*`+ArV!6zE5%u|ELauNtO z(g?B_nrSMd=PO6A_Ok?<#?eo2Tv;9sd~(nthm^Uyhc zGCYjxj3rte`6k>4EUI*`r@~?{@9UtY^B>!t` znCB|HTcY@93*Gv>zQf?kP!<4)yiyyDudcf;|5x_y@KCTGQ!aWdSii% zvUHS!|4ntEs)do=x3rFmGMA_5Ki}*|ax+bViFZ~Tlvt|@jiP7tHOGIt@0sodXDf;t za=ukB*&*#Ar7hUdbInVc2;6TlsNq=NKD&>>U0ZUq>WPEnc(hPnDV5(q*(m*7{bvb( z2o=YuTN*~!_M~3r;&oL&x7e%)(%SWA2T!#V{?yc)A=*%eU7SmF;jnY;E3R3Z*tgQ_ zbZ6r!GKBRsG5K#VZ-?pe2x-j!cyHjcdY+0w-do98%jw8fr5zc%v%PkYT&V*)gADc# zx{epNe~}!}j52q85O{4X>)=IN;F`&(;%n#3FT#ZYQ%k$|uLGLbXeBEmv>94{Ak9Lg zyh4lmus|Cuel-ZBYxuc}$eC%vD~e10R;c&zIx3u>u zmIz?s(#9y2BVHQ1c!m{~EYw1zpp*(6iSlsIAt)&Du5MC=RgZ$n9`W|2JCqVue3KPu zxZuDKCRnffJ>W3973wg!ignhrX z-v(m5&%HgR&KJKb8SiHRpq?yrKXn?09|HAjQ#i%GcI&Fr-};{n0)%bi%L`W~-#MaA z{NZsVe&m53Zj5X(dS5XgsXhS-$_e}aR2!HwW9{aifIb>DjMfmNd3a{p38;v={eI7F zoTODRcq=dipn_7_whl;;TumXKlr3zIJJM?`T;^B8sHGz%&quYD09T1UO+$=HDj$V}S_FMi zKa@4AOYVayhJ{~+%^c*X3a<@Y7RZWAd+?QB(($K!`|sGd#B2oJ8}_)wbYJWHGat3c z3s;e115}ivJF}gOEF-2kmv-U_o(+0|07GxDqbrxu4 zIiFa+Oo9+Pj+uvrf^Q$Zzxs{8gix_z z67!Rl=vjLGX2+Le?SmTG9}Nm{ZS-tlg@SQqbw72RP}Ha{hLula$_yj;U5g}^y;}Cy zQbN^sUIWC`N=}d?c!W2_u6_s!kA;trVeB-8`|Y40aLEV>BVv=p?2U6*CJMlVkek@W zTOlJ*qXB~q5g3firOKM5cj#DxB624>;}QpA2c*`^1cL#o8`MjzkI0x@)=h-mq?yD* zq6+8U_?a1=e-Jn{A{9@VgJueh82!J@oj87AEyXw&+{dnUy9MYEtFUK`(JXzId(|<2 zvGM1#RtSaeF{dfcHvl*RG1)d{%8&;;z9urih;RB%A$?VHH5g&pHFuuUul?fE-sFgVRr zbebmP1z(2=ULgm`xX#L9F00#jIQTMh-*%~ap0|X8MdKkgk9U&6pQ(pF)()hP0{7W} zpUIhn_ZF#pJF76F>J>Q(7zz;*aE}X*-&l7w0VsDNEjo*h|T>mTJ@YUAcCLYe0r^|*+(B(Mz zy`)7@6=1GG$qiNt3H-9Db1vVLFiQL43hxMC7UmU%zkTdWB@C*(C)sIDu-JUy@J6^J1x(x~7vFH!5_&P9V|2yqDQrIkf{>xHcph` zHqIWdFG#Q3e`8kkZ#+JUygMvFCoF75+%C8({}r5!x`;i55fsOArr`M7a6oRXsKh8X93W?n*(;$@@8^#FTB^EKrJm$pI9`waM(t~SBS*^~OiaFR4^o4AZw|Usre>jt4b~+dJA*c486(~h zqup^PW@bT57|EW5Cn500VjjspNtZlWyqhzqWv&<1JWV89>1wF;$T1fML3$67E~tv9 zyQaIK-Gz6woI_Paz4%>47&60H<-3h|{~TL!6iEV_G+Iys3tS1Kp8xAox_h(DRb{So zu4f`s`jkQ%~#!)9F!HAkbE$kwMQHRo#m5$j=r6O`oIO>0&p;pe&qv`^C8oM0X9^k3lOEm*EoAJsa+uHJu2D z_v=d3rMY~!FLZuaZ`-KqgmL{8Cp6W}A@UD$|KYu$SuHhx=KhN$YFv(KAkG5#>wSBG zF2x$B&`svA*!4Cp=4Kr2>#}mQU<8mA1WPChh$=Gga4W;#i_p!bz&c!U@V{}^Cgc&2 z>W#adX4(a^uNzKJ6b_!d_(Ou2!t;*8(jLK^sw&B>_8V2jyd`H-ic|sX!E#qA@e8dS(s*MC`kEcg z%80mQy)3yt36%8gwo*+V*98Q2emy%C)8PdKBi9E7quvT-Spq`#Ml8FfCdjvj@W=#pQ`_?75zdBzA`R?(zcnUj~&$2B)RLn+Y~{B0_c+x(x=J=baR5i@4y4V2p-}XC@e=X4s*>-w!2HM41SmMp(f7tWF_YB(XHomZK3anm|G`anj<~ttpTn05c2c5M5a&_g*QH!DF7WzJbSNYV@#pub76ea3->eu$vi4tf4Yg=x zeYEF}u;d_Amc;g_71n*1pPMzODLmH|8h`xMl!hsn{3(LE5Quk)WDSG35R~H_J|j~p zly7JcJ%oT55XKXDlcK7#a%+z)NKx4IrtvT|lEtc6 zRhu(qQW@tSX0x# zKig4)YTv~Q1d+opfoQ9m->YBlQlMJ6P;<$#DXrDfD~m~$=*4WJv(Eq(P$8dgI-`LG zai4Sz@Domqcmw+P@=8thCaStO(*wfmYL-X#?}8Mh`_US`&XK-h7?Q{)f2icS!-ajv z4@wmUz_cJfO=BA?{njcA3ttTzmfqJQ8UMibcuOacZEdA**X09VyyU>Ah{f66U%*=B z>VwwSHL{7d1$=Rapz0n>>MOG$P8rYs8E9C0eY3G%hGGo>&7&g`iV2p=@_zrHI4aeQ za1Mz-YLkX(>R488)`%UjZW+?ksS@HBRIU`?3M-oLX1wl4q|nu?ufZD9N?{jSJi-Cn zIGwjxD$tW@rV?PkXk;Ou6C)EjW092gqGhYxV5J|p5oBcyj#Jd%*{qSo?Mze6`H<8Q3Z{at*+b`VSg76S;lfT$e?&-#phIzcOwc-XdQ7Cw2m8$w5L%ax3$Q#NC4VDt9%-DY z&}e+LYq%HO6rE2gMe33v8Uw&^d4Y%@6q-x$5W6P~cNxm&9kCiZss1ElyD|InRWA_6jb)bJlJ!1{3-Ybm7p+U2(%YM6+7 zWH#o;=WHeW+qdHZ-K_R+<{9cILnaDTSclP_zT({aX&J(dzc2r|CR? zSbpq}A+y=G4xrGQ>|abm90MPZ_&!phq>33XIF@|)P1a9qiBh>EJSq-v7yiaf96F}S z{gkkNyb@?H-Y&gHh5m?f^GRjPl4qs@?NWt?tYjBd)sBW%IG0vHa~Jk9tZ=JCY=-w+y7C zgu$|I7{f2`Vo37GC^W#*m?M15*e(+gNZmXE{V2YV#L8HKGv0_e1e~vJ=zL{c^dTg} zHKr9ES=Nx4<<**bF0HK+OS`Q?-DeI8`^W>C_~!Y1aoqr_r{iQql_vC}{WW(h1n<8c z!%F;fZi8odV*~$=%yKwAYV@-S$eyuIzMJ4=U3Cuu?$R3HQriKYab+MuhP`1=s`G_oc zpKM8!LFnTQWdG>b-Rl4{uoR#pc}dSZ7F6_M8PIJ)?p1PhRyUynO7t^fW%M+$u@8+k zv7dUe&{O){p1x2zB;C9K#<;s_mcaV8)8{b<<5v%oKda{OrwkUYuUk;Pv9o7pJ+_n5 zy9^?-6Hj=7;K*^+kF}SJ2%gg(qb+@N_a0%GF=?rKa!AOsISIV6pdTFv|DqLh(e)5r zll(BJiutp4007M8(UN!Tg&x5OO`a5%Z!=;|cE)m_1d+b&SD&p&aA%=d&U6F`N>UtU zU={ND;%xrY#?K~E!FabbIt!A6IpQkRE< zUzbwi6Zd~RhMXb8+={z+X7-+{mgZD0<+{%2o9qQ$-hbIVe8|rS_%S(<1-pO;qW^H9Uy-;&&+Op zjyprr_KG_{c7x~HUqsR{qMuUZ3fzx=EkWnn-Z^*XE<^bPbiy~3NPpSr9t4KU5$1&S zAh2s$IjlFBE*o_rcN?jj5OwEcpsTU6n!PXO$A$UHOPO_HF6~Dq2dl9r`Q=pO*g@$O zS2>9@6(*5%9#*renbn@?9$zIRv}w$MhFT}gGZwI+zjOOb%Qban=6y-79ls&=pe+6X zTVjUol9b|E6|nIH1$pEojv8*iP1ZBo{#=tKoes+Ac~O`y`||P05vlOg^hEf<^=^}d zG@{lN>}+sA6P0{2z>9~^#s;}}`{>ww0k&kzZi-FgIg9|bOZ+&r0CG7N`gP6oPvNgR zFw%{e8np%WDAlNO@p|z^;=TDL)7}!~Ojlw=4{;q0`eFNnVOKlm*slzD4JWL4T4P?f z-+iCk0CFkpEj(|q_IDpr9CGusP>NR3_^0>oMu2{3kwbWS1UKi&b$%Qw0@QGEZo*Eq zX05=I4L&qe9KqmD+9!5N#`xGUOo%`{oa&>egmKjTKefh?7D3e;yfj0X^Dn*AFE1*P zr-qCHN|u)(ky2U0Z%ZVXdLeEbBw1a&M+#zCxUU_jD`d?abJTEPfbYm5R^5hTAw>?W zd_a4M<=W$mXw6-AQcv>7TT<_|{_9LE1kkqw1b+hkS5n*Fi~5Nx9_lQFx&;X63ryl! zFP9iMTgFcw&eZG?H_Hf3B-{37H_z(zcNo#LHV7VxG!*yLm2niqOwQQ-zzSY>Wo^6K zg8Z@*St=r)cy?@p==g!r!R}3{R!<@_n(7ZzUj;IEAPaV%pGE2etMwM~<`YOx9999a zAoz9gR?dM|*sk;lFVDscWOMh9SW=i~e>{q~WB<6=K>Sg+K?+DXHsSFR$w&RyJtt5fIQz4GD!LlVTB;6ryV?$})b&=2&3sIpE~ zO$gT)o)f>FRR$0c*f$Hm`eX!(FC=LkcJ4@q)WsP^St-<4TGN-Jvk)o(ttxMN?7GfV z|GrYG3u_yl?i06qJxYa3RDePUP2jJ5dLMJVb{hpkAZ;lFeZ>+911b53WB)JncBS8o z-6au!8DQ(EnN1FNZ=gqwXf-6z@EBTY2<++}i^>&@`%Y?+o+a5YoyynPCjc8Gs!pWg zVfc-r`16uo6JRgU0r%(Nk2+kvXJ>-X$U!Jl-LKAbz7RD(#wR1PKf-Gc6~(yI=j_;bSbUc#OFXAk#@w;#{uTLU*T?_VA@-7DnD=UJ54x_@}v)*rjC ze=Az@sQZ&OFfo9nq3jlMEK3E}_P0Ll{Du6|63QkM2Ib(Ce+qRz_)|@VMNIhP?rX^; z7<--}EVghXp~Co{%gwRrU=llh z)BK78mdCkw$=1tf-3hof{2JDq4!zny18nH%d72m^v~%%gxlf9ui@lyiX$RWPfh7XQ z!neF#0CG#Fp4g2-9x`-XcvN536#oLU=SCkej34J-lGY?EEky$+`qSj?I*I zayvuZ3r;|(s&z_x*bP`B$%#GG%06>tWo)8oaZ1Wc$dyuqE=y(V?0;NJUr)C{v?0&% zl_PlX=s05eEEGZPvS9yDJy8~yqydzA_b!)~9`Cxe7eXz9cwUv&wD>F^B10HxP(`a` z8bAXr(y{>FqP;agCoPJ6V%((THki#bdM3Y9t{5!BtZZJ`s;EU6+I%b2ZF0DQo6_lt z#oh}*go#)tXSXX`4kCf9Xl|N8Sm?bN1H&Z&Qj^d%P$c_32Hko2b?mf0YE4+&y&BDoyhlJ_e@zdUKj=n&qFdt>&KBt zld`N3Qe-GOPP%B$AzSv_<2xTK=O6bIKgJanWOs!JF>lIWw#aQyzTa{D20;nIgbnuv zNaIs(G}x;yNO5SgVR~bkj_1!S-Kr~kX%MYGAiU)m1EZUDKqtlCN{LDkA6w0A^Aw5L&>WEfa*r9g2bR z^pQ`Yu&Tu=SWcG)@Ft|#l3-Z%sUz{-@uo9{n63b66UcbAXG1{5>YF;jW=&zI3aCe( z{b%;EPdvfG0}&FtpR$tTQ~3Hj{lZW%J_R!9D2dCBYVsD2Wvt@xZkDiNP4~)&1rUc-1 z_n^%A5ej%JDdx>;I?`@(4Ija~{L}2lX6s*lA_*>o&su!58~2u-P0qo9kW1HLSoE_{ z4&uILLL6H-x32cL^HnBZ5bOLfwq2>O_folf9L);FptaTluqaraF$K0)#~f{?A*^ry zr7^^%%p?Bg=*TGT&U>`-W}XSt+~un{?Gd(;X8ZmRExx&`z>m;AAd}2<^$OE|pC8UH z<3+5>Pz}4=WZrJGB3|RYr~(4D$!q6CBv7sv>29I@;Nm|JUCK|1g{csEJ^9i5jkfu= zib|*EHtXB~w&;8)tv{dn4_OU67Jo$qG3j$so+aNGJy_9^T(Iw{$v*RKs8G+spI`CG zD*7uBpl;W}UAcTF(8E+holpN7?blABymPMgiZ~^c!U&GSg*8uyX0qc3S^hRz(C_ZV zA-XC1H3vvClZ3thx-f}yZb0NgNYfkTKlYFattyWeu$A2`qYl<+ya@VrHq1YZl`!>c1Z;vA~)2Qf1VzQ!kK zPviOm1t(v(+^qFFF6mW*5O9!59V;@I-J2RLz~0A2mrbsSgz;r2WBb`#6uUwMD}^mY zkVJ--8_U5ztu7gIG0G*7_75nzks$HF@tH)!hM*GN{lnATUdZXApeE@5;pr^{n*854 z&@mX@DBUGUgTzESBm`j~4MS2ILApjLAl)5OQj>CkA`B!)3$-Prdkl%+y!$Gtv_Zzq34b=*6_Iug{6VV}iQk3{aVup;_ac+VTp zIQ~4wRrG4PHu}i;E?nE<1S;b7?fR*R5EZirXv4RDdP{DcAC5a<2bYkq99VpH77FKw)m7MIkp^LBDHtw$r1-?m?@5 z8r9k^4Xjysy%mbnAL*zo&f_ffY2bn@_|pt_t#{_Lp3orbW9}fv>PzkHQ(D^*psmWK> zf;nWC`PNy@n%)%rI1J{YxO11epr(nXk5RRJR(pB4sNh#bL2lw zd11bex%dKLFM#XM#M4Myb6mq6XDYk&#{;goz+g*U)pAR|hZJ>^%qz>OI=>^_h|!z% z-^q5rUMpg)`x2;@c%@CJFJB(d&?r$Z}M-{!#~kVnikLC(_QTwcUvoGB8@p6MIt- z6kImxOvMO&mCI{_?7-tYN21&Y&Z^~6U(j33Iaps`G8T**Keh=<|4zf zD`nm3JJd%r5?OJ-xG|aLF+01j#=qbxc;`Q>hvIylQGtOJ12t7=+>*bqV!ghY4(;uo z6&+D<0K~lcUpYfFs_{RIBUah4CfWV=g%Ng#TWW=4%VXL@T8^Vwr~i3FR>Ghe)02b$ zUpGsyw|hBy-p?bsX3tI^V#7WS5?dm--h%l~ z%w66iJnB}b+WUVQMM1sHaN^(c!fTyi-;XE3u1)}g=chY$F|$9dc;C!j315xmhWWxW zp>?(*{tJEdfo+Eix5D{<8?1-~IwE9Qv@p+=^FsrB&$|)a;(FAoANefbzL@!e6>X3(%y>$Cmy^3SC2~-*j`N=|r+wtXyXwp#;6p{9*Ker^TxQ*)Q6=WO%XBG0U zKTZV#7E2ZlDCL(9vq5ROHyV!7SF1K`s8>zXhhHS{;9aD1<0x`QVG0=Q;e5f?cBWGF zS81kvoI#z+(TsSpXHRkZ9B+TPkB{Z86t{(FAO9Jy6ffy+cXs=_w(ii1L%AbDBP6Xl z>Wk!Za!5{Rb!y48$MShkMPJNVPC;eD#g1lJ$ZN%aUyZ5p?)XibP#xVY%_xhP^Q8X@ z_0mgxv}T6?OY(|DuEkF_9vUmQjwqeWx;M~GZ%7o~BfUMeX^N+@jBOwN7ye3Ahl!;z zTNLL{`=IHLhqp*U&RL|Bp(PV(X(pEryV+PS+s`quYh<=RRo$L7k%eodSVSrrFQKHf z6_Tg=A4=-1?zA9XZ3_>+ozmyNXt6bb5+r?YL-*PPnEN}3MuQ(~y6GwDc*Dp0t!zX0 z&V^sf4RGL}0~M_ed{?pKKlZ4DvZA;x|Dj)|{ukTC7{){y#k4EFFVO*2PPdRh&8~!k z9gw2gL2nXjoK;#5TbPDD+=2BhD6#w2msK2iJ?J1Fon%$i(VKte7paKt8mrweTj~P& zq4S3X*vJ+-$1?Ui%-L(;Qv79{w4#`&_zekJ(z@Zpr9suiRk?Z9Q?q-OrhdE}SQNB%3306eI9HwqmYgP_d=zEyI*Y>qv>Ezs3 z@YuLp7d_WU2H0yx{enLu`B%GV@z{0#!X z7%aTGIY1OoaFJlc)WE66624Vjcy^*yG14e4^+5~ev&=ZygD0!G(J};HhVA9;{o`Tn zAXv@sPa{?9!;VHP+*5i)0w9z%-l)AbyHSeQXXJ7b!6~zf*o39!qJO=|ktEn%UoR?E zWli-(y=6o!a=RD0@lcuRE63NkRj9$&rDJXU=#tWX==Z8si8BKN6!cu;HS!Fvt=8+Y z01NgChKw*;3Ge&4jZ{HE7r}aeD6YagM|5&@wG27v#={lk&iZQINC4WsAuGyct6B^MEMpPt;?B+6u^!p#kI(k_x06j1%5|%Ut1&)4@g4-dF`cjd(UlNA$=DL> z|4;=E3gAf!wP;eQ8^FVK70H$`I$28DC{(Fwh7s%O50ayI)Hv}b2EGLS zHI@aYesf!^Q%+|CY}gn}{ouRYKNJdgMsh=rTiS~E!J+rJ$7`s6v_2gkk?gvGPG9=~(U=_195+81~v6T|>4UfYKqv*oZ z-RYuW5YrrY`UCgV0OX`MBlpddv!|GNnWA2`Y)*7Jv!Zh*NZP}OO8h$ zv&qn471B^-`CCUvq1RXE&-@|c!w<8kD^Z`o6q?+SEyf`^w+E}b6D~g)iRhW>B_nq} zQ3dy>eBO#>|Iz&r+ts+tPUP#n2M`2Zb6lo3WShL`7W8^K0A(R~+^A2m3~#+xvx6v> zL5Y&M5j-S-O4rAS=PyrZE5;(FYEWGFnYfwVJ-ITYf{!IbTKYF%$1ue+e-k>k&W0bX zOZFIu{d6RWazu}$B6YFWwmUvEIgLw`c}fflB#(jxC7*k0dyb$XzgmZR7Cz>p?&}-c zD)vq2o9MYW9#juL()f_|jOJS4!ZYe&+|V{X3BZN-?w1hs!J`%4B}LALCjSG{sIR{9zjw2xJ%+{)QQ`}) z#%(-}{%2AHyArVosC-~@eea{}&tr8Uk?sG}ZTo#|Ap06CBoyuhzn}8Am)qN*lnDQ2 zd8Q+L^~#Nv+8(M!zRi-yGm)!}W0lG6N2x8wS!I9MI{J4n6gv9SxU9ZruPvS(b3Mp7 zKZ3G2SUh+dnSjR+6p-t&S|7jo+D+cJ^>n5`xn1-NdElI!|x`pb^yq!tB#52H7 zqM6ac>jonFFt-=)G`f687GERg7#MVdhYdk&h5_+vM#-j?dw{Utw{!*fs6$%AqkD9i zaJIB{r%HFbAdC#(jxu<<_|k2)$h|zFah^(Lnt~j!>38$WeLUvwIYM97Pwo@pi2ZE= zrhs*HMu1o2%tL*H)8);cdzORJRwZO0j4f_Yx`#ux? z?aO(k-Gbp68j*O2LbQqz+in#6cw^ueTSkT`&Ald`W8SHI8`aHUUB$St=d~J@!Dj{` z#Eu=V#dD}LP*&FvU2FAbphCYt3^Muhs&Vs7CLnS!K9Uw|rhP0wd& zV`n={{YEMbeVDeT#_ZRNrOiFljpn?@RFj=)y_k>@tJCd^Oot(Q0{JByCIF6=?b;DV zltxZFyPG5Bz;%D!rGZ}K{TwOQ!zfqH+{5ulpPU6+!sQ?IjcHu`A%5Y;-+R6Fs=3^+ z0cGW~s-2i{%WNgq;Mti0-it-qldDffoOZ0i2RKqHEAAM6cDRRjJ39+&x#`4~(Vym& zxzqe?`nuNT!2b-7K@V0nxwxFjX5~3th%S+`K!lSrYK?Sdeq$6up%c+k}dp2Oc-CX7{+IJ=iF5( zk4-+%kI+u}=1krtWCEBUeRbZu>lSoIw~;}$`Ch+#I9LpMs4PaH;7VO=Z%t7(Ru!s2 zyLHa`e_jB+#KwK?{gFPX#w#!SbUr8dL zVSA@!+P&4LviC)H&ue(v79grqp=1f+mW@5L>!t>+aMA+f@*Y_g)yDHIDZxX$0V7?)$<|A=coKXv zGuV?(;d58Bqa~svZ8GPHa1XWhQGhbNS`aQZWDF^xO63>*H$c4MzWAiAs?9dzjSZ<+ zI4i$kq~YIysgK*+0N?8m7FUp&@N%MRC0Q8i^&$Tao^Grpj+!9!k6TMRsUKgdzJh5{ zja&kc5H&hjN$7PI2EI&amAdgHy5A$h=!Ay)oLH7Ctg5c)J4A;Yzz2PMW`3_sWr7?c z{X2;=KX4$TK!P4}(GqN*VKZ$eddzm+`!AwF(a4x+ca2d}DaNxx;m@&i`soOEi#G+4 z8kqXko_=!QCr29J=m2}%l`dtfnX!f*b9C(2@Mn}zr&S3i(tnN64b*r_5vKcH&^X4B29-4${7}BH`#?MZNGipoczG^TZGw4 zI!b@Fg1M`a!dXdy3}{V4p0zaDs%*hvBVcjA^Oxv+E7h2yHAC@BTM2v|VL{&gF*W`G zqK%~KCs@i8+vAjxMz^daAPdRIHZftFlUnsu7ZEyzLM&Wc$!+{y*~!8F`x$r>%X z))*(cEBZ`_AH%{_HXPEBuD5D`R?CC6o(h7Ktnp$fr5HRsFaAuf2|8q<^+yCFI|SAi zYIgHaEhtSzK^eG|g*~mJNR&B^JJ{rrv0ZXKACj(i86vXU)W&~wK5a6;zNk3{cI3-W zX~;EsVZ^p*rx~F^;3G|^PZiw$KmA; zGL^Iu-ZX=B^QNGz`tHQ{e7Iq01XVAl(tp7hbkFGTadzgV>Hqio<-IW(zPI*UY?_Hx z?@kUZAVb*CUMh%49+t-Lt-@hJe$q|kreCuP0pbMG;|g?lo|V&Gaf}7|c%?tz=Z+{* zFgh`q4HIr(D!NhcvEHh|Wp^j$biW(}XK{g))2IHK95rnUTKw`9biCR3Ku{p^z9?=X z%C$0b??)$QSxT@ulTiWbHClBFP9m*joQNH9V~}l=wrT{B&V!7As+}8pX14hlqW5(E z<9ZtVwd~_5J`(QqIufA7rvg4;C;%F1$74o%eIWzuEA{abj#fGJNX}E5vJu*$5{MnQ zv#O#kksWl)m6R~t9Rp?}ox2TjefTSuxZK&gS$r#1DsGQx>OpGbJvc2YIhKBrKWEf+ zmUUw}KwVS&z6$J-T!CFLN3%Q1Qsdr)!xNrgi8ADZS?NT}6BzY3Hj)?hyU8`ynp8WC z5fWi{)q$BmC?I-gS1H!$g0%H;&ob>`kENNHL(+`chofS~OMZU?8pl8|;g{8!Hoj(F z=qx$5ONGrz0maD``0j}J3a4zxevk@tmHf*$)!E&&!z37H6^Z4*C1szrtz@A;mxC6= z`Yh=w!yA;y7oLj|OYu?6JJp!85^H{T?$qNbAI_6{ME6qHiEX4j#yo5mT~GefMV5=- z+D6{<8!K~%E>~OH>1+D@AJkj%C)uJNGo_YbwrAja$qMG>q=xdU7F>Y|*S(teQsrQ&0a;levR z6%#wz)4>`4SA^c#8^IS}gj-3WoWVTf!q zz!QHhd(-r^@Yngs;tnN~vSPWp!PNpNL)DBU?Bh3>-X&MvR-~HbJpRQz)vC}I;ayI9 ztbPBRx3KC@xu(gccEd#ZNbYJ)xI=rce_-H7&|eUY1rB5xT9@fJYnlW*WIVs5hCMp5i9xS#Mu+xkhA!YyRqgXd>=G z>5!;YJ9#l%_y{w)F(R9l9Oce$DNbz2c$e__{ z*%wr-b(;v_@+NFRxIcU&JHo-*>}IO6X$5I*&xT){ouyvRJKZ{XJa^%uPYPu7-&+sz zst1B-lBw3mx>{+@|I*(mF0`nkEsqSo>8xJl5njVNeA~Im>Fe_}1Mv0(fz4zrJ*friI znlDqkBT?h|u3D7=)F*X?4TPfxR)nho;u@)O&l}=>2%h%Y!IB;#fJ~&q0zYRgO7HyR z2y~g9RLP+%;0+StBW|#5FKn1X6*-C~Ur_t`z>r}z*-m9%Q>n5i@_6@&AWR;$%6lj42!n0Gk-Y6b2;h+(}>T48N`UJIif7`#vKek}sTN z7t+uoq3N;Pb_z0b^9o#U_bwYdE@AzrG&m#d5n!wbNh(U~UwIe4wqlK_Gtc}rlA9)# zivLzBKE`4kgWQ5e6iVPPHQnBVx@rHPsDNVV@Gu{bg!NsP;_RM~U!t4!k-4ncM;MYw zo=hdS$jQ&e?2y!|2XVcaY33epH%bTU0>^F0OJgbA4xW|WF1mx&kNg4aD{hqa)r)xW zM22HbxJ$G;PV76LXWgiV#yvs`1)$?+yhUQ_rQ$T0f3+-g;5Y` z>j@P|-pXC;gH3OqXwBynahQOrgIw>qgLWc7W&w33!1R95M3FX2Yrs;q7T>#YOGbRca` zv=P^mhIaiE4a-8jeXvG5Y4$HywLeT6ng;O_#D@0?M6;JWNnqpxGmCC0~t#Q>{= zjT5gEZ?LOJT%19Rew8>AIK)+;r~EXO3=aF9pxg9BIOBKIGG1Eg(ZvI4OKPWC_ejhO zfnK+h2u+2Hd>1xU@>DSFzbk2;k(sEL2>;>YaW)Fy-M*yxn%Uu-M&at^gfa=Y!Ge`| zsmmY?etZ;U#VN%{gmtICYVtoBJA|mJG|sI+#~#(0-_R&IcBdvX5#e%~mOr|9QP3S;dk_E0 zscxA-;in@BbhTJL3ddjtc85oKtmdi|YNria_O{KHgN^wWzmHTZWPC`2N{dtCZ|y7(stvi^u;S zet>ef9;^qW58I?K^y9!V4yfE`xK<@6L_@OjM!|07ean0ygY%v~9m*oNM6}*1uvb=G zCk=J=-R|8%%6NODEj)C0_3%OvgmW0vWg0FV5Qk5Dwp*B|QGC;GA237Mx-01*pLVEH zQBX44SjtHgfxYCKswF>oAGI!EcNvHZb_Fy=~Zwdu4LbmyY&L3tzbY6 z1)^n(VB7`FeP31H{#~$H?cSo83~2(zApHy9N6iFNkmi#?8gyeltKt&v5riw+fJtnV z@>N#f^=1$$ju3(mR{^cz{efrt``hwEF-Wu?^=twR$$Yv9$cBUVowT~$IPxP8=AjXR zIw~T0-%TZ7&7S^p&5|a$bKK?(M>%9&%oav~z7g!*LesnC$cZ?Fu}P9V>l!sCsM*EI z#+5zmq(kD53}fkkc-9GP@6ig;_Rx?S10?U>_g61@sYzDAwZh_G<-+bNqwjTYeP-6e zeP(*Nf8l6a415H@LV8peUvW0U=i8QwB5r)f=t(rY6*k~O9}2qv^bfGUb$Z7>5JltH zaQcsyt!(^)Tl>$YBuf%_N0~pUY>%oVCQvWlU1t8;87dc_}? zKZ6*(qSLL2F8we>@7V{!iqJrTu+7Lmo11XGM80|a#bNj#wYb{Aw)L(04Kc=M;?2k2 zPjqp}r+R--ct`Z!fA-CmG#F|bnjVY1Uyf}CL`yAAY4roaL3Ih$pue|c71Vm1Cm;8|*&ovMi1%6EdUPY-{)VCr*-bh%^R0XHxau$1V>=$o`cWJaVUzi`Owk$m6&F$3m zcpKy7V|$(=&7`R7hR+xT_pZ#Q0WwCDmU+$u@czmBWcOxdd*0q`-l!FaSf%5x7nXHb zIRndi0rAa~CY2TW_*2hOB(!~x|4JqKhZS@l!}Q2Q2LAvq7=gIaaWP5=Lz@eqLE+zsDa0d6AbZ&c)A65-96ZtrtwGN6fxrUC{QfmjJbdjPV|druy+{C z*;go&rrWu~AH#!c&4B2`!+ zp9}!5VAmgEK);=9-g4BA8+aA!5eF8{Eqsf!`Ot#+IQ=GzuHl+0W=A_<9B*%WK4mRF z$9k5MyEiGGKn{b_CsawPv>SZuFpE$5G^u)Ewht|cm;xsU5PZ+w^IRl=zujwtofL3m zGVp*Yq4&;L%{m_im*6Ki1<%__jtu2krb(OvUDHzBoegp6;3ASO!Y*Kh^D~oXf<``K zgcT4L0XHDc;Ma_XxTllXdM~QqeC=8wxj4d*x--M4#x*Y=xFqw`KRe4q-Naic(q%YR z0JC67fZ}m?{4CaUh}!QB;F!&&wXJ2S2DrbGj&G9sYsDAM)094K8fNwAY<*$&9@?T6 zr9;oA4@ZqH_`p&0DV(&Yv&c>|vWC|vUv=Yj71Xv=koDNSh%WOv+0i*g7d8t|q1->p zD+4CK^6vJ+!Z4GVA?(cSOGl`%6u=$07Ce#Tm1H4^BwZ<5+iR)2w@?B&z{LcT+aFEylaJUzoOv3ozyJ7NZmcc?Joo0ITZ2!MF~9PfZs zeY1Su5^qz?p`7zE5w-7$6m?pk+U?i5tMicITfxsbuqy$tY~)l?)~}zRr(CH{vSWGW z0);{Epf;fECArQ6dx;lMFsBnmqrp^DP$G?}dbRS`21L7@90bNJNfUb9rE&_GZIdeE z8TgFswf9eMR4c%;7uwsey}H^Gjr`?fSs4kg(jXv3BnHZ2n9rMgj2JWbd6d=RTJ48m z#5*romKDvbmMcnNlyqbUvoirjEAMH?e7ea%{9X$%@^Hb7#hbf};uT>JN=UxODq{(x zGpee|nU#_7L@uP=Xm-$2+d%6tSy(o9;9YK<(458)9f+9V61+!=%`x!mF@_3{-Vw{l z8js2>BxOXuYg(3TF7;<*)BbYboeG{onl1~Ud`bl%KzUiK_#W;$p$jerUo$uv64hb$ zDD8um6ip3bNZ0yen}Lq3i$4&#O|;sgo7lqKyx;lJzSBb=O==|%$w5{FH^VZ%fu-7( zOpsk)S5|UI&FI;(&h(c0A*ZI;kF7IzWpc6$Oiuk5qy+%%Fe;JVtNe3kUV7w%_CI&#`GFyhz;fqv7R6Vrf=oMfb1I4oFUP_ciiT3wOYt>TL^$j=nAWy zhwU<2d;vMU3#k3)ntS)!MS|f`2W~W10|2+1JlIGgZqd}v$zN{LW=y}S zleMol>Y$>-YM!B)xq6E5mkKinqVC@lg(g zN=bqB7=}>in96z1B!5v)%|5HAbUjGj*a*m27bum888H^<4<*H=E;EE}9U431ju$dA z-um#$Jo9ktW;gT?lSk-!j51)t{!r+YzR$i6YZIgYN!y)%o8CW2mQFc9YURCFb zo5{CD6uR#PInI#{C@8GR$gK$S&kXe#-P*7*CWJn}72bJWC!!3-*i9*}eQV{@f0Ju><* zkRyBw!d3JY!4HB^P&v$4njU}^i^gt>{d=#Pog7j?ig`yP@f?RA0KG;hT1vtG)mn;e z9igMug5p~D?z35U6t{Kej0;B_I-%#u1Fcm|!U1zbAvsQ1uDHDe_HzDmbASbGDVz}4 zQR*y<8S0$@Kd?Z*lT-nWUR-TNfKWqx#<`(%2^)dx& zg&eapf1*|SW@$R%dpt=$g$r{6b_8m3oT+@JKIZy*!)Ky*{q_GQyGU5?b2Zi;JY=({ zIwOL=I##y0lQq^d6(0S6Q8u$i&Q<-I%^J1RUT+oCH~TiR?-Wk*-mtH?@p7wxJwiV) z?X9$_P*C!df-74=3YG4TQ=S4sjZ=L}6?U?cWWnF91@O_1j!d4kLpcE%NIB9e>fvg) z@U6600r;9s`L1$G8JO1x+G` zZ%QQB?HKv2fJ?fSU?T@m{^>4(`^Rjl`MwpIA=iJ;>&^p*Wy!9GQe3L6%!zJ@-c6y1 zagq471@iGiZlqZ-D>C-TOMl2NX;MO2(;Mo0`o~efVxu^^JClhB9OW6KfU#JxWJ?yd z+&}}QiwOj+qkR@4FRUh>nkhMx_d!n#sb;%0{C;KAo=k zM+jT$G`W0-*t@@;OjXM9qk1Goks#1yt`$G+M!|euog>`(qd*)Q>@&IZCi4Q{OwuMA z(EilP_7OglcXV59?fg+cyCPRpt9)?F#(n8pr&b_ANksS8VUpV~!UQU#s9zMoXlp@W z>nDF@=%1&tLgr%2_;~P1y!eqhF#+Qc)w=7%gm$ksEeUo^nD70JjjETF%x9GsCU_^U zp)EMSjGuXW?}f0;JK-WPtmNiVE&8jY&RsZ1y!iQ-cYiONY!`u2KA^`_1#}4mnGIrh z&5L!ashgcr)}sz!T1(&YcAL*zfS0Yuv6_8eL;@pwzns<3S znM7lG>+C*yW|Z}6H`kvyGaUM*DL5DAI-!8UOg_NEP6-kVE@_VPE+?nTtJ)~%9%B)E2xqBy3^@jvj0=JiZ;6rOlXaN7|YiZ1@5+oVxi9Z-Iin86Yky<*CU!8dM1Mcp!zzE5EIH}UJv^FcDf89`4{ z{><=PU95fdfO6#Sc@#<1?!rISLks>GP_gqV`7u(YsuXkudN<8|?J#!oVEakET`mLC z_M5TxQf6VV{GYJ7fQ{n0B`uy2B?8}ehvvOMTs>sL zjDdGmb{SvaRTGk~6Dv*GqmoETT3qq4UZyaV2}94#F$n8CdTcXX@NsY+850riRK66e z?(oth<|(?MY6FQk9ID(wm^$;BkI!9~ONZTD~ zJ;n1bx6*9(Mv%6SG<4bNaeeuP*a!BTg49VM;ro=TK`)@iT4%t;_RD@XV#bODs@~V| z&q8N6oihhzh4Xm5QB$qt_v8`e-UUQ>nRQ6kjCd;~dL*u>W@4 zw{G9V4pK#+>TpS}DIYb0R|A=^FOH^BZ^#<<^MK+9^6n-Afoq43kI9>CWh#T%Sec9t)*t$*i z4Czy0aSmU}WsRxo&f{H-z^6P;G+4YF+U&6ZFr+U<`RVGJ#iEyV461@I*qU^Og+Vfw zV_-tw37Hr1$DIi?0H>G%iu(Ew@*hFvkE?zQYj{~WH80?$p6%ip}_(x8c@0A$6__#(X_{MKCWvTt*=7 z{?6yFY5p3|mC`~RUTKMtL^ODR6m(yF0BHQ=q$w|@gKx=chD>o?6^y6`$N@{dmr1A%Lxe$l4WmbeL`XWrDb-DAi zOY8vpf7$y6e=FKH>`^AA^9`h;wocsIL(WO@tBP3E*1sRw1P^$NeOl!rNBW6Wy*; zjF_(^BdJ_1p>1Hy>xb$mxh@O>ENZ$U9+_tL}R z=^Fi+Wfdr2zVmA*>WLpEBf^xX>v&57{P|#I=kS$=9YjfiK+2LwC*k%Zk=vx2l4QIq z!SEsVpT=BZDif|-lnHYKnI4&(U4bDxR)AREED{h&;236I)T6MxNGRfDk0Z}OB%%$SW94DGl zTc;0$$^&Z2N>YP$x{6b|>Er372U!q^-}_Js)mYCzvKXniP-xj--1?K%vzkLl_y=>% zInn#_KGxC&&Oe!;$A_E6bc(_m1n#t!Ry<92+VIYI$RlY|eO2%d`_AfHT?Fx{<>bCC zl5Lb7J!*ZSX?#p*Tu|TG*052_SQPZ^tX~oPG`E2? zrqujLcpnSun6`m~{h2eE6*An-qT0>&-xkt@lK#gs^88y9J>+I6Tda79l*a3Y7Cl_4 zNo#Ta`(~M0ZI3QCqr-b%KYvi+ZWseqGa ziB{6$*}3dlay7c>1{+C$8|~z*rp)u#zAuR`?ydu+7kRz|uhgGVBzHme$OybL8M!-y zmnHD-bWUT%(xCY^!uT%@ZHj9Rhur}%ON?JZuZdiNHNbxLkn8nVozoEZ9pl#D8I(eT zZ~uP$C}BBiBVCS~HL?06TFpQ7!`hKC;l_Beq|Cp6B-^~BOV+{le>dW@M{?J}n?KeA}Zh7NvxeDA9k@dEDBAi?l|eK82D8 zuo5Q0--!K!YGrl{4N&B)Z$Q_Set~>%myWd%jZ$< z*W8HI!ubKT$M_O9*%ihWV3m4)dO#(n6lA0xA9j>?#J`r z6vrCf-{nxcZcaMoj=d<@@MJqliCOV^+`Gi$Do#t*nV`voTF3FcZqx)ht9kTJ3Eaot zsTznz-pY`=PUmRFn7*?q#iG4p5@xd2$CMT{EVo!j`c5mk z`saYp0~FSLf%wxIi)4#MwlMvjOYz`0oZGw3U}XD|{)1BW@l||&uX}w&s5fDpPh5hQ zp&d9K6Mp1C-@?NErH31tBGe&+Z!g9pQH9kes-dc?;na7}8R|=@s<#qV**+qlzVL+VfWqO_k75h=z!Sg+LHH{myEwZupW2wI&9G{)*kp8eBzP%@2uO6!-| z8^pCS)}ab818VoOSpv;%X43d?Cua-( zbYZI-oYfF+@;!GPwfpzb+ZD>@s8p-2!6DT!e)2@l%d8)nFI{hPQ3|pl!@&+7C+9T0 zu*6K6M1rF#LVGV={8L#CHZlWBXy8TZD^esn9v~DCF95C|rN{ zRm=a2O{uUVJub;7SKhR7&Nv;9iJs@(;b)g$qRXFD@9f9FGMoV49vb5arO*X$DPJX} zNPKYO{E8(cl+j$BPZY%$LY;J7E)r+?%h4)G<-cQhNwu0VD^_1U)Zm48J>+ZJB0LYn z8-x(5M2|efRiQ8jmix(0a};pb-Q6iey!5|)8Zmt6%gxWrjY6xbs#|#0 zaQdPxn=`o79*+GoDDT=d+bAvTL0d!y!*-MabAD;EN1kBUDqW@v4NFOwIzbgln^PCHuu^?u)lo(4d?AOfaq<{DmX!k1od4B$YeI#qj*tI|EL|8 zM~O1a{v`zzp5}h<+e-!m0LZ;-#}=r;jorc`lv1mXYV|O7yh#Hn-7cj$hAi^0+0YP3 zFHD;yg1veAt-k5!|4P0HalD*7@{7U%`>3t7kC;7{Gx45-tpCanO!UyVB=`b@Ti$C` zl*DM0&J&LoOUG5959u_y{k6(oy%oOj@}%oC49UNtAl(Zcht2zeV?0zj4SB%KhLYOL zLlnA6l^<11I(pq0Nqfo0O2%2{@Q%KC;#MYUSQ-ma?%fSwvL%JyP!r+HCjFo9pUF}X z(P^m0J()4!1H4(>D1X*PkTp`68JfF))}Ec|`E^;a74OWxC%yM~vE6A?;ksL;^~||; zl!%Y;e!|&BcBTdjA539c-TgL{hb>JvUR*e_*+`;jJ~$d$c^t>HRF&LsxVOXzZCCl} z%}7dXnojyc1D77PciGqJ)HibJg}`I;?9xP;^j6kzvDI}r5DOwlOc511iIjFxziwvg z?ZS6KR0UDMo|7YrY_ERwB-wL+ySJ`=_8afZ_blO-2!Ab`i2b0J>rS>;6M3&lYpaR1 zv2p|cROSg$aEaHz-|Y4bT?JPS>UV3-oTv)=ZKE?i&+nnBQ!t>%?EUUOG=?Iro^ zeoPBV`yaOD8+Vah9_-y83|D!nu<<6B^_ByiF!|gkGNv_FSU{JZ?1m_fAe7H0n{x_Yn$2F$Z_&?gHJPv4p@=)^Lx8 zy`t5KB?Gz65Uf(OGt?AfiXkRJi_Jrad>S!7T^3{_-?v|9EUCnd#ZXgQ?a0{P+u-w< zxfD~gC-H(<16Gl6j#Y5$f#OL39*fo_UP^enL_-*`hw4B*MoC6VVIzN5DK`nf!I$Yc zlm(KgJ=zJ*QIV9B^l$AarhGDjP_={l;O?UpPtt!Yg+GB(9|(xVH;6r7jlar^Vi1Cd zP?xOz7ruS_jO0cHfE}X)eDo&xhX+2KBcamL&=LrQ&;PF&y3BLp{AM~~|0v8_G3-8~ z98X*>%hzPX%&j{J=3t>Eg&kF8-5w&E9+oXJW6~xog%DmJ3;63jL=Q1;S!ndrv#wiW zdEOPO*_zO}Bha3DD3f`%DKE+?^^GYST^e2D{MF0@?0V=o444@-w6>lEARXYU!8<0T zsP26futof@BdlvgL5EO!ILG=9)4xN^CME*kOo)%EupP~OPDuVI!gK4BJd@hB|FEIt zN*Kvq4sKEwr)Qw4-&=)|3gIV#5cNF0)Q5kL;HNyxNtMTAgEarX|NfseV%`h&)E)OQ zEUfrea~Merx|h{p7eV`PMlc;vpM7VaamkgYPeAuI+`LA6aT-zL3j=5FLS`6&+4Y+jzkQP!<{!O~MZtt9WN<=^PD9Z36 z7yo_^ekQ!t=NiLxIs*jY&VGt{+zpT77j5(sX*#fsVI$XAAOH4J9cy&PV`z zk2wAn58agmSQf)GsIr6U7TjM8fi`O15M+nB>HS%+9^&=}N(g<766U9>hv9t4dL{V&hmeY5kk>(*N~?OW zu`?Ar2~zMy?y@vZW%~bzskaJ<`i;7Uhc2Zd$a`53@Gs>Y z@9!3RXX(hA>^_XY(MPVP8>%nH_5p&nrz3h8U`F6gEl{DLA_^uPUjHW9-6s0Ozj)@3 z_`s5-;5mIUOZL=J9_ycNLXEjBs8R;X!wgtyAn^dsP0bgy+-S?lxZ|ZRDSE?mc z1!oJ`o6nFVE64;m?Z~>lElu4iO@m1-`0#HKoBPOXKzyM-H2LiCf-hQLp-CymZfSxo zKjOie2Na^z2>~|$*l%?(;W)_ta2N2xezRgy#Vq8XO^nv@`pb^SjV8rdZV4dZ9>?ZV=NLHW zGjwTFsb{hiBAAfI(=$>pl-v_ zKGk@1kb2c^{`T@ANnuXd9BGkX;>uetkPn zt7vT%ybe&cFGk&f_%|G#maayx$6ZOO@+nJlNcvIC{t_@4m-GA#)N74t=-7GyIMJvu6^-N7?KeCO&ao!OENXtCvt7&L0jv+8zMU zMaN?`?3PW5LqUL@z&q9LgM7N^%JvhPxddR2B0BhFRcO)0-Ar?lYhyO9a7G>dS5J}j zUBQf;!@-h#M-Pq;wo-J7&{|W;GuT|GeqVY`qUN`sMV9EpOKh!)tt#&Rrn`y6d*y!@ z+S(EPh^S9OOvH=M-PD~${>Zex!=)}Z!b_JYwZ=Atex{ERAj%a&|4MZ&5t_N!$_9MQ zNU2o;m{pJsLVd5fUINP3rIMEhUC+sTR1Xwag|9VR{igOvCdp^j9ick;CQ?H`vM&ICeF(qKMx1`D|zgL!9pMlTH&K4TeR%I{v!{ zDwfhVY=So52qQE%g}DCokBzj64+5f77Re0zr_VT+e(pO(bhJRKO+!Rtw9;qVrX-2P z33*dPd;PBP1m={e_My0PuAwE}UZdi7N+dGvlFT~T67eVLea>UQ&eKUO!l-$aV7@0O z;Eezxd=Eq>fuV>UY7urEY{?;%aPSG(EVu6jfpM}SuoylG*QWzrkuV2Ua3Oq*oC<=2 zChS{sQ0-vR3f-ea-KLJdKX3hj%fTsnZHh4+8>tUl8Vh)ok$LlHRLyS=Lubm^($Y%z zx5wS(W2}e{==YW9Q5J=YcXsl*d8mFG#bHkHB+Z|y0|wtwNvyL$j|Otcuo36`;Uwc` zW8a+}cd^9VbkW~_9*LnTS#lCbej1w%f%>T2(qhAqVuP};@X|&@bWcd-%$e-Y-c@il zjx65dOF`fNWbc57dGp~9Drodx1ANl7$UVjLT9%w#DE7fmQ{-;2$Mx^l`=IGuLJUr2 zbr%F}^M}P^he#om8R!IxAFkk~+&4F47soT0ZO4vU#hXwrmh$%@M`aq@>EUPH>s1_h zebc4C*Qowjxk<2D&awo^4n0c!hbboF;MRGBKY=uM;uU;df+{#r3Ql>yjoD!Ml+Jxh zmOqX$AFjL_;*&dBPOEVDLZU@sdNF(|oUvIQw@J#*aAt`Nr1{l9U(Mmje_#3Jm}bCX;IZ#BX!*(Zmv>+0W^P zJoiWCm6i?_fhV7A@e`;%k=4D;ocx_O8v)v9bJ@O+b9>liden-o^?RV_s!r)mK+b^( z&W;;``fwG=BTKp})His&dGQAfHTwzh8g2_;To@VjuRVwB^7I5|j}QdfI8x*`tv58z zj24-%*~XNLh>npPl3>&%cs6HQ`hwqv!Vqy+h0u3`RKgWP zrwx#UVdRgsSO8UQeD-(GeUQm#dQKSF4xsZksOZkhlT-K%ZV!s>(r{`&v+w%vVwZTO zzS@KXrVkPuRp7sSX7X{mMj?f)7!6laoGPXv`K8G}%ZhvB0Yn^_h->%TZecod1e3Q+ zf|s3Ewa?6Nh10%K;Bm^&qbiv{wf{fDk|Z}eR7tTL5?}UJtqo=OZ-*` zJT!(bRkLQG?DXDk{kqZ=QNG-7h8G{Vt{=?;P@=xMU7y-|i2bN#j1$OVoTgJIfeJ$+ z-_?EEks!w5Zb^CPtZRiLSHADbJk8j1?I}men*N`*{_Fs?5$DCE0RMqy!zI(L#aJC; zn~5Hs7D<*ifKXP)B9AZ0$CxBt zXtiSaFc;ItWTwY@}uEKnw<7gn(u6TC^i3Gwpy!IXO36VT80bLisFf0JN>RF73 z9*?3T39|X1Q0(nueH#w_@vBk!i1x@q_LmFamecB|2j&}axl{umIi}yw)hBaRAU%*e zU-A*aQyRP~w6*~`$5g8I_Dxm!t%MGaZIBUH4VN`#)=!o<0A zW8dfoYRGr5J_>1yDWy{1OpCR2L)wha)82@#xha9GP>3g3pHr5`Z(cs+!LD>T_4`kK z4+yfadKPC{LZ~`z)Lh=(!ir`ye9^cX)H}*5;a;AwkBqH&w0=TOFQaIM!*f*4!^z36 z3aITAd3{M=ZJZ)C%+?~xt*qwSzh&Dq)sU#%Qk+?!l@+l;fnLCIU=M;Q0f=}Ztq#0V-3KZ~pmOy}QUR`#``uWWyMVq)WK}Ubk6)A)BbM}A(r;;L&-pZf6sS@Q2wVt@h@91Ld&dD z4cz;N=kj_Ma;R%nOe$9bw#Vp3zr^$%VY{!*DAzTI3Wg~dYs>uczG$;f8v($9Fo^Wu3w+(@nPiR*RPpgAIgpv~mZ~x%v|Dp4iSgx~?{Ca{GZx1m*oc{HJ|9=i$LRex zkNK{;BI{p~Ax!(GRCuml6Jv!5S6XrYHFeI2R4x8l|Db_AEGZ>)ZQDw8-LTq{#dOAl zL0u8=RKae`6|xFQqf_;0|6?2LI4*=OxAH@T`5m-2k-p`)Po7+zirp;~oL=Gv=jjT5 zo*;SEjM2|b^TaWGqnifOPraZGk+@Afix;Zku3J)%*)=dU$v*n?rl$C|w;PJDvH#+qx!p{7$kH1~W4EWNJN|I1VCacsc=ZeZ z+W@!DbsuW1s5l`)7U}rvT8Ww=D_(Wsmaqe;h_a>Y$~BIL=X(-=K)^bu`HI@t+$uqL zpyPVD37q=s0@;UHTYjKv4BFPck)mPyEU=;@+6{Dpe1-1zTG>8e2@>NBNdoEo2QyFZ@PwP7LRi60tbS&472SPj+&=$ z#g3`2Fxk@I@xF-v{_Z(2q((-iuX>q>RP5ZVVCO%32Ho({YGRu>x$U3aJ69OdNeA?Z zfelsM&9Xqe^^N^B-GPd)MVA2yg_0!il;~lc9JCA<3^${4SiuvUl0m6*pOW^4ekS}I z1VZj5cT+wEzD&-yM~~X;U6QlBb=4qX`F}6(1SThz+3HV>Avv`Zvu{)P#;%esbvw1H z-;5qAh1bvJU2^(@i&=ca+~%dC>U-?m;i4>r7f-Qn4>YF@0kr-f}F_cbVC@GF?*BH+I}V9%{wEeF_6ePBU1f^LJk>x6$*JnI-!z1`)?sY z_RUJTJOd-tU`BOa%ctaZgIK=0Ga2j1$+wjFyKjP%-FYPQ$XS7J5jePujN%5qN0oax z$25TI+1p>HeTT2T`#vj&!an6gCcgt01y=_gb^6a!>kS2}|2gU!KkZrfyj&l)Z2xbQfl_;C4vgIUak;?YdZ`l_uI8Na{G@@NR|eAt8hUI!Wy(Q~ z14fdG!JXv2C^;6+CrIv2v6x9yCP+A()P6LL`e*LbfIzX!4;fVB2o zf{;9<8-fs$Ca_dJl*jolv|Nv$#bME+uoE2jMcr-cPH{#K?V}N^{cqVk^$*`Cp1q-! z^MO)}aBULob}$v-Ox9?L*&3`m@$~c!#=y-E-tO2!-@IPL8>! z6R3KEuIN;U4go<_*uejmFMD^^Y`3P>Wz7rC%iHjb$ao}E}Jmv7>j6NMfX;3tc2z>kC-yi%W41#saPO( zirKY2ITS%>KEFDhbvyrKt;UR1t>_oVLzNPOdsY2$#y|;h)MJkrLs7lC8#yFN*elcf z1lnGz!j^HmA&ep{`Ru4ii`NqDH1a?+cqG*Ien#+Lk;F3x&^81I+%Dn%fVW9CjXO8# zj(@46sY3bhhcam53#~<%+jq1&q_4ciqAZywLT?ufy~MmvKzP;4J0!zAqxTe>IKD2InLM3dH z%1gG1=IK#A>_e8Tud2hpw+gI)%Ps9Rfj$AoTJTbg@^GO~W%o!U-8NBPtc&pq&?s|) zUDy^QFj*C&zP%s1W1f%RxYxVpnZ&AtUN(}{f!i$VnfMe8G;!NcS_RSmfGm!ttRM#6 z$vb5HG3%T5L2>L5qJ;@t%0UdRFWA--@HA^=0FIZ%c+MwRFo?Ud2K0}DM`fJ<{YNm? zQMOSTR+|SchRB6S^)X`h2YcWYbJL+8=2i?-oLu%x4n2D>1Ee{u3)}E46eBnq8mt;( zd9U`5qkT!K1mNO7@aY5diP6q-(dRQa>IbTuuE&Zh7SQpLtFRWadtL>@_rfmk6EXJ& z9>>V_ezjmb)*)+DB3%PdeJ}96k`-|$gE=l@Hp2v|pRlZ)IH8NVUzRdgW@+O#ovLOa z6pillg}vhnL{DY|My?d;RC;R|iGF{CktUK6oDG~BYA_=;pWF5b5&o~#Yq5tQ-3N`{5xaA1(82b9utg0O5yP|XcKGg_eJw0XqV4W+q@-=5b zp%IlN`4F{{L+~`E;IC2I)F0*L6nAkV0z8ABY*jqpBf$2DoD0aEZ;8~H$7vNdj=T^2 z>PzUKrra4;FpUYP1Z7M`W&Xrim9x)pS8)8E4sNZg{#h8%)_}4mL2~MKF9txFE8?cI`mn6$eQ&R6NaW0k1 z_*QqBtQXJL{A1sYcKOAFXiIe46MRS@3UM-!i!8d;Z1R}qdhz6&5$nyc0VX=f8^R|O zZ}tCrUKtLPeY1sKPG&zmkowyQzzdWPfN$`y{=4wT-Bqu4FyN-0}9z0%bTc|c{S>C zdby|@B?TMafQy7=wsW6M`#MH-*ynweQ3WWPR^_^T3uaxZY8jlL12ZmM6Tk6zvbNuL zkxeX_^$Vu)f0B9D#l{X*v9K90ke=IGXIB>q22A?Y&TZ-Pm4WH_Y4mqjpmKb#HkI35 zvE?z&(7rVFht@YSvho6HTbVHmJ)0BwCh$h`il|Nm&uL8>vLDPYz#=rpyO`+cDG!k3 z<*Y0_6sEUYFtBG}d>7*H<9O&4)>%`@E=%VY7YrZSB?Sv&qc%nf&&CoeeAu{OoUf-W zjY*Y%fZF!iLK;_-uo{=3_}aTc7*Cy~FcU1tD%X8-|IEz<{aFA4J)FS*(~xW+zjuSN#*d%Ek=I+)2)3i&Ywf(nh8Cp&+`eOb$@O2EWn%1M1*>q1&SPyQ!oEwjj zbO}Cz&fT3M0HHDx>_BhgThALtoL?&ZVoBWrh5~bJCyh6SjSh7+x(EDv9EG}b$FFx8 zZw3n3>sSQxH3O1!5TCSU+8;o^YHwv}Jp`RMfYs_>T1HF*<6;f~16D;) zlfTovTPptenkXk=E|2xf9i14L4;)q0w44|q6ADc<_op0Y^8aI$Adwd1cmnKbd-U1m zzPCnq9uO=Qd*c3EChgx-wM!ZJ^>-ap6sNWbCzh7uq}hGvp?t;J>n)Yir_oF}rD zob`XI^!DY3|L8~j9QkrS z@hyHUe`MduMFzQo`|-g-zb)e<@zp)P^XL9%)JI0%b=o6ZJUDFA z=Yt?!M7x0E)2#&T>Eg0)(JcN$3lf!ChJr{Qb*x40&6A(gQh(PAFsi046^#6RuSE^T z?WlItR;8%8a>s0C%+s&zNl5=ja~x|A^j_?m?3$kNk!fDrjBgTTfIags^M73Z88~^# zK|HpQaltV{5ftA-{aSD(Yu%X z)UWz6CAaclfO4<|-mGZok(OWN3IkMA1G*_pkN)X9T4DrdWRMc(KCIKCe&+jT!5o*- z0vzqb_=XMZwj1EM*Z(iaUFS_#j_;w&B(eXar$}rFHsOVu_Q2EJkCV>UL3v)6u` zR73)dJ4Vb@{&CBCMFl8$D`O&57X&N12gr?_%sQ_D(P<`;{II6WoopUU0+wL8mYHe0 z;-#m-uN3T_Izt|j+YKsT)_0qDaIJhr82KnUuPu)_itEl|l(q~dZ|yaeCfIIhUR^2~ zr&lwTB03rXH}C&JM|~NtGe405eDRuDKg)C0=8aEV3p zRiUl4$l=azCyzD585ce%c&ud<75YJIHG^Do5h!(%eqcuOlhp-6eI{S{KzxOR;Vsf! z^+BR7^u<33|DM%FAKrt10c-T$o7}SK`Fas88|UuqpVTpKl?_X*E5* zFR|YAqMu zPvRKmrNdKwAM7?Ed3p@`1bOG?ETUNDG3Sh4;F}NLADHhuwXLVZm&-A@`O0N0#j;v` zs+mRoMqQ*^T>oAANar_Xi07SE@q?iV`G+`J^|4V7FjN~H@I?Expq}M*?2AHea(7~r z7Nu9{-BKl=hXG3N1agH8Ponv68N#AvF9V*Ze$9mf*Qj~=&&Te7Mc~OJy1HE?M$hf_ zwgPjgITdXa+(;~?o*9?gOG?|Wbp8lay!<0c_rB{;*?2ob(aT`L{(rGb)7gEzpl3OD zp@tf|)q$sBjT8U8 zdYqEqQ=EJY(KeTihz!vVfBwEo5-Sh-fOqw38~<4^-$!KvyT8=t6d=V_q&52}->11B zXk=(c2+N%s&ialE4n#t{FZ|AanwElT?9aIS^FFxBDt%|^%om%rNAgWJbmvn4I3XUu zmlrFl2?d-?^RH(FCPFfprhI{u#Jm22H7IGAb) zapL16d#})^`g#cO*6hmG{$q$Xr^~qmO{jf*k?!r z92BBr6gRJ;BXUZei?t%ME_z#SQ1>oKxdE@m8jOiPuL4ClxnJZ+oFkKu1_qdu&7G($999E( zLhE|2A~~78rvat>B?_f#hBO87jyuNt25PG8e&5#6BXa6jt4IP0;M2FEhICiAPPbbH zsh`&CM%mJloQl8;a%mGsdJzudWTyN;63HjwJI(77-g~He3j$p-l!Fo|Z_fT=*?`>` zucaMppx57muTAZR3I?iv5?$_i7dFz>=%o3o(CJxE4L6u(LPK5&1dBWI)PE>quKyr@ zB0N&Wjd94{)=W|DBA2X09FMe!|2^D$-s%HT#l(*S43A8|mxTHwf)C6CRY^AFh^~Sg z-f>+Z0iyQ0kp$C2KyR`|G0AkAHeNH0Vc(S8%wp>-htg8 zbXLBOnv{#=naB5Ccx_BfJ@UbL)BDiO>` zx*TA60%OB_1^FdO74=EB_TQWhx5Wk;Rl{hEuM;niwhk%nPz;$RA(WtVqKKHwepVI2 zC+P?RRFCVYACulaN`i0~BO7_1O}Kls$x{;9Yp&vWsLBL2HjyKCp#5nxPrir!=ok6r zJ_IhhVG618z?K(Ge`R?oZM`>3#f%kOjElTUmICWx)LIfsV4L`kb zvCOEBTrB+@w39zsPk2+uyieKX6LBPeej(=Yt?1de8icjIAptv2B_9J(v% zG*&(-ZH_eTbN&avxX7}S6;oLez(#6Lvcwa~KDzMg_c zukb>6da*Y?gc92k(kj(YA2Rm%0xm^T#yg%LjiY37yr~v&D=Hp{kC2|m1HwUZuZ@Zu z&R?6%XaTr4IQ4d&tg3-9U7n-*AP8EiFm5UBGo4NN71TuMT}zEwCOc9(e=_iV?&kNh z$%}fi!90@nf_sOB%@fw@Ls<&b(^*R|#K8kARAF97;lEqa5e{4Kfgf1ro0sf+^MbEc zPPiYUeosbKg#~>ZCXeN&@7zT!M=Muy;EueGQzVXlPvCNZVLjgyMxnA!Ni#FO$p54R z2tp9^KOLfHbGOdC#a$zb_%a^DcYO3rI$D z?f@e7)9n%|esswv{=kyk?z1-pHuGq+CPQ}TVzUd0+A*Mx+AE+c(ZENQ-_hq#@0;wtBpv zhwkdXOEK5&!!Qla6ng_bx%|7lscX4`{2nXJO-5#H0I_M2baaOF6}aT1C?hG9mT$do z5h2g#{R$=m4h`oVd0TuS%`(LD7oV1hGqtwfCF<*5;?BO-&iH1GF?JtK@ zd+WvRcg+_)&f&rWq_=qxbVpF^T>gi;-39D;qOJy|q^9H^uUD{YVdQBFe6|lU5c(z6 z>?8~m!kGywMNQM)oY#wnsPCsKaamRf9j;`SmoU8fl%q6?Zuvw#G#109qO4NoMRSaHKbwopYSO1u9qor!m8* zKS&G`x}P_jsKTv3;AB3edR9a+#NkC}R_%f8HCdO&IJh{c!#%oVE~C?sSH3K_4-t4G zx;eB}Kqd?mjtf8Y77XMi-+Nu)8NLQ^Q?4Y9A}Dp=HMW)8Yi6Q827SQ|{_l3U&*yO6 zS`E|&kjMub@oV}i%vnnoj@oVq z*rQqV`=IrB>KR$_AQP)6Mm`?v?#~u}iXC0rF&}i&TVg0)=aWYT#i_r=gt#-+{s2)Xamn@nmhoXP=1->kLM$TZj)o_eb+!2j&{ZhNyat#o+sdEAU}mK z4&@7e3vjRVY9LG5wd0~a#fnvK4gN)B98?Rc>@#3#@~enCZjT`w{AQ0`6Yx0c=;4(@ zpP_(z8x;tpBT#JBK#+11wOxAqJ|k_$Bwr0=E8LgYKpaA#sHOyCH!MlEoCN_WD%bx44+|jwR=a=<8J#&tJE&G#T-WFFZux`!^AV+WQ`6WH$v}p^#Y#?Q5T=rx1DHp4* zJihFaLD!N-r*cG_q-#;6tFfbx$FXYZt)W3 z^DBBwhDNemjXQhKxcS+u!2+Y%Pnpp&Y%K5Gu3ul{v*crv^YS~k%LkLI%ks{HJR5YA zUk$Q*|Cym0kMwvH%+Yt08!C4p#HM;9}$2TT2mZL5M4YQEfPl*^RaM)6}Whvf)z%Z_e zD+^@D=&Ve^gN*USPRvw`hd&zJX#ssXtkg5dnS6Z%b5iL|(j!+}$n5P*207`c#8m!o zeTdWt=GU%e(QZ3Dl|LZZ`{cveS35fFDbK{Z)JUi>c&KO+9( zV4z#hV_$GId+KL-zYf4(E3H9T%s7K!hZs5aY`b42PX#1h4B%>%rbOT^dW&R)LlyYg zI!@~nPifA4qf`7z5xXBnFR|^X5Ht!~du;$cJwCdrgLy&J@m}Tz{&Z*SHUDC-Xe~~} zkd`w+2}dqls>mkkLh9QVuq^LK4m&Rg4kDl?<4`gQ%Uhs;iE@1R{07rRTPe*>OHEX- z9Us=BRnd>IOMuT5n(tj*X7aK^BJKuQ1#7BJmwOX9{rL>Sd2JY$Sn8OD0pm4^f5Z!a(<6;+uT$@Gm~v>ksqiB#Smv(M1+&R_VWr1R=H4kce-MTxwdCzr4Pu2qF37Yz5u!XiiPXy9Tr#u z4_uEk+H`L_>405pF*i+6sV2RFP0j7jdxGM<(&Tab`#lKFB(`Wm?>}umi^D@XUA4kf z^RZoOzOU+)VW#p(Lbq4bilEyG9IJj_uAQ4mIWs+s_oG(<$Z!18-SqaI1S13yyxsV7 zWy)H6saHN4C=7Y`ahfpAeKarHgz;1w6?7*eZa-$Im3RD~qFY}3(@Pe`ySK%9ouS>W z{WSG1zUXHpt-Jp#wz2JRqov< zHA@UgLh?qt6<9W$nJ5Sd@=72hyxbT)?Rjw=))WrQZrg~Hr4$04tIb)|4$a>(tcVWM z+{q!CSJ&l>0ZBs`>!VoXD^QjvPn85dMuoar<4eB~z55MRW)w z^Xv+}&B;zHF~r>>u#n22J555XEkak|c)z03+NWs7vSn4HX2fnk;?v~LG)haH1|Oxx zG$%Tj#Op|O4z~~><@cKO4SqCS|NdLfKydgUKKyPMjU8`?B2-;*Z8*%u0T+8zr9IV% z`y`3QzY%XEp4dm6#B)^JpCA!rF~J z#13Y4eEg~Sc;Cu1kLhOe*G3cO7~nWC^M@XW4BxY>R)a{50oz_XEDpy z|Fkt-MS^PUf75Rue5P-7(pz!RXbrV%c)i;_0bTpoQ#MUbaSuYqG3wk=Co(rbjoi=bMLY9|9x<{@h0mW@&7>cp@H0;z* zZL8tb&te0)-WqsB0-U_W_XRSQ>t5#L&~m2>FsP#aYXoj(#vdyUoiM0x zReUL8UoQ7FD7QP{XUUu2$!%aS>PO3%7`&-wrmo;UwbkTnQB42aIq9H?ncrt{OBz(- z_21~Q23$1L4F&q-uAam5JZ^vs{hg|$-kJTAAnP61yG~srw>r)jVn-dDsyCVL6O#94 zq)}*h+uwKWqJs)zw8Ju4-`?i@WsZ%r2`-$IAqFE$9$>9=E8aC53qAgAg#~s2?*nJ@ z_xfM79niFQxRCmj`azO|V&FJMMQ4y9{5ic)D;^gNQ~7*@lYs0;$67 z8u83OiK{y@EXUiTcPP?YvFF=l{C3H8+)YYaIej^2ck1(SXkPgKT5_iQ447?vI`N~7 zbtyis)2TlKl+uCep{#B%(Cq?{$Zr@{?W)%S$3c*@RacrXPqCRif-<;p9H9#&`tGr2 zfvde>Vqy?p1}dR~p~|(^m$;jgo;RwKpfoyf*LGhb{}AT!H-;GX`=Z%7d`zGzZ50=l zrbNC#AmiquO*Pi*asfF{FCSrbJ{Sts;*zkr4R;O~;3o}Dcye#-Rn0x4`*u=R>xktM zC3l)eFvm#cfw84b-CqhZj>W^7M#=ev6+>t>hZ%i+aR+y{nd15#Si-;{rQX7+;`qV ziJI<}GZmldqC`m*sy%0Y$;PU!8MymT&EFTNTbKI+Xszn~jpb)?LajBFEwe6r zYot#$xelIjl;-R#mx!w2Nq9olS0Nf8wbfVUHZa7y^?vt{BF(QT>1v9nM@vg1c{uGY z3Pv;O@@!&fwLMzv5~{joAJ2?fEkBZw`X8K%AK z&pns^Owxd%9N!L1Va&HwM^y*L>}DOt=p?&AoIK$O$^89B1@ml6NjTypm1BhA z7|w7ZK%n2>eqF1f0gbomiP5T7>n<6*yVnX|SZW%7FT&&e>`(xz9}s;*apx zThLfl%vlCEU9X+5<9t|#`pVYqg*Fgcl4?h8jL{JFkNXFYA+VF2dBOUS)B<)lGfW+$jGgjgcFrrRjtb&bx7z+>VdbZE zU%<|-s;s@K^U<(GV4p1jbYsZ>a_|IP;54>e*pAiR=9$b-S$^Xy3|Qd+q^5Zj_qK6F z9`lZ*b5|g@dL13ELZirVZ!@KB{iDwuLdNGco)||O{#m;=v;1rIC&)gVXpT<%xqux;{$7*n+bHfP!`J>FCh~IORoIeX!oD{j5#X9TPf{}z-@ZryDgx(WdsCiZt7Wv$6wBKliAK; zDHGSUI3?zUnLusLT*5KYy!+i=`-_%*o6vDY`6iPS7F^On-$u3ot8P$|+=nZAg$VQ* zbmSm>9i_HgpYL~o$j7;O8D1btpqV6gMAJ$`pS6ClHt>;^h(TapDasa)iGYmqFLX!qsN2PqI&4h1aj01POO090ndlA8wXR}L$3xo)x#J3=8poC&vs?*OJ8&m z_^Q~pN#h+EO~__)JX*E=u;_3T*LVr^2AH_XpH&@?ypViDUW>I%R`Q3w2$tpROUUHW z_AB$#tcU|v#T;7{g#P2`Rldy1Qx^A{!xUM!L)WHR}(abGCs}rcBJ7`7(Vch z*s`p~`cG~Ty-9^j&iIS0oH&apBIwhwt z8%_zuMH70C?CXCW<4CXGY81z@eT5u)rVD`He;2%YTw-NUe7?J3U*SGz2xJLVD5@+cB(;}9aF}k(At+A@>A-A<`AL2e*K_xjfACI z4Zp_q7KE(Myz;G3<6_ndlFpUbV*>SFpB!{k~x80X%3*U^5?6l-~g2VtpJn{1n&{GK_4}0JaU(_;*nkE*BG9Wo0=2x%o zhFQ=578N&%J&a#W*Zh*}Umxuio{611IKUYB_D>IeYuW@VTkpQSVULM+m4rHoUfKcx z+N9~;ytIW&?$yUxUCG~IuO|l4`n80JC1bW@fX^E+{*7{t94nK0E`YM=T1`pBh}^~x zcSrlA^de5*zMA%sjx4;GYf--@#I}Xa{qy|bmii@tZO}Rc3yr|+vNb>C7l3gf$1WZ$ zAF+GV|G2x!JG5M($$31+L#xfICOk0o;=%XYN0J3+f@@@Ne5Ol#=nN#@+yZ{}Y{?BX6}KfN@tuv~yGsEP>%2UZ!~+_YX!ipt}i&14n3ts)%_gYqdP zjsm2QXwVK`##*e-_aw`Yz+aK?8shMb@7SH##bOil*bwhk5Nk8#gXRB5o7ei})O(n-lF)a&35EDW0OBu%u|f`X|3Vlsl3R1kM)@1 zs?~7Kk@_$Hsw$8cAkk0PIHSh3jzuxv)Tp{K;h>CP`!s@n%Vh#XFS_<{n4jE_g4WRI zj)f|AuJiVp0<9ZfhMJ z`RQ!ti${{bQ(J|3-(z1=gc@?UhcLx=%J+dghWzlkTE;}PbsOK+ zJEqiR)M#2$N-gxdJx^2%0Rf)sy>h-zV9 zekZKZSLNvwgprFapNC;9xpg%)pK%W|!32W7ZHVbN#=!a@ba>u9edT)}j0N6mzp91- zkI6xwt^1BZL`l8a&zTzHd>uOYY#uMVxr%4J1hcu_X`)hoMh*rBK&;Dc(MMDniA5jN z*n^z6kIUtMT1`sQ!xHZj`KbEDL)8;;sz|CLWO9=8qt$l-W^{!% z9$nUW+S}6u_RZ~ihNSf_gI1eW0DHIGo2^ihkMI2!hLiqH>yvP; z7Uq4Y`@{hpFzSVWfRVhvWBQRSSy>SUfodjRu^Ejc&=jp#J^8T%3>FS+clmD{s4W9r zIRD%wf&M?X-ZCtzfa@9_x|9wPq&o!!8M?b$T2fj-Kym;IuONHXDPOh0M%O8h{P=vcrV|jP6U1h1`F

TQeIS) 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 z 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 tJWj@@a_?v}|IJhSj~|uHLiT+f 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

tC!G&WD-N?p#b2V16Em7>CjOLVDDVE-8AC0bHv& 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 Yh;7R~q-{L-4(g{Qr!HG5^D_MZ0M0o1(f|Me diff --git a/app/src/main/res/drawable/brainwallet_logotype_white.png b/app/src/main/res/drawable/brainwallet_logotype_white.png deleted file mode 100644 index cc0f84e77b043182278ace91d0664e5c2ac2c0a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126886 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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90f8dedd..cd3b7691 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] kotlin = "2.0.0" -agp = "8.5.0" +agp = "8.5.1" androidx-core-ktx = "1.12.0" androidx-appcompat = "1.6.1" androidx-legacy-support = "1.0.0" @@ -25,7 +25,7 @@ google-play-feature-delivery = "2.1.0" google-play-review = "2.0.1" squareup-okhttp-bom = "4.12.0" squareup-retrofit = "2.11.0" -firebase-bom = "32.7.1" +firebase-bom = "34.0.0" jakewarthon-timber = "4.7.1" eclipse-jetty = "9.2.19.v20160908" junit = "4.13.2" @@ -87,7 +87,7 @@ firebase-analytics = { module = "com.google.firebase:firebase-analytics" } firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" } firebase-crashlytics-ndk = { module = "com.google.firebase:firebase-crashlytics-ndk" } #firebase-iid = { module = "com.google.firebase:firebase-iid" } -firebase-config = { module = "com.google.firebase:firebase-config-ktx" } +firebase-config = { module = "com.google.firebase:firebase-config" } firebase-messaging = { module = "com.google.firebase:firebase-messaging" } firebase-inappmessaging = { module = "com.google.firebase:firebase-inappmessaging-display" } jakewarthon-timber = { module = "com.jakewharton.timber:timber", version.ref = "jakewarthon-timber" } From 4efd95fcdbc454e0b05d9f34eaa18afb907e249c Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Tue, 19 Aug 2025 03:19:43 +0700 Subject: [PATCH 51/65] feat(#195): adopt koin annotation for dependency injection (#120) --- app/build.gradle.kts | 4 + .../java/com/brainwallet/BrainwalletApp.kt | 18 ++- .../FirebaseRemoteConfigRepository.kt | 63 +++++++++ .../data/repository/LtcRepository.kt | 83 ----------- .../data/repository/LtcRepositoryImpl.kt | 93 ++++++++++++ .../repository/SelectedPeersRepository.kt | 84 ----------- .../repository/SelectedPeersRepositoryImpl.kt | 89 ++++++++++++ .../data/repository/SettingRepository.kt | 80 ----------- .../data/repository/SettingRepositoryImpl.kt | 91 ++++++++++++ .../data/source/LocalCacheSource.kt | 2 +- .../data/source/RemoteConfigSource.kt | 59 -------- .../main/java/com/brainwallet/di/AppModule.kt | 95 +++++++++++++ .../main/java/com/brainwallet/di/Module.kt | 132 ------------------ .../navigation/LegacyNavigation.kt | 3 +- .../BrainwalletMessagingService.kt | 8 +- .../notification/NotificationHandler.kt | 125 ++++++++++------- .../brainwallet/ui/BrainwalletViewModel.kt | 2 +- .../buylitecoin/BuyLitecoinViewModel.kt | 3 +- .../ui/screens/home/SettingsViewModel.kt | 3 +- .../home/receive/ReceiveDialogViewModel.kt | 2 + .../screens/inputwords/InputWordsViewModel.kt | 2 + .../ui/screens/ready/ReadyViewModel.kt | 4 +- .../setpasscode/SetPasscodeViewModel.kt | 2 + .../ui/screens/unlock/UnLockViewModel.kt | 3 +- .../ui/screens/welcome/WelcomeViewModel.kt | 2 + .../YourSeedProveItViewModel.kt | 2 + .../yourseedwords/YourSeedWordsViewModel.kt | 2 + .../util/cryptography/KeyStoreKeyGenerator.kt | 61 -------- .../util/cryptography/KeyStoreManager.kt | 4 +- .../impl/KeyStoreKeyGeneratorImpl.kt | 65 +++++++++ .../worker/CurrencyUpdateWorker.kt | 2 + .../brainwallet/BrainwalletScreengrabApp.kt | 4 +- .../FirebaseRemoteConfigRepositoryTest.kt} | 9 +- .../notification/NotificationHandlerTest.kt | 49 +++++-- build.gradle.kts | 1 + gradle/libs.versions.toml | 9 +- 36 files changed, 670 insertions(+), 590 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepository.kt create mode 100644 app/src/main/java/com/brainwallet/data/repository/LtcRepositoryImpl.kt create mode 100644 app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepositoryImpl.kt create mode 100644 app/src/main/java/com/brainwallet/data/repository/SettingRepositoryImpl.kt create mode 100644 app/src/main/java/com/brainwallet/di/AppModule.kt delete mode 100644 app/src/main/java/com/brainwallet/di/Module.kt create mode 100644 app/src/main/java/com/brainwallet/util/cryptography/impl/KeyStoreKeyGeneratorImpl.kt rename app/src/test/java/com/brainwallet/data/{source/RemoteConfigSourceFirebaseImplTest.kt => repository/FirebaseRemoteConfigRepositoryTest.kt} (91%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 66c1b24e..b42bd6bd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,6 +8,7 @@ plugins { alias(libs.plugins.jetbrains.kotlin.serialization) alias(libs.plugins.google.services) alias(libs.plugins.firebase.crashlytics) + alias(libs.plugins.ksp) } val localProperties = gradleLocalProperties(rootDir, providers) @@ -215,6 +216,9 @@ dependencies { implementation (libs.airbnb.lottie.compose) implementation(platform(libs.koin.bom)) implementation(libs.bundles.koin) + implementation(platform(libs.koin.annotation.bom)) + implementation(libs.koin.annotation) + ksp(libs.koin.annotation.compiler) implementation(platform(libs.squareup.okhttp.bom)) implementation(libs.bundles.squareup.okhttp) diff --git a/app/src/main/java/com/brainwallet/BrainwalletApp.kt b/app/src/main/java/com/brainwallet/BrainwalletApp.kt index 8a55523b..9143a90f 100644 --- a/app/src/main/java/com/brainwallet/BrainwalletApp.kt +++ b/app/src/main/java/com/brainwallet/BrainwalletApp.kt @@ -6,28 +6,33 @@ import android.app.Application import android.content.Context import android.content.res.Resources import com.appsflyer.AppsFlyerLib -import com.brainwallet.di.appModule -import com.brainwallet.di.dataModule -import com.brainwallet.di.viewModelModule -import com.brainwallet.notification.setupNotificationChannels +import com.brainwallet.data.source.RemoteConfigSource +import com.brainwallet.di.AppModule +import com.brainwallet.notification.NotificationHandler import com.brainwallet.presenter.activities.util.BRActivity import com.brainwallet.presenter.entities.ServiceItems import com.brainwallet.tools.listeners.SyncReceiver import com.brainwallet.tools.manager.AnalyticsManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.tools.util.Utils +import org.koin.android.ext.android.inject import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.GlobalContext.startKoin import org.koin.core.logger.Level +import org.koin.ksp.generated.module import timber.log.Timber import timber.log.Timber.DebugTree import java.util.Timer import java.util.TimerTask import java.util.concurrent.atomic.AtomicInteger +import kotlin.concurrent.thread open class BrainwalletApp : Application() { + private val remoteConfigSource: RemoteConfigSource by inject() + private val notificationHandler: NotificationHandler by inject() + override fun onCreate() { super.onCreate() @@ -35,7 +40,7 @@ open class BrainwalletApp : Application() { /** DEV: Top placement requirement. **/ val enableCrashlytics = !Utils.isEmulatorOrDebug(this) - setupNotificationChannels(this) + notificationHandler.setupNotificationChannels(this) AnalyticsManager.init(this) AnalyticsManager.logCustomEvent(BRConstants._20191105_AL) @@ -72,8 +77,9 @@ open class BrainwalletApp : Application() { startKoin { androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.ERROR) androidContext(this@BrainwalletApp) - modules(dataModule, viewModelModule, appModule) + modules(AppModule.dataModule, AppModule.module) } + thread { remoteConfigSource.initialize() } } // override fun attachBaseContext(base: Context) { diff --git a/app/src/main/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepository.kt b/app/src/main/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepository.kt new file mode 100644 index 00000000..15d7323f --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepository.kt @@ -0,0 +1,63 @@ +package com.brainwallet.data.repository + +import com.brainwallet.BuildConfig +import com.brainwallet.R +import com.brainwallet.data.source.RemoteConfigSource +import com.google.firebase.remoteconfig.ConfigUpdate +import com.google.firebase.remoteconfig.ConfigUpdateListener +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.remoteconfig.FirebaseRemoteConfigException +import com.google.firebase.remoteconfig.remoteConfigSettings +import org.koin.core.annotation.Single +import timber.log.Timber + +@Single(binds = [RemoteConfigSource::class]) +class FirebaseRemoteConfigRepository( + private val remoteConfig: FirebaseRemoteConfig +) : RemoteConfigSource { + + init { + val configSettings = remoteConfigSettings { + minimumFetchIntervalInSeconds = if (BuildConfig.DEBUG) { + 0 // fetch every time in debug mode + } else { + 60 * 180 // fetch every 3 hours in production mode + } + } + remoteConfig.setConfigSettingsAsync(configSettings) + remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) + } + + override fun initialize() { + remoteConfig.fetchAndActivate() + .addOnSuccessListener { Timber.d("timber: RemoteConfig Success fetchAndActivate") } + .addOnFailureListener { + Timber.d( + it, + "timber: RemoteConfig Failure fetchAndActivate" + ) + } + remoteConfig.addOnConfigUpdateListener(object : ConfigUpdateListener { + override fun onUpdate(configUpdate: ConfigUpdate) { + Timber.d("timber: [RemoteConfig] onUpdate ${configUpdate.updatedKeys}") + } + + override fun onError(error: FirebaseRemoteConfigException) { + Timber.d("timber: [RemoteConfig] onError ${error.code} | ${error.message}") + } + + }) + } + + override fun getString(key: String): String { + return remoteConfig.getString(key) + } + + override fun getNumber(key: String): Double { + return remoteConfig.getDouble(key) + } + + override fun getBoolean(key: String): Boolean { + return remoteConfig.getBoolean(key) + } +} diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt index 39542354..b6914b6f 100644 --- a/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt @@ -1,19 +1,9 @@ package com.brainwallet.data.repository -import android.content.Context -import android.content.SharedPreferences -import androidx.core.net.toUri -import com.brainwallet.BuildConfig import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Fee import com.brainwallet.data.model.MoonpayCurrencyLimit -import com.brainwallet.data.source.RemoteApiSource -import com.brainwallet.data.source.fetchWithCache import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse -import com.brainwallet.tools.manager.BRSharedPrefs -import com.brainwallet.tools.manager.FeeManager -import com.brainwallet.tools.sqlite.CurrencyDataSource -import com.brainwallet.tools.util.Utils interface LtcRepository { suspend fun fetchRates(): List @@ -26,79 +16,6 @@ interface LtcRepository { suspend fun fetchMoonpaySignedUrl(params: Map): String - class Impl( - private val context: Context, - private val remoteApiSource: RemoteApiSource, - private val currencyDataSource: CurrencyDataSource, - private val sharedPreferences: SharedPreferences, - ) : LtcRepository { - - //todo: make it offline first here later, currently just using CurrencyDataSource.getAllCurrencies - override suspend fun fetchRates(): List { - return runCatching { - val rates = remoteApiSource.getRates() - - //legacy logic - FeeManager.updateFeePerKb(context) - val selectedISO = BRSharedPrefs.getIsoSymbol(context) - rates.forEachIndexed { index, currencyEntity -> - if (currencyEntity.code.equals(selectedISO, ignoreCase = true)) { - BRSharedPrefs.putIso(context, currencyEntity.code) - BRSharedPrefs.putCurrencyListPosition(context, index - 1) - } - } - - //save to local - currencyDataSource.putCurrencies(rates) - return rates - }.getOrElse { currencyDataSource.getAllCurrencies(true) } - - } - - /** - * for now we just using [Fee.Default] - * will move to [RemoteApiSource.getFeePerKb] after fix the calculation when we do send - * - * maybe need updaete core if we need to use dynamic fee? - */ - override suspend fun fetchFeePerKb(): Fee = Fee.Default //using static fee - - override suspend fun fetchLimits(baseCurrencyCode: String): MoonpayCurrencyLimit { - return sharedPreferences.fetchWithCache( - key = "${PREF_KEY_BUY_LIMITS_PREFIX}${baseCurrencyCode.lowercase()}", - cachedAtKey = "${PREF_KEY_BUY_LIMITS_PREFIX_CACHED_AT}${baseCurrencyCode.lowercase()}", - cacheTimeMs = 5 * 60 * 1000, //5 minutes - fetchData = { - remoteApiSource.getMoonpayCurrencyLimit(baseCurrencyCode) - } - ) - } - - override suspend fun fetchBuyQuote(params: Map): GetMoonpayBuyQuoteResponse = - remoteApiSource.getBuyQuote(params) - - override suspend fun fetchMoonpaySignedUrl(params: Map): String { - val externalTransactionID = Utils.getEncryptedAgentString(context) - val finalParams = params + mapOf( - "defaultCurrencyCode" to "ltc", - "externalTransactionId" to externalTransactionID, - "currencyCode" to "ltc", - "themeId" to "main-v1.0.0", - ) - return remoteApiSource.getMoonpaySignedUrl(finalParams) - .signedUrl.toUri() - .buildUpon() - .apply { - if (BuildConfig.DEBUG) { - authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com - } - } - .build() - .toString() - } - - } - companion object { const val PREF_KEY_NETWORK_FEE_PER_KB = "network_fee_per_kb" const val PREF_KEY_NETWORK_FEE_PER_KB_CACHED_AT = "${PREF_KEY_NETWORK_FEE_PER_KB}_cached_at" diff --git a/app/src/main/java/com/brainwallet/data/repository/LtcRepositoryImpl.kt b/app/src/main/java/com/brainwallet/data/repository/LtcRepositoryImpl.kt new file mode 100644 index 00000000..72730ccc --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/LtcRepositoryImpl.kt @@ -0,0 +1,93 @@ +package com.brainwallet.data.repository + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.net.toUri +import com.brainwallet.BuildConfig +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Fee +import com.brainwallet.data.model.MoonpayCurrencyLimit +import com.brainwallet.data.repository.LtcRepository.Companion.PREF_KEY_BUY_LIMITS_PREFIX +import com.brainwallet.data.repository.LtcRepository.Companion.PREF_KEY_BUY_LIMITS_PREFIX_CACHED_AT +import com.brainwallet.data.source.RemoteApiSource +import com.brainwallet.data.source.fetchWithCache +import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.tools.manager.FeeManager +import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.tools.util.Utils +import org.koin.core.annotation.Single + +@Single(binds = [LtcRepository::class]) +class LtcRepositoryImpl( + private val context: Context, + private val remoteApiSource: RemoteApiSource, + private val currencyDataSource: CurrencyDataSource, + private val sharedPreferences: SharedPreferences, +) : LtcRepository { + + //todo: make it offline first here later, currently just using CurrencyDataSource.getAllCurrencies + override suspend fun fetchRates(): List { + return runCatching { + val rates = remoteApiSource.getRates() + + //legacy logic + FeeManager.updateFeePerKb(context) + val selectedISO = BRSharedPrefs.getIsoSymbol(context) + rates.forEachIndexed { index, currencyEntity -> + if (currencyEntity.code.equals(selectedISO, ignoreCase = true)) { + BRSharedPrefs.putIso(context, currencyEntity.code) + BRSharedPrefs.putCurrencyListPosition(context, index - 1) + } + } + + //save to local + currencyDataSource.putCurrencies(rates) + return rates + }.getOrElse { currencyDataSource.getAllCurrencies(true) } + + } + + /** + * for now we just using [Fee.Default] + * will move to [RemoteApiSource.getFeePerKb] after fix the calculation when we do send + * + * maybe need updaete core if we need to use dynamic fee? + */ + override suspend fun fetchFeePerKb(): Fee = Fee.Default //using static fee + + override suspend fun fetchLimits(baseCurrencyCode: String): MoonpayCurrencyLimit { + return sharedPreferences.fetchWithCache( + key = "${PREF_KEY_BUY_LIMITS_PREFIX}${baseCurrencyCode.lowercase()}", + cachedAtKey = "${PREF_KEY_BUY_LIMITS_PREFIX_CACHED_AT}${baseCurrencyCode.lowercase()}", + cacheTimeMs = 5 * 60 * 1000, //5 minutes + fetchData = { + remoteApiSource.getMoonpayCurrencyLimit(baseCurrencyCode) + } + ) + } + + override suspend fun fetchBuyQuote(params: Map): GetMoonpayBuyQuoteResponse = + remoteApiSource.getBuyQuote(params) + + override suspend fun fetchMoonpaySignedUrl(params: Map): String { + val externalTransactionID = Utils.getEncryptedAgentString(context) + val finalParams = params + mapOf( + "defaultCurrencyCode" to "ltc", + "externalTransactionId" to externalTransactionID, + "currencyCode" to "ltc", + "themeId" to "main-v1.0.0", + ) + return remoteApiSource.getMoonpaySignedUrl(finalParams) + .signedUrl.toUri() + .buildUpon() + .apply { + if (BuildConfig.DEBUG) { + authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com + } + } + .build() + .toString() + } + +} diff --git a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt index 0275d542..2d8513ff 100644 --- a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepository.kt @@ -1,93 +1,9 @@ package com.brainwallet.data.repository -import android.content.SharedPreferences -import androidx.core.content.edit -import com.brainwallet.di.json -import kotlinx.serialization.json.jsonObject -import okhttp3.Call -import okhttp3.Callback -import okhttp3.OkHttpClient -import okhttp3.Response -import okio.IOException -import timber.log.Timber -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine - interface SelectedPeersRepository { suspend fun fetchSelectedPeers(): Set - class Impl( - private val okHttpClient: OkHttpClient, - private val sharedPreferences: SharedPreferences, - ) : SelectedPeersRepository { - - private companion object { - const val PREF_KEY_SELECTED_PEERS = "selected_peers" - const val PREF_KEY_SELECTED_PEERS_CACHED_AT = "${PREF_KEY_SELECTED_PEERS}_cached_at" - } - - override suspend fun fetchSelectedPeers(): Set { - val lastUpdateTime = sharedPreferences.getLong(PREF_KEY_SELECTED_PEERS_CACHED_AT, 0) - val currentTime = System.currentTimeMillis() - val cachedPeers = sharedPreferences.getStringSet(PREF_KEY_SELECTED_PEERS, null) - - // Check if cache exists and is less than 6 hours old - if (!cachedPeers.isNullOrEmpty() && (currentTime - lastUpdateTime) < 6 * 60 * 60 * 1000) { - return cachedPeers - } - - val request = okhttp3.Request.Builder() - .url(LITECOIN_NODES_URL) - .build() - - return suspendCoroutine { continuation -> - okHttpClient.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - continuation.resume(emptySet()) //just return empty if failed or need hardcoded? - } - - override fun onResponse(call: Call, response: Response) { - val jsonString = response.body?.string() - - if (response.isSuccessful.not()) { - continuation.resume(cachedPeers ?: emptySet()) - return - } - - val parsedResult = jsonString?.let { - val jsonElement = json.parseToJsonElement(it) - val dataObject = jsonElement.jsonObject["data"]?.jsonObject - val nodesObject = dataObject?.get("nodes")?.jsonObject - - //filter criteria - val requiredServices = 0x01 or 0x04 // NODE_NETWORK | NODE_BLOOM - - nodesObject?.entries - ?.filter { entry -> - val flags = - entry.value.jsonObject["flags"]?.toString()?.toIntOrNull() - flags != null && (flags and requiredServices) == requiredServices - } - ?.map { it.key.replace(":9333", "") } - ?.toSet().also { Timber.d("Total Selected Peers ${it?.size}") } - ?: emptySet() - - } ?: emptySet() - - sharedPreferences.edit { - putStringSet(PREF_KEY_SELECTED_PEERS, parsedResult) - putLong(PREF_KEY_SELECTED_PEERS_CACHED_AT, currentTime) - } - - continuation.resume(parsedResult) - } - }) - } - } - - } - companion object { const val LITECOIN_NODES_URL = "https://api.blockchair.com/litecoin/nodes" } diff --git a/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepositoryImpl.kt b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepositoryImpl.kt new file mode 100644 index 00000000..454be2d2 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/SelectedPeersRepositoryImpl.kt @@ -0,0 +1,89 @@ +package com.brainwallet.data.repository + +import android.content.SharedPreferences +import androidx.core.content.edit +import com.brainwallet.data.repository.SelectedPeersRepository.Companion.LITECOIN_NODES_URL +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.jsonObject +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Response +import okio.IOException +import org.koin.core.annotation.Single +import timber.log.Timber +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +@Single(binds = [SelectedPeersRepository::class]) +class SelectedPeersRepositoryImpl( + private val okHttpClient: OkHttpClient, + private val sharedPreferences: SharedPreferences, + private val json: Json +) : SelectedPeersRepository { + + private companion object { + const val PREF_KEY_SELECTED_PEERS = "selected_peers" + const val PREF_KEY_SELECTED_PEERS_CACHED_AT = "${PREF_KEY_SELECTED_PEERS}_cached_at" + } + + override suspend fun fetchSelectedPeers(): Set { + val lastUpdateTime = sharedPreferences.getLong(PREF_KEY_SELECTED_PEERS_CACHED_AT, 0) + val currentTime = System.currentTimeMillis() + val cachedPeers = sharedPreferences.getStringSet(PREF_KEY_SELECTED_PEERS, null) + + // Check if cache exists and is less than 6 hours old + if (!cachedPeers.isNullOrEmpty() && (currentTime - lastUpdateTime) < 6 * 60 * 60 * 1000) { + return cachedPeers + } + + val request = okhttp3.Request.Builder() + .url(LITECOIN_NODES_URL) + .build() + + return suspendCoroutine { continuation -> + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + continuation.resume(emptySet()) //just return empty if failed or need hardcoded? + } + + override fun onResponse(call: Call, response: Response) { + val jsonString = response.body?.string() + + if (response.isSuccessful.not()) { + continuation.resume(cachedPeers ?: emptySet()) + return + } + + val parsedResult = jsonString?.let { + val jsonElement = json.parseToJsonElement(it) + val dataObject = jsonElement.jsonObject["data"]?.jsonObject + val nodesObject = dataObject?.get("nodes")?.jsonObject + + //filter criteria + val requiredServices = 0x01 or 0x04 // NODE_NETWORK | NODE_BLOOM + + nodesObject?.entries + ?.filter { entry -> + val flags = + entry.value.jsonObject["flags"]?.toString()?.toIntOrNull() + flags != null && (flags and requiredServices) == requiredServices + } + ?.map { it.key.replace(":9333", "") } + ?.toSet().also { Timber.d("Total Selected Peers ${it?.size}") } + ?: emptySet() + + } ?: emptySet() + + sharedPreferences.edit { + putStringSet(PREF_KEY_SELECTED_PEERS, parsedResult) + putLong(PREF_KEY_SELECTED_PEERS_CACHED_AT, currentTime) + } + + continuation.resume(parsedResult) + } + }) + } + } + +} diff --git a/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt index 3f217918..484b5249 100644 --- a/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt @@ -1,17 +1,8 @@ package com.brainwallet.data.repository -import android.content.SharedPreferences -import androidx.core.content.edit import com.brainwallet.data.model.AppSetting -import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Language -import com.brainwallet.tools.manager.FeeManager -import com.brainwallet.tools.sqlite.CurrencyDataSource import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update interface SettingRepository { @@ -41,77 +32,6 @@ interface SettingRepository { fun getSelectedFeeType(): String - class Impl( - private val sharedPreferences: SharedPreferences, - private val currencyDataSource: CurrencyDataSource - ) : SettingRepository { - - private val _state = MutableStateFlow(load()) - val state: StateFlow = _state.asStateFlow() - - override val settings: Flow - get() = state - - override suspend fun save(setting: AppSetting) { - sharedPreferences.edit { - putBoolean(KEY_IS_DARK_MODE, setting.isDarkMode) - putString(KEY_LANGUAGE_CODE, setting.languageCode) - putString(KEY_FIAT_CURRENCY_CODE, setting.currency.code) - } - _state.update { setting } - } - - override fun getCurrentLanguage(): Language { - return sharedPreferences.getString(KEY_LANGUAGE_CODE, Language.ENGLISH.code) - .let { languageCode -> Language.find(languageCode) } - } - - override fun updateCurrentLanguage(languageCode: String) { - sharedPreferences.edit { putString(KEY_LANGUAGE_CODE, languageCode) } - _state.update { it.copy(languageCode = languageCode) } - } - - override fun isDarkMode(): Boolean { - return sharedPreferences.getBoolean(KEY_IS_DARK_MODE, true) - } - - override fun toggleDarkMode(isDarkMode: Boolean) { - sharedPreferences.edit { - putBoolean(KEY_IS_DARK_MODE, isDarkMode) - } - _state.update { it.copy(isDarkMode = isDarkMode) } - } - - override fun putSelectedFeeType(feeType: String) { - sharedPreferences.edit { - putString(KEY_SELECTED_FEE_TYPE, feeType) - } - } - - override fun getSelectedFeeType(): String = - sharedPreferences.getString(KEY_SELECTED_FEE_TYPE, FeeManager.REGULAR) - ?: FeeManager.REGULAR - - - private fun load(): AppSetting { - return AppSetting( - isDarkMode = sharedPreferences.getBoolean(KEY_IS_DARK_MODE, true), - languageCode = sharedPreferences.getString(KEY_LANGUAGE_CODE, Language.ENGLISH.code) - ?: Language.ENGLISH.code, - currency = sharedPreferences.getString(KEY_FIAT_CURRENCY_CODE, "USD").let { - currencyDataSource.getCurrencyByIso(it) - ?: return@let CurrencyEntity( - "USD", - "US Dollar", - -1f, - "$" - ) - } - - ) - } - } - companion object { const val KEY_IS_DARK_MODE = "is_dark_mode" const val KEY_LANGUAGE_CODE = "language_code" diff --git a/app/src/main/java/com/brainwallet/data/repository/SettingRepositoryImpl.kt b/app/src/main/java/com/brainwallet/data/repository/SettingRepositoryImpl.kt new file mode 100644 index 00000000..fc862d72 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/SettingRepositoryImpl.kt @@ -0,0 +1,91 @@ +package com.brainwallet.data.repository + +import android.content.SharedPreferences +import androidx.core.content.edit +import com.brainwallet.data.model.AppSetting +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.SettingRepository.Companion.KEY_FIAT_CURRENCY_CODE +import com.brainwallet.data.repository.SettingRepository.Companion.KEY_IS_DARK_MODE +import com.brainwallet.data.repository.SettingRepository.Companion.KEY_LANGUAGE_CODE +import com.brainwallet.data.repository.SettingRepository.Companion.KEY_SELECTED_FEE_TYPE +import com.brainwallet.tools.manager.FeeManager +import com.brainwallet.tools.sqlite.CurrencyDataSource +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.koin.core.annotation.Single + +@Single(binds = [SettingRepository::class]) +class SettingRepositoryImpl( + private val sharedPreferences: SharedPreferences, + private val currencyDataSource: CurrencyDataSource +) : SettingRepository { + + private val _state = MutableStateFlow(load()) + val state: StateFlow = _state.asStateFlow() + + override val settings: Flow + get() = state + + override suspend fun save(setting: AppSetting) { + sharedPreferences.edit { + putBoolean(KEY_IS_DARK_MODE, setting.isDarkMode) + putString(KEY_LANGUAGE_CODE, setting.languageCode) + putString(KEY_FIAT_CURRENCY_CODE, setting.currency.code) + } + _state.update { setting } + } + + override fun getCurrentLanguage(): Language { + return sharedPreferences.getString(KEY_LANGUAGE_CODE, Language.ENGLISH.code) + .let { languageCode -> Language.find(languageCode) } + } + + override fun updateCurrentLanguage(languageCode: String) { + sharedPreferences.edit { putString(KEY_LANGUAGE_CODE, languageCode) } + _state.update { it.copy(languageCode = languageCode) } + } + + override fun isDarkMode(): Boolean { + return sharedPreferences.getBoolean(KEY_IS_DARK_MODE, true) + } + + override fun toggleDarkMode(isDarkMode: Boolean) { + sharedPreferences.edit { + putBoolean(KEY_IS_DARK_MODE, isDarkMode) + } + _state.update { it.copy(isDarkMode = isDarkMode) } + } + + override fun putSelectedFeeType(feeType: String) { + sharedPreferences.edit { + putString(KEY_SELECTED_FEE_TYPE, feeType) + } + } + + override fun getSelectedFeeType(): String = + sharedPreferences.getString(KEY_SELECTED_FEE_TYPE, FeeManager.REGULAR) + ?: FeeManager.REGULAR + + + private fun load(): AppSetting { + return AppSetting( + isDarkMode = sharedPreferences.getBoolean(KEY_IS_DARK_MODE, true), + languageCode = sharedPreferences.getString(KEY_LANGUAGE_CODE, Language.ENGLISH.code) + ?: Language.ENGLISH.code, + currency = sharedPreferences.getString(KEY_FIAT_CURRENCY_CODE, "USD").let { + currencyDataSource.getCurrencyByIso(it) + ?: return@let CurrencyEntity( + "USD", + "US Dollar", + -1f, + "$" + ) + } + + ) + } +} diff --git a/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt b/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt index d86d312d..e00a051e 100644 --- a/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt +++ b/app/src/main/java/com/brainwallet/data/source/LocalCacheSource.kt @@ -2,7 +2,7 @@ package com.brainwallet.data.source import android.content.SharedPreferences import androidx.core.content.edit -import com.brainwallet.di.json +import com.brainwallet.di.AppModule.json import kotlinx.serialization.encodeToString /** diff --git a/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt b/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt index dc5c7ff4..d39b04fb 100644 --- a/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt +++ b/app/src/main/java/com/brainwallet/data/source/RemoteConfigSource.kt @@ -1,14 +1,5 @@ package com.brainwallet.data.source -import com.brainwallet.BuildConfig -import com.brainwallet.R -import com.google.firebase.remoteconfig.ConfigUpdate -import com.google.firebase.remoteconfig.ConfigUpdateListener -import com.google.firebase.remoteconfig.FirebaseRemoteConfig -import com.google.firebase.remoteconfig.FirebaseRemoteConfigException -import com.google.firebase.remoteconfig.remoteConfigSettings -import timber.log.Timber - interface RemoteConfigSource { companion object { @@ -20,54 +11,4 @@ interface RemoteConfigSource { fun getString(key: String): String fun getNumber(key: String): Double fun getBoolean(key: String): Boolean - - class FirebaseImpl( - private val remoteConfig: FirebaseRemoteConfig - ) : RemoteConfigSource { - - init { - val configSettings = remoteConfigSettings { - minimumFetchIntervalInSeconds = if (BuildConfig.DEBUG) { - 0 // fetch every time in debug mode - } else { - 60 * 180 // fetch every 3 hours in production mode - } - } - remoteConfig.setConfigSettingsAsync(configSettings) - remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) - } - - override fun initialize() { - remoteConfig.fetchAndActivate() - .addOnSuccessListener { Timber.d("timber: RemoteConfig Success fetchAndActivate") } - .addOnFailureListener { - Timber.d( - it, - "timber: RemoteConfig Failure fetchAndActivate" - ) - } - remoteConfig.addOnConfigUpdateListener(object : ConfigUpdateListener { - override fun onUpdate(configUpdate: ConfigUpdate) { - Timber.d("timber: [RemoteConfig] onUpdate ${configUpdate.updatedKeys}") - } - - override fun onError(error: FirebaseRemoteConfigException) { - Timber.d("timber: [RemoteConfig] onError ${error.code} | ${error.message}") - } - - }) - } - - override fun getString(key: String): String { - return remoteConfig.getString(key) - } - - override fun getNumber(key: String): Double { - return remoteConfig.getDouble(key) - } - - override fun getBoolean(key: String): Boolean { - return remoteConfig.getBoolean(key) - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/di/AppModule.kt b/app/src/main/java/com/brainwallet/di/AppModule.kt new file mode 100644 index 00000000..3c9fd77c --- /dev/null +++ b/app/src/main/java/com/brainwallet/di/AppModule.kt @@ -0,0 +1,95 @@ +package com.brainwallet.di + +import android.content.Context +import android.content.SharedPreferences +import com.brainwallet.BuildConfig +import com.brainwallet.data.source.RemoteApiSource +import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.tools.util.BRConstants +import com.google.firebase.Firebase +import com.google.firebase.remoteconfig.remoteConfig +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.koin.android.ext.koin.androidApplication +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.Module +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.kotlinx.serialization.asConverterFactory +import kotlin.getValue + +@Module +@ComponentScan("com.brainwallet") +object AppModule { + + val json = Json { + ignoreUnknownKeys = true + explicitNulls = false + prettyPrint = true + } + + val dataModule = module { + single { Firebase.remoteConfig } + single { json } + factory { provideOkHttpClient() } + single { provideRetrofit(get(), get(), BRConstants.BW_API_PROD_HOST) } + single { provideApi(get()) } + single { CurrencyDataSource.getInstance(get()) } + single { provideSharedPreferences(context = androidApplication()) } + } + + + private fun provideSharedPreferences( + context: Context, + name: String = "${BuildConfig.APPLICATION_ID}.prefs" + ): SharedPreferences { + return context.getSharedPreferences(name, Context.MODE_PRIVATE) + } + + private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() + .addInterceptor { chain -> + val requestBuilder = chain.request() + .newBuilder() + .addHeader("Accept", "application/json") + .addHeader("Content-Type", "application/json") + .addHeader("X-Litecoin-Testnet", "false") + .addHeader("Accept-Language", "en") + chain.proceed(requestBuilder.build()) + } + .addInterceptor(HttpLoggingInterceptor().apply { + setLevel( + when { + BuildConfig.DEBUG -> HttpLoggingInterceptor.Level.BODY + else -> HttpLoggingInterceptor.Level.NONE + } + ) + }) + .build() + + internal fun provideRetrofit( + json: Json, + okHttpClient: OkHttpClient, + baseUrl: String = BRConstants.BW_API_PROD_HOST, + ): Retrofit = Retrofit.Builder() + .baseUrl(baseUrl) + .client(okHttpClient) + .addConverterFactory( + json.asConverterFactory( + "application/json; charset=UTF8".toMediaType() + ) + ) + .build() + + internal inline fun provideApi(retrofit: Retrofit): T = + retrofit.create(T::class.java) + + inline fun getKoinInstance(): T { + return object : KoinComponent { + val value: T by inject() + }.value + } +} diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt deleted file mode 100644 index d8f47bd3..00000000 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ /dev/null @@ -1,132 +0,0 @@ -package com.brainwallet.di - -import android.content.Context -import android.content.SharedPreferences -import com.brainwallet.BuildConfig -import com.brainwallet.data.repository.LtcRepository -import com.brainwallet.data.repository.SelectedPeersRepository -import com.brainwallet.data.repository.SettingRepository -import com.brainwallet.data.source.RemoteApiSource -import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.tools.sqlite.CurrencyDataSource -import com.brainwallet.tools.util.BRConstants -import com.brainwallet.ui.screens.buylitecoin.BuyLitecoinViewModel -import com.brainwallet.ui.screens.home.SettingsViewModel -import com.brainwallet.ui.screens.home.receive.ReceiveDialogViewModel -import com.brainwallet.ui.screens.inputwords.InputWordsViewModel -import com.brainwallet.ui.screens.ready.ReadyViewModel -import com.brainwallet.ui.screens.setpasscode.SetPasscodeViewModel -import com.brainwallet.ui.screens.unlock.UnLockViewModel -import com.brainwallet.ui.screens.welcome.WelcomeViewModel -import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItViewModel -import com.brainwallet.ui.screens.yourseedwords.YourSeedWordsViewModel -import com.brainwallet.util.cryptography.KeyStoreKeyGenerator -import com.brainwallet.util.cryptography.KeyStoreManager -import com.brainwallet.worker.CurrencyUpdateWorker -import com.google.firebase.Firebase -import com.google.firebase.remoteconfig.remoteConfig -import kotlinx.serialization.json.Json -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import org.koin.android.ext.koin.androidApplication -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject -import org.koin.core.module.dsl.viewModel -import org.koin.core.module.dsl.viewModelOf -import org.koin.dsl.module -import retrofit2.Retrofit -import retrofit2.converter.kotlinx.serialization.asConverterFactory - -//todo module using koin as di framework here - -val json = Json { - ignoreUnknownKeys = true - explicitNulls = false - prettyPrint = true -} - -val dataModule = module { - factory { provideOkHttpClient() } - single { provideRetrofit(get(), BRConstants.BW_API_PROD_HOST) } - - single { provideApi(get()) } - - single { - RemoteConfigSource.FirebaseImpl(Firebase.remoteConfig).also { - it.initialize() - } - } - single { SelectedPeersRepository.Impl(get(), get()) } - single { CurrencyDataSource.getInstance(get()) } - single { provideSharedPreferences(context = androidApplication()) } - single { SettingRepository.Impl(get(), get()) } - single { LtcRepository.Impl(get(), get(), get(), get()) } -} - -val viewModelModule = module { - viewModelOf(::WelcomeViewModel) - viewModelOf(::SettingsViewModel) - viewModel { ReadyViewModel() } - viewModel { InputWordsViewModel() } - viewModel { SetPasscodeViewModel() } - viewModel { UnLockViewModel() } - viewModel { YourSeedProveItViewModel() } - viewModel { YourSeedWordsViewModel() } - viewModel { ReceiveDialogViewModel(get(), get()) } - viewModel { BuyLitecoinViewModel(get(), get()) } -} - -val appModule = module { - single { KeyStoreManager(get(), KeyStoreKeyGenerator.Impl()) } - single { CurrencyUpdateWorker(get()) } -} - -private fun provideSharedPreferences( - context: Context, - name: String = "${BuildConfig.APPLICATION_ID}.prefs" -): SharedPreferences { - return context.getSharedPreferences(name, Context.MODE_PRIVATE) -} - -private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() - .addInterceptor { chain -> - val requestBuilder = chain.request() - .newBuilder() - .addHeader("Accept", "application/json") - .addHeader("Content-Type", "application/json") - .addHeader("X-Litecoin-Testnet", "false") - .addHeader("Accept-Language", "en") - chain.proceed(requestBuilder.build()) - } - .addInterceptor(HttpLoggingInterceptor().apply { - setLevel( - when { - BuildConfig.DEBUG -> HttpLoggingInterceptor.Level.BODY - else -> HttpLoggingInterceptor.Level.NONE - } - ) - }) - .build() - -internal fun provideRetrofit( - okHttpClient: OkHttpClient, - baseUrl: String = BRConstants.BW_API_PROD_HOST -): Retrofit = Retrofit.Builder() - .baseUrl(baseUrl) - .client(okHttpClient) - .addConverterFactory( - json.asConverterFactory( - "application/json; charset=UTF8".toMediaType() - ) - ) - .build() - -internal inline fun provideApi(retrofit: Retrofit): T = - retrofit.create(T::class.java) - -inline fun getKoinInstance(): T { - return object : KoinComponent { - val value: T by inject() - }.value -} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index 26e1b5dc..10503556 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -10,8 +10,7 @@ import androidx.core.net.toUri import com.brainwallet.BuildConfig import com.brainwallet.R import com.brainwallet.data.repository.LtcRepository -import com.brainwallet.data.source.RemoteApiSource -import com.brainwallet.di.getKoinInstance +import com.brainwallet.di.AppModule.getKoinInstance import com.brainwallet.presenter.activities.BreadActivity import com.brainwallet.ui.BrainwalletActivity import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/com/brainwallet/notification/BrainwalletMessagingService.kt b/app/src/main/java/com/brainwallet/notification/BrainwalletMessagingService.kt index d44ba2af..06cd68c7 100644 --- a/app/src/main/java/com/brainwallet/notification/BrainwalletMessagingService.kt +++ b/app/src/main/java/com/brainwallet/notification/BrainwalletMessagingService.kt @@ -1,11 +1,13 @@ package com.brainwallet.notification +import com.brainwallet.di.AppModule import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import timber.log.Timber - -class BrainwalletMessagingService : FirebaseMessagingService() { +class BrainwalletMessagingService( + private val notificationHandler: NotificationHandler = AppModule.getKoinInstance() +) : FirebaseMessagingService() { override fun onCreate() { super.onCreate() @@ -19,7 +21,7 @@ class BrainwalletMessagingService : FirebaseMessagingService() { Timber.d("timber: onMessageReceived data=${message.data}") Timber.d("timber: onMessageReceived notification=${message.notification?.title}, ${message.notification?.body}") - if (NotificationHandler.handleMessageReceived(this, message)) { + if (notificationHandler.handleMessageReceived(this, message)) { return } } diff --git a/app/src/main/java/com/brainwallet/notification/NotificationHandler.kt b/app/src/main/java/com/brainwallet/notification/NotificationHandler.kt index e0284842..893d37a6 100644 --- a/app/src/main/java/com/brainwallet/notification/NotificationHandler.kt +++ b/app/src/main/java/com/brainwallet/notification/NotificationHandler.kt @@ -11,15 +11,34 @@ import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.brainwallet.R +import com.brainwallet.notification.NotificationHandler.Companion.NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE +import com.brainwallet.notification.NotificationHandler.Companion.NOTIFICATION_CHANNEL_ID_GENERAL +import com.brainwallet.notification.NotificationHandler.Companion.NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS import com.brainwallet.presenter.activities.BreadActivity import com.google.firebase.messaging.RemoteMessage -import com.brainwallet.notification.NotificationHandler.NOTIFICATION_CHANNEL_ID_GENERAL -import com.brainwallet.notification.NotificationHandler.NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS -import com.brainwallet.notification.NotificationHandler.NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE +import org.koin.core.annotation.Single -object NotificationHandler { +fun interface NotificationHandlerBuilderProvider { + fun createNotificationBuilder(context: Context, channelId: String): NotificationCompat.Builder +} + +fun interface NotificationNotifier { + fun notify(context: Context, notificationBuilder: NotificationCompat.Builder) +} + +@Single +@SuppressLint("MissingPermission") +class NotificationHandler( + private val notificationBuilderProvider: NotificationHandlerBuilderProvider = + NotificationHandlerBuilderProvider { context, channelId -> + NotificationCompat.Builder(context, channelId) + }, + private val notificationNotifier: NotificationNotifier = NotificationNotifier { context, notificationBuilder -> + NotificationManagerCompat.from(context) + .notify(System.currentTimeMillis().toInt(), notificationBuilder.build()) + } +) { - @SuppressLint("MissingPermission") fun handleMessageReceived(context: Context, remoteMessage: RemoteMessage): Boolean { if (remoteMessage.data.containsKey(KEY_DATA_BRAINWALLET).not()) { return false @@ -36,66 +55,68 @@ object NotificationHandler { val intent = Intent(context, BreadActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } - val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) + val pendingIntent = + PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) - val notification = NotificationCompat.Builder(context, channelId) + val notification = notificationBuilderProvider.createNotificationBuilder(context, channelId) .setContentTitle(title) .setContentText(body) .setSmallIcon(R.drawable.brainwallet_logotype_white) .setContentIntent(pendingIntent) .setAutoCancel(true) - NotificationManagerCompat.from(context) - .notify(System.currentTimeMillis().toInt(), notification.build()) + notificationNotifier.notify(context, notification) return true } - const val KEY_DATA_BRAINWALLET = "brainwallet" + fun setupNotificationChannels(context: Context) { + createNotificationChannel( + context, + NOTIFICATION_CHANNEL_ID_GENERAL, + context.getString(R.string.notification_channel_name_general) + ) + createNotificationChannel( + context, + NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS, + context.getString(R.string.notification_channel_name_litecoin_news) + ) + createNotificationChannel( + context, + NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE, + context.getString(R.string.notification_channel_name_brainwallet_update) + ) + } - const val NOTIFICATION_CHANNEL_ID_GENERAL = "general" - const val NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS = "litecoin-news" - const val NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE = "brainwallet-update" + private fun createNotificationChannel( + context: Context, + channelId: String, + name: String, + ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel( + channelId, + name, + NotificationManager.IMPORTANCE_DEFAULT + ).also { notificationChannel -> + val notificationManager = + context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(notificationChannel) + } + } + } - val defaultNotificationChannels = setOf( - NOTIFICATION_CHANNEL_ID_GENERAL, - NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS, - NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE - ) -} + companion object { + const val KEY_DATA_BRAINWALLET = "brainwallet" -fun setupNotificationChannels(context: Context) { - createNotificationChannel( - context, - NOTIFICATION_CHANNEL_ID_GENERAL, - context.getString(R.string.notification_channel_name_general) - ) - createNotificationChannel( - context, - NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS, - context.getString(R.string.notification_channel_name_litecoin_news) - ) - createNotificationChannel( - context, - NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE, - context.getString(R.string.notification_channel_name_brainwallet_update) - ) -} + const val NOTIFICATION_CHANNEL_ID_GENERAL = "general" + const val NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS = "litecoin-news" + const val NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE = "brainwallet-update" -private fun createNotificationChannel( - context: Context, - channelId: String, - name: String, -) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel( - channelId, - name, - NotificationManager.IMPORTANCE_DEFAULT - ).also { notificationChannel -> - val notificationManager = - context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager - notificationManager.createNotificationChannel(notificationChannel) - } + val defaultNotificationChannels = setOf( + NOTIFICATION_CHANNEL_ID_GENERAL, + NOTIFICATION_CHANNEL_ID_LITECOIN_NEWS, + NOTIFICATION_CHANNEL_ID_BRAINWALLET_UPDATE + ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/ui/BrainwalletViewModel.kt b/app/src/main/java/com/brainwallet/ui/BrainwalletViewModel.kt index 381d9c77..9d526ec7 100644 --- a/app/src/main/java/com/brainwallet/ui/BrainwalletViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/BrainwalletViewModel.kt @@ -2,7 +2,7 @@ package com.brainwallet.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.brainwallet.di.json +import com.brainwallet.di.AppModule.json import com.brainwallet.navigation.UiEffect import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt index 5e6e6316..30975ab3 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinViewModel.kt @@ -1,6 +1,5 @@ package com.brainwallet.ui.screens.buylitecoin -import android.util.Log import androidx.lifecycle.viewModelScope import com.brainwallet.R import com.brainwallet.data.model.AppSetting @@ -21,7 +20,9 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +@KoinViewModel class BuyLitecoinViewModel( private val settingRepository: SettingRepository, private val ltcRepository: LtcRepository diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt index 738af4be..46f5c426 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt @@ -22,8 +22,9 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel - +@KoinViewModel class SettingsViewModel( private val settingRepository: SettingRepository, private val ltcRepository: LtcRepository diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt index f6b2ba8a..e381351c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogViewModel.kt @@ -21,8 +21,10 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel //todo: wip +@KoinViewModel class ReceiveDialogViewModel( private val settingRepository: SettingRepository, private val ltcRepository: LtcRepository, diff --git a/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt index 7da2b003..bfdd4aad 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/inputwords/InputWordsViewModel.kt @@ -16,7 +16,9 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +@KoinViewModel class InputWordsViewModel : BrainwalletViewModel() { private val _state = MutableStateFlow(InputWordsState()) diff --git a/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyViewModel.kt index b66a6889..25fac5c8 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyViewModel.kt @@ -1,7 +1,9 @@ package com.brainwallet.ui.screens.ready import com.brainwallet.ui.BrainwalletViewModel +import org.koin.android.annotation.KoinViewModel +@KoinViewModel class ReadyViewModel : BrainwalletViewModel() { override fun onEvent(event: ReadyEvent) { @@ -9,4 +11,4 @@ class ReadyViewModel : BrainwalletViewModel() { is ReadyEvent.OnLoad -> Unit } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeViewModel.kt index cd867bc7..982dd71d 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeViewModel.kt @@ -11,7 +11,9 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +@KoinViewModel class SetPasscodeViewModel : BrainwalletViewModel() { private val _state = MutableStateFlow(SetPasscodeState()) diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt index 686b562c..30e3274a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt @@ -15,10 +15,11 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel import timber.log.Timber import java.math.BigDecimal - +@KoinViewModel class UnLockViewModel : BrainwalletViewModel() { private val _state = MutableStateFlow(UnLockState()) diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeViewModel.kt index 5045014e..47a282e0 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeViewModel.kt @@ -20,8 +20,10 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel //TODO: revisit this later +@KoinViewModel class WelcomeViewModel( private val settingRepository: SettingRepository ) : BrainwalletViewModel() { diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt index c6406a2d..e54f745f 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt @@ -8,7 +8,9 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +@KoinViewModel class YourSeedProveItViewModel : BrainwalletViewModel() { private val _state = MutableStateFlow(YourSeedProveItState()) diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt index 562b8b97..b85e71c7 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedwords/YourSeedWordsViewModel.kt @@ -5,7 +5,9 @@ import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect import com.brainwallet.ui.BrainwalletViewModel import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +@KoinViewModel class YourSeedWordsViewModel : BrainwalletViewModel() { override fun onEvent(event: YourSeedWordsEvent) { diff --git a/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreKeyGenerator.kt b/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreKeyGenerator.kt index ff4c51ac..c8aa3d92 100644 --- a/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreKeyGenerator.kt +++ b/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreKeyGenerator.kt @@ -1,68 +1,7 @@ package com.brainwallet.util.cryptography - -import android.os.Build -import android.security.keystore.KeyGenParameterSpec -import android.security.keystore.KeyProperties.AUTH_BIOMETRIC_STRONG -import android.security.keystore.KeyProperties.KEY_ALGORITHM_AES -import android.security.keystore.KeyProperties.PURPOSE_DECRYPT -import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT -import com.brainwallet.tools.security.BRKeyStore -import com.brainwallet.tools.security.BRKeyStore.NEW_BLOCK_MODE -import com.brainwallet.tools.security.BRKeyStore.NEW_PADDING -import javax.crypto.KeyGenerator import javax.crypto.SecretKey interface KeyStoreKeyGenerator { fun generateKey(alias: String, isAuthRequired: Boolean, authTimeout: Int?): SecretKey - - class Impl : KeyStoreKeyGenerator { - - private val keyGenerator by lazy { - KeyGenerator.getInstance(KEY_ALGORITHM_AES, BRKeyStore.ANDROID_KEY_STORE) - } - - override fun generateKey( - alias: String, - isAuthRequired: Boolean, - authTimeout: Int? - ): SecretKey { - val keySpecBuilder = getKeyGenSpecBuilder(alias) - if (isAuthRequired) { - setUserAuth(keySpecBuilder, authTimeout) - } - keyGenerator.init(keySpecBuilder.build()) - return keyGenerator.generateKey() - } - - private fun getKeyGenSpecBuilder(alias: String): KeyGenParameterSpec.Builder { - val purposes = PURPOSE_DECRYPT or PURPOSE_ENCRYPT - - return KeyGenParameterSpec.Builder(alias, purposes) - .setBlockModes(NEW_BLOCK_MODE) - .setRandomizedEncryptionRequired(false) - .setEncryptionPaddings(NEW_PADDING) - } - - private fun setUserAuth( - builder: KeyGenParameterSpec.Builder, authTimeout: Int? - ) { - builder.setUserAuthenticationRequired(true) - if (authTimeout != null) { - setAuthTimeout(builder, authTimeout) - } - } - - private fun setAuthTimeout(builder: KeyGenParameterSpec.Builder, authTimeout: Int) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - if (authTimeout != 0) { - builder.setUserAuthenticationParameters(authTimeout, AUTH_BIOMETRIC_STRONG) - } - } else { - val timeout = if (authTimeout == 0) -1 else authTimeout - builder.setUserAuthenticationValidityDurationSeconds(timeout) - } - } - - } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreManager.kt b/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreManager.kt index 6f72268b..1223f2fb 100644 --- a/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreManager.kt +++ b/app/src/main/java/com/brainwallet/util/cryptography/KeyStoreManager.kt @@ -4,14 +4,14 @@ import android.content.Context import android.security.keystore.UserNotAuthenticatedException import com.brainwallet.tools.security.BRKeyStore import com.brainwallet.tools.security.BRKeyStore.AliasObject -import com.brainwallet.tools.security.BRKeyStore.CANARY_ALIAS -import com.brainwallet.tools.security.BRKeyStore.PHRASE_ALIAS import kotlinx.coroutines.runBlocking import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import org.koin.core.annotation.Single import timber.log.Timber import java.security.KeyStore +@Single class KeyStoreManager( private val context: Context, private val keyGenerator: KeyStoreKeyGenerator, diff --git a/app/src/main/java/com/brainwallet/util/cryptography/impl/KeyStoreKeyGeneratorImpl.kt b/app/src/main/java/com/brainwallet/util/cryptography/impl/KeyStoreKeyGeneratorImpl.kt new file mode 100644 index 00000000..8a14c8db --- /dev/null +++ b/app/src/main/java/com/brainwallet/util/cryptography/impl/KeyStoreKeyGeneratorImpl.kt @@ -0,0 +1,65 @@ +package com.brainwallet.util.cryptography.impl + +import android.os.Build +import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyProperties.AUTH_BIOMETRIC_STRONG +import android.security.keystore.KeyProperties.KEY_ALGORITHM_AES +import android.security.keystore.KeyProperties.PURPOSE_DECRYPT +import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT +import com.brainwallet.tools.security.BRKeyStore +import com.brainwallet.tools.security.BRKeyStore.NEW_BLOCK_MODE +import com.brainwallet.tools.security.BRKeyStore.NEW_PADDING +import com.brainwallet.util.cryptography.KeyStoreKeyGenerator +import org.koin.core.annotation.Single +import javax.crypto.KeyGenerator +import javax.crypto.SecretKey + +@Single(binds = [KeyStoreKeyGenerator::class]) +class KeyStoreKeyGeneratorImpl : KeyStoreKeyGenerator { + + private val keyGenerator by lazy { + KeyGenerator.getInstance(KEY_ALGORITHM_AES, BRKeyStore.ANDROID_KEY_STORE) + } + + override fun generateKey( + alias: String, + isAuthRequired: Boolean, + authTimeout: Int? + ): SecretKey { + val keySpecBuilder = getKeyGenSpecBuilder(alias) + if (isAuthRequired) { + setUserAuth(keySpecBuilder, authTimeout) + } + keyGenerator.init(keySpecBuilder.build()) + return keyGenerator.generateKey() + } + + private fun getKeyGenSpecBuilder(alias: String): KeyGenParameterSpec.Builder { + val purposes = PURPOSE_DECRYPT or PURPOSE_ENCRYPT + + return KeyGenParameterSpec.Builder(alias, purposes) + .setBlockModes(NEW_BLOCK_MODE) + .setRandomizedEncryptionRequired(false) + .setEncryptionPaddings(NEW_PADDING) + } + + private fun setUserAuth( + builder: KeyGenParameterSpec.Builder, authTimeout: Int? + ) { + builder.setUserAuthenticationRequired(true) + if (authTimeout != null) { + setAuthTimeout(builder, authTimeout) + } + } + + private fun setAuthTimeout(builder: KeyGenParameterSpec.Builder, authTimeout: Int) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (authTimeout != 0) { + builder.setUserAuthenticationParameters(authTimeout, AUTH_BIOMETRIC_STRONG) + } + } else { + val timeout = if (authTimeout == 0) -1 else authTimeout + builder.setUserAuthenticationValidityDurationSeconds(timeout) + } + } +} diff --git a/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt b/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt index 739da912..d49b325b 100644 --- a/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt +++ b/app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt @@ -8,7 +8,9 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import org.koin.core.annotation.Single +@Single class CurrencyUpdateWorker( private val ltcRepository: LtcRepository ) { diff --git a/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt b/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt index 4dbbde76..6e14bcf3 100644 --- a/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt +++ b/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt @@ -8,6 +8,8 @@ import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.GlobalContext.startKoin import org.koin.core.logger.Level +import com.brainwallet.di.AppModule +import org.koin.ksp.generated.module import timber.log.Timber class BrainwalletScreengrabApp : BrainwalletApp() { @@ -23,7 +25,7 @@ class BrainwalletScreengrabApp : BrainwalletApp() { startKoin { androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.ERROR) androidContext(this@BrainwalletScreengrabApp) - modules(dataModule, viewModelModule, appModule) + modules(AppModule.dataModule, AppModule.module) } } } diff --git a/app/src/test/java/com/brainwallet/data/source/RemoteConfigSourceFirebaseImplTest.kt b/app/src/test/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepositoryTest.kt similarity index 91% rename from app/src/test/java/com/brainwallet/data/source/RemoteConfigSourceFirebaseImplTest.kt rename to app/src/test/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepositoryTest.kt index 7af41f07..6c98db43 100644 --- a/app/src/test/java/com/brainwallet/data/source/RemoteConfigSourceFirebaseImplTest.kt +++ b/app/src/test/java/com/brainwallet/data/repository/FirebaseRemoteConfigRepositoryTest.kt @@ -1,5 +1,6 @@ -package com.brainwallet.data.source +package com.brainwallet.data.repository +import com.brainwallet.data.source.RemoteConfigSource import com.google.android.gms.tasks.Tasks import com.google.firebase.remoteconfig.FirebaseRemoteConfig import io.mockk.every @@ -10,14 +11,14 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -class RemoteConfigSourceFirebaseImplTest { +class FirebaseRemoteConfigRepositoryTest { private val firebaseRemoteConfig: FirebaseRemoteConfig = mockk(relaxed = true) private lateinit var remoteConfigSource: RemoteConfigSource @Before fun setUp() { - remoteConfigSource = RemoteConfigSource.FirebaseImpl(firebaseRemoteConfig) + remoteConfigSource = FirebaseRemoteConfigRepository(firebaseRemoteConfig) } @Test @@ -76,4 +77,4 @@ class RemoteConfigSourceFirebaseImplTest { assertEquals(100.0, actual, .1) } -} \ No newline at end of file +} diff --git a/app/src/test/java/com/brainwallet/notification/NotificationHandlerTest.kt b/app/src/test/java/com/brainwallet/notification/NotificationHandlerTest.kt index 5a860d26..c8a5813e 100644 --- a/app/src/test/java/com/brainwallet/notification/NotificationHandlerTest.kt +++ b/app/src/test/java/com/brainwallet/notification/NotificationHandlerTest.kt @@ -3,15 +3,17 @@ package com.brainwallet.notification import android.content.Context import android.os.Bundle import androidx.collection.arrayMapOf -import androidx.core.app.NotificationManagerCompat +import androidx.core.app.NotificationCompat import com.google.firebase.messaging.Constants.MessageNotificationKeys import com.google.firebase.messaging.Constants.MessagePayloadKeys import com.google.firebase.messaging.RemoteMessage -import io.mockk.Runs +import io.mockk.MockKAnnotations import io.mockk.every -import io.mockk.just -import io.mockk.mockk +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK import io.mockk.mockkStatic +import io.mockk.unmockkAll +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before @@ -20,11 +22,36 @@ import org.junit.Test class NotificationHandlerTest { - private val context: Context = mockk(relaxed = true) + @MockK + private lateinit var context: Context + + @MockK + private lateinit var notificationHandlerBuilderProvider: NotificationHandlerBuilderProvider + + @RelaxedMockK + private lateinit var notificationNotifier: NotificationNotifier + + @RelaxedMockK + private lateinit var notificationBuilder: NotificationCompat.Builder + + private lateinit var sut: NotificationHandler @Before fun setUp() { mockkStatic(MessagePayloadKeys::class) + MockKAnnotations.init(this, relaxUnitFun = true) + every { + notificationHandlerBuilderProvider.createNotificationBuilder( + any(), + any() + ) + } returns notificationBuilder + sut = NotificationHandler(notificationHandlerBuilderProvider, notificationNotifier) + } + + @After + fun tearDown() { + unmockkAll() } @Test @@ -34,7 +61,7 @@ class NotificationHandlerTest { every { MessagePayloadKeys.extractDeveloperDefinedPayload(any()) } returns arrayMapOf() - val actual = NotificationHandler.handleMessageReceived(context, remoteMessage) + val actual = sut.handleMessageReceived(context, remoteMessage) assertEquals(false, actual) } @@ -76,13 +103,9 @@ class NotificationHandlerTest { if (testOSVersion == 6 || testOSVersion == 15) { assertTrue(successMessage, true) - } - else { - mockkStatic(NotificationManagerCompat::class) - every { NotificationManagerCompat.from(context).notify(any()) } just Runs - - val actual = NotificationHandler.handleMessageReceived(context, remoteMessage) - assertEquals(failMessage,true, actual) + } else { + val actual = sut.handleMessageReceived(context, remoteMessage) + assertEquals(failMessage, true, actual) } } diff --git a/build.gradle.kts b/build.gradle.kts index 26e5212f..8cbe07fb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,7 @@ plugins { alias(libs.plugins.jetbrains.kotlin.serialization) apply false alias(libs.plugins.google.services) apply false alias(libs.plugins.firebase.crashlytics) apply false + alias(libs.plugins.ksp) apply false } tasks.register("clean", Delete::class) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cd3b7691..fc956caf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,8 @@ eclipse-jetty = "9.2.19.v20160908" junit = "4.13.2" mockk = "1.13.13" koin-bom = "4.0.2" +koin-annotation-bom = "2.1.0" +ksp = "2.0.0-1.0.24" [libraries] androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" } @@ -112,7 +114,9 @@ koin-android = { module = "io.insert-koin:koin-android" } koin-android-compat = { module = "io.insert-koin:koin-android-compat" } koin-compose = { module = "io.insert-koin:koin-compose" } koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel" } - +koin-annotation-bom = { module = "io.insert-koin:koin-annotations-bom", version.ref = "koin-annotation-bom" } +koin-annotation = { module = "io.insert-koin:koin-annotations" } +koin-annotation-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-annotation-bom" } [bundles] androidx-lifecycle = ["androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel", "androidx-lifecycle-viewmodel-compose"] @@ -136,4 +140,5 @@ jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serializati jetbrains-kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version = "2.1.0" } jetbrains-kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } google-services = { id = "com.google.gms.google-services", version = "4.4.2" } -firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.2" } \ No newline at end of file +firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.2" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file From 5900ed4082aef15f11158064e2b5e133fc60364c Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Tue, 19 Aug 2025 15:08:59 +0100 Subject: [PATCH 52/65] Create PULL_REQUEST_TEMPLATE.md Create PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 59 ++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..9cbe9c85 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,59 @@ +# Pull Request Template - Android Development + +## 📱 Description + + + + +## Platform +- [ ] Android +- [ ] iOS +- [ ] Games-Unity +- [ ] DevOps (AWS) +- [ ] Website +- [ ] C/Golang + +## 🎯 Type of Change + +- [ ] 🐛 Bug fix (non-breaking change which fixes an issue) +- [ ] ✨ New feature (non-breaking change which adds functionality) +- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] 🔧 Refactoring (code change that neither fixes a bug nor adds a feature) +- [ ] 📚 Documentation update +- [ ] 🎨 UI/UX improvement +- [ ] ⚡ Performance improvement +- [ ] 🧪 Test addition or improvement + +## 📋 Changes Made + +- +- +- + +## 🔗 Related Issues + +- Fixes # +- Related to # + +## 🧪 Tests Status +- [ ] Tests ran successfully locally? +- [ ] Added more tests? How many? +- [ ] Code coverage percentage of the codebase: __% + + +## 📸 Screenshots/Videos + + + +### Before + + +### After + + +## 🎯 Reviewers + +@kcw-grunt, @josikie + + + From 3b1f628e0918d9108cafc578e433cca479c5667f Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Tue, 19 Aug 2025 21:08:33 +0100 Subject: [PATCH 53/65] bump for test (#121) * bump for test * Updated the template * polishes --- .github/PULL_REQUEST_TEMPLATE.md | 26 +++++++------------------- app/build.gradle.kts | 2 +- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9cbe9c85..df64dbb1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,6 @@ -# Pull Request Template - Android Development - ## 📱 Description - - ## Platform - [ ] Android - [ ] iOS @@ -15,22 +11,20 @@ ## 🎯 Type of Change -- [ ] 🐛 Bug fix (non-breaking change which fixes an issue) -- [ ] ✨ New feature (non-breaking change which adds functionality) -- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] 🐛 Bug fix +- [ ] ✨ New feature - [ ] 🔧 Refactoring (code change that neither fixes a bug nor adds a feature) - [ ] 📚 Documentation update - [ ] 🎨 UI/UX improvement - [ ] ⚡ Performance improvement - [ ] 🧪 Test addition or improvement -## 📋 Changes Made +## 📋 Changes - - -- -## 🔗 Related Issues +### 🔗 Related Issues - Fixes # - Related to # @@ -40,20 +34,14 @@ - [ ] Added more tests? How many? - [ ] Code coverage percentage of the codebase: __% - ## 📸 Screenshots/Videos -### Before - - -### After - +| Before | After | +|--------|-------| +||| ## 🎯 Reviewers @kcw-grunt, @josikie - - - diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b42bd6bd..2032355a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,7 +21,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 36 - versionCode = 202506271 + versionCode = 202506272 versionName = "v4.6.2" multiDexEnabled = true From f11d5a81ebc315b026714a0b76021d6e98cd16c3 Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Wed, 20 Aug 2025 17:36:42 +0700 Subject: [PATCH 54/65] feat(#174): initiate games module (#119) --- .gitmodules | 4 ++++ app/build.gradle.kts | 7 +++++++ build.gradle.kts | 1 + gradle/libs.versions.toml | 3 ++- modules/games | 1 + settings.gradle.kts | 18 ++++++++++++++++++ 6 files changed, 33 insertions(+), 1 deletion(-) create mode 160000 modules/games diff --git a/.gitmodules b/.gitmodules index 17190631..bd038a83 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,7 @@ [submodule "app/src/main/jni/core"] path = app/src/main/jni/core url = https://github.com/brainwallet-co/core.git +[submodule "modules/games"] + path = modules/games + url = https://github.com/gruntsoftware/android-games.git + update = none diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2032355a..a15a6cae 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -188,6 +188,13 @@ dependencies { } } + val gamesModule = findProject(":modules:games:content") + if (gamesModule != null) { + implementation(gamesModule) + } else { + logger.lifecycle("⚠️ Submodule ':modules:games:content' not found — skipping dependency") + } + implementation("androidx.webkit:webkit:1.9.0") implementation(libs.androidx.core) implementation(libs.androidx.appcompat) diff --git a/build.gradle.kts b/build.gradle.kts index 8cbe07fb..a34bb719 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false alias(libs.plugins.jetbrains.kotlin.android) apply false alias(libs.plugins.jetbrains.kotlin.compose) apply false alias(libs.plugins.jetbrains.kotlin.kapt) apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fc956caf..c234152d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -135,10 +135,11 @@ squareup-okhttp = ["squareup-okhttp", "squareup-okhttp-logging-interceptor"] [plugins] android-application = { id = "com.android.application", version.ref = "agp" } +android-library = { id = "com.android.library", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } jetbrains-kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version = "2.1.0" } jetbrains-kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } google-services = { id = "com.google.gms.google-services", version = "4.4.2" } firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.2" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } diff --git a/modules/games b/modules/games new file mode 160000 index 00000000..a5f408cc --- /dev/null +++ b/modules/games @@ -0,0 +1 @@ +Subproject commit a5f408cc093f729b32f351e29d010a31242eef8e diff --git a/settings.gradle.kts b/settings.gradle.kts index b3356345..2ee160e5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,15 +11,33 @@ pluginManagement { gradlePluginPortal() } } + dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } + + versionCatalogs { + val gamesToml = file("modules/games/gradle/libs.versions.toml") + if (gamesToml.exists()) { + create("games") { + from(files(gamesToml)) + } + } else { + logger.lifecycle("⚠️ Submodule catalog 'games' not loaded — file not found: $gamesToml") + } + } } rootProject.name = "Brainwallet Android" include(":app") include(":install_time_asset_pack") +val gamesDir = file("modules/games/content") +if (gamesDir.exists()) { + include(":modules:games:content") +} else { + logger.lifecycle("⚠️ Submodule ':modules:games:content' not included — folder not found: $gamesDir") +} \ No newline at end of file From 77ed7dfd7b63b285e1b45b7f2762b7dc8505a360 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Wed, 20 Aug 2025 15:55:37 +0100 Subject: [PATCH 55/65] Force pushed the version and code bump and catch up with Prod. --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a15a6cae..a68ebc9c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,8 +21,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 36 - versionCode = 202506272 - versionName = "v4.6.2" + versionCode = 202506273 + versionName = "v4.7.1" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") From ef353e37358557a53ca8099f4f2802566b8c5cba Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Mon, 25 Aug 2025 09:12:16 +0100 Subject: [PATCH 56/65] =?UTF-8?q?=F0=9F=9A=80[Release=20v4.7.2]=20Merge=20?= =?UTF-8?q?into=20Develop=20(#127)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚀[Release v4.4.7] Merge into Main (#70) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington --------- Co-authored-by: andhikayuana * 🚀[Release v4.5.0] Merge into Main (#78) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.5.4] Merge into Main (#87) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * Updated README * code bump * chore: open bread activity first then open moonpay widget (#88) * code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.5.5] Merge into Main (#101) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Update build.gradle.kts --------- Co-authored-by: andhikayuana * 🚀[Release v4.6.0] Merge into Main (#104) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * version bump * code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.6.1] Merge into Main (#107) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * updated metadata (#105) * chore: remove screen lock detection (#106) * build bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.6.2] Merge into Main (#110) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * updated metadata (#105) * chore: remove screen lock detection (#106) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * 🧰 Fx/seed words UI polish (#108) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * Removed unused audio files * polished tests * removed unused asset pack * code bump * code bump * ❇️ Feat/add polish punjabi farsi (#109) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * Removed unused audio files * polished tests * removed unused asset pack * code bump * broke out completion of the seed phrase and navigation - Feedback was a user could complete seed phrase and not tap "Game and Sync" - Forced users to start all over - Saved a correct seed phrase confirmation into memory * code bump * fix for https://console.firebase.google.com/project/brainwallet-mobile/crashlytics/app/android:ltd.grunt.brainwallet/issues/1386f366ab35e9112a6b742d629bb0be?time=last-seven-days&types=crash&sessionEventKey=685DA96C00BF00015A7AFEA30E0DB49C_2098799426616143441 * measure where users tap * code bump * fix: fix YourSeedProveItState.isWordUsedCorrectly * Cleaned commented out BuyLitecoinscreen * code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.7.0] Merge into Main (#115) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * updated metadata (#105) * chore: remove screen lock detection (#106) * 🧰 Fx/seed words UI polish (#108) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * ❇️ Feat/add polish punjabi farsi (#109) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * Removed unused audio files * polished tests * removed unused asset pack * code bump * fix: fix YourSeedProveItState.isWordUsedCorrectly (#111) * Upgrade targetSdk 36 (#113) * chore: change drawable with density for brainwallet_logotype_white * chore: adjustment WelcomeScreen.kt * chore: adjustment for targetSdk 36 also support 16KB page size * bump clean extra semicolon * Update pro-guard-rules * Updated the version --------- Co-authored-by: andhikayuana * Updated games module to v1.1.0 * Updated the games submodule * Renamed and tested with user skips --------- Co-authored-by: andhikayuana --- README.md | 5 ++++ app/build.gradle.kts | 4 +-- app/proguard-rules.pro | 2 +- .../java/com/brainwallet/data/model/Fee.kt | 2 +- .../navigation/LegacyNavigation.kt | 2 ++ .../com/brainwallet/ui/BrainwalletActivity.kt | 4 +++ .../screens/buylitecoin/BuyLitecoinScreen.kt | 1 - .../ui/screens/home/SettingsEvent.kt | 1 - .../settingsrows/LitecoinBlockchainDetail.kt | 4 +++ .../ui/screens/home/receive/ReceiveDialog.kt | 1 - .../ui/screens/topup/TopUpScreen.kt | 1 + .../ui/screens/welcome/WelcomeScreen.kt | 1 + .../yourseedproveit/YourSeedProveItEvent.kt | 2 ++ .../yourseedproveit/YourSeedProveItScreen.kt | 4 +++ .../YourSeedProveItViewModel.kt | 5 ++++ .../brainwallet/tools/util/BRConstantsTest.kt | 28 +++++++++---------- gradle/libs.versions.toml | 2 +- modules/games | 2 +- 18 files changed, 48 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 4cd2e194..0c961d8d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ ## Easy and secure Brainwallet is a easy and fun way to use your crypto (Litecoin) and memorize your seed words + +### Release notes + +- v4.5.4 + - Added new MP Buy UI diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a68ebc9c..253c6aca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,8 +21,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 36 - versionCode = 202506273 - versionName = "v4.7.1" + versionCode = 202506295 + versionName = "v4.7.2" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 7ab25998..44883644 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -40,7 +40,7 @@ -dontwarn org.slf4j.impl.StaticLoggerBinder -dontwarn org.slf4j.impl.StaticMDCBinder -dontwarn org.slf4j.impl.StaticMarkerBinder - +-dontwarn java.lang.reflect.AnnotatedType -keepclasseswithmembernames class * { native ; diff --git a/app/src/main/java/com/brainwallet/data/model/Fee.kt b/app/src/main/java/com/brainwallet/data/model/Fee.kt index b1d086ae..28413fd9 100644 --- a/app/src/main/java/com/brainwallet/data/model/Fee.kt +++ b/app/src/main/java/com/brainwallet/data/model/Fee.kt @@ -91,4 +91,4 @@ fun FeeOption.getFiatFormatted(currencyEntity: CurrencyEntity): String { fun List.getSelectedIndex(selectedFeeType: String): Int { return indexOfFirst { it.type == selectedFeeType }.takeIf { it >= 0 } ?: 2 //2 -> index of top, since we have [low,medium,top] -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index 10503556..a46e3261 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -18,6 +18,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import timber.log.Timber +import com.google.firebase.analytics.FirebaseAnalytics //provide old navigation using intent activity @@ -35,6 +36,7 @@ object LegacyNavigation { auth: Boolean ) { Timber.i("timber: startBreadActivity: %s", from.javaClass.name) + val intent = if (auth) BrainwalletActivity.createIntent(from, Route.UnLock()) else Intent(from, BreadActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) diff --git a/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt b/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt index 8ef9dfda..ed8b27d9 100644 --- a/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt +++ b/app/src/main/java/com/brainwallet/ui/BrainwalletActivity.kt @@ -32,6 +32,7 @@ import com.brainwallet.ui.screens.inputwords.InputWordsViewModel.Companion.LEGAC import com.brainwallet.ui.screens.inputwords.InputWordsViewModel.Companion.LEGACY_DIALOG_WIPE_ALERT import com.brainwallet.ui.screens.inputwords.InputWordsViewModel.Companion.LEGACY_EFFECT_RESET_PIN import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItViewModel.Companion.LEGACY_EFFECT_ON_PAPERKEY_PROVED +import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItViewModel.Companion.LEGACY_NAVIGATE_TO_HOME import com.brainwallet.ui.theme.BrainwalletAppTheme import com.brainwallet.util.EventBus import com.brainwallet.wallet.BRWalletManager @@ -115,6 +116,9 @@ class BrainwalletActivity : BRActivity() { LEGACY_EFFECT_ON_PAPERKEY_PROVED -> { BRSharedPrefs.putPhraseWroteDown(this@BrainwalletActivity, true) + } + + LEGACY_NAVIGATE_TO_HOME -> { LegacyNavigation.startBreadActivity( this@BrainwalletActivity, false diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt index 89fd9473..ad6b3cf5 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt @@ -47,7 +47,6 @@ fun BuyLitecoinScreen( val loadingState by viewModel.loadingState.collectAsState() val appSetting by viewModel.appSetting.collectAsState() val context = LocalContext.current - LaunchedEffect(Unit) { viewModel.onEvent(BuyLitecoinEvent.OnLoad(context)) viewModel.uiEffect.collect { effect -> diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt index 61a8ced4..cf6b1d31 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt @@ -8,7 +8,6 @@ sealed class SettingsEvent { val shareAnalyticsDataEnabled: Boolean = false, val lastSyncMetadata: String? = null, ) : SettingsEvent() - object OnSecurityUpdatePinClick : SettingsEvent() object OnSecuritySeedPhraseClick : SettingsEvent() object OnSecurityShareAnalyticsDataClick : SettingsEvent() diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt index f964e418..1c3e6ef8 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt @@ -14,6 +14,10 @@ import androidx.compose.material3.SegmentedButtonDefaults import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt index 8292904c..e96a1f2a 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt @@ -90,7 +90,6 @@ fun ReceiveDialog( val appSetting by viewModel.appSetting.collectAsState() val context = LocalContext.current val wheelPickerFiatCurrencyState = rememberWheelPickerState(0) - LaunchedEffect(Unit) { viewModel.onEvent(ReceiveDialogEvent.OnLoad(context)) viewModel.uiEffect.collect { effect -> diff --git a/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt index 22f5722d..7ef16b33 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/topup/TopUpScreen.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.brainwallet.R +import com.brainwallet.navigation.LegacyNavigation import com.brainwallet.navigation.OnNavigate import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index cec6d05a..d5a1fd2b 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt index 68816d6a..b315d980 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItEvent.kt @@ -13,5 +13,7 @@ sealed class YourSeedProveItEvent { object OnGameAndSync : YourSeedProveItEvent() + object OnCompletedPaperKey : YourSeedProveItEvent() + object OnClear : YourSeedProveItEvent() } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt index 71d1c56e..e505438c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItScreen.kt @@ -53,6 +53,8 @@ import com.brainwallet.R import com.brainwallet.navigation.OnNavigate import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect +import com.brainwallet.tools.manager.AnalyticsManager +import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.composable.BrainwalletScaffold import com.brainwallet.ui.composable.BrainwalletTopAppBar import com.brainwallet.ui.composable.LargeButton @@ -86,6 +88,8 @@ fun YourSeedProveItScreen( LaunchedEffect(state.orderCorrected) { if (state.orderCorrected) { coinAudioPlayer.start() + viewModel.onEvent(YourSeedProveItEvent.OnCompletedPaperKey) + AnalyticsManager.logCustomEvent(BRConstants._20250303_DSTU) } } diff --git a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt index e54f745f..75f68797 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/yourseedproveit/YourSeedProveItViewModel.kt @@ -51,6 +51,10 @@ class YourSeedProveItViewModel : BrainwalletViewModel() { } YourSeedProveItEvent.OnGameAndSync -> viewModelScope.launch { + EventBus.emit(EventBus.Event.Message(LEGACY_NAVIGATE_TO_HOME)) + } + + YourSeedProveItEvent.OnCompletedPaperKey -> viewModelScope.launch { EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_PAPERKEY_PROVED)) } } @@ -58,5 +62,6 @@ class YourSeedProveItViewModel : BrainwalletViewModel() { companion object { const val LEGACY_EFFECT_ON_PAPERKEY_PROVED = "onPaperKeyProved" + const val LEGACY_NAVIGATE_TO_HOME = "navigateToHome" } } \ No newline at end of file diff --git a/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt b/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt index 5779b8df..1f6fee1b 100644 --- a/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt +++ b/app/src/test/java/com/brainwallet/tools/util/BRConstantsTest.kt @@ -16,12 +16,12 @@ class BRConstantsTest { @Test fun `validate App external URL constant`(){ - assertSame(BRConstants.TWITTER_LINK,"https://twitter.com/Brainwallet_App"); - assertSame(BRConstants.INSTAGRAM_LINK,"https://www.instagram.com/brainwalletapp"); - assertSame(BRConstants.WEB_LINK,"https://brainwallet.co"); - assertSame(BRConstants.TOS_LINK,"https://brainwallet.co/privacy-policy.html"); - assertSame(BRConstants.MOBILE_MP_LINK,"https://brainwallet.co/mobile-top-up.html"); - assertSame(BRConstants.BITREFILL_AFFILIATE_LINK,"https://www.bitrefill.com/"); + assertSame(BRConstants.TWITTER_LINK,"https://twitter.com/Brainwallet_App") + assertSame(BRConstants.INSTAGRAM_LINK,"https://www.instagram.com/brainwalletapp") + assertSame(BRConstants.WEB_LINK,"https://brainwallet.co") + assertSame(BRConstants.TOS_LINK,"https://brainwallet.co/privacy-policy.html") + assertSame(BRConstants.MOBILE_MP_LINK,"https://brainwallet.co/mobile-top-up.html") + assertSame(BRConstants.BITREFILL_AFFILIATE_LINK,"https://www.bitrefill.com/") } @Test @@ -89,7 +89,7 @@ class BRConstantsTest { // public ActivityScenarioRule mActivityRule = new ActivityScenarioRule<>(IntroActivity.class); // @Before // public void setUp() { -// Log.e(TAG, "setUp: "); +// Log.e(TAG, "setUp: ") // } // // @After @@ -97,16 +97,16 @@ class BRConstantsTest { // } // @Test // public void testLitecoinSymbolConstants() { -// Assert.assertSame(BRConstants.litecoinLowercase,"ł"); -// Assert.assertSame(BRConstants.litecoinUppercase,"Ł"); +// Assert.assertSame(BRConstants.litecoinLowercase,"ł") +// Assert.assertSame(BRConstants.litecoinUppercase,"Ł") // } // @Test // public void testAppExternalURLConstants() { -// Assert.assertSame(BRConstants.TWITTER_LINK,"https://twitter.com/Brainwallet_App"); -// Assert.assertSame(BRConstants.WEB_LINK,"https://brainwallet.co"); -// Assert.assertSame(BRConstants.TOS_LINK,"https://brainwallet.co/privacy"); -// Assert.assertSame(BRConstants.CUSTOMER_SUPPORT_LINK,"https://support.brainwallet.co/hc/en-us/requests/new"); -// Assert.assertSame(BRConstants.BITREFILL_AFFILIATE_LINK,"https://www.bitrefill.com/"); +// Assert.assertSame(BRConstants.TWITTER_LINK,"https://twitter.com/Brainwallet_App") +// Assert.assertSame(BRConstants.WEB_LINK,"https://brainwallet.co") +// Assert.assertSame(BRConstants.TOS_LINK,"https://brainwallet.co/privacy") +// Assert.assertSame(BRConstants.CUSTOMER_SUPPORT_LINK,"https://support.brainwallet.co/hc/en-us/requests/new") +// Assert.assertSame(BRConstants.BITREFILL_AFFILIATE_LINK,"https://www.bitrefill.com/") // } // @Test // public void testFirebaseAnalyticsConstants() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c234152d..f1ff0cc4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] kotlin = "2.0.0" -agp = "8.5.1" +agp = "8.7.3" androidx-core-ktx = "1.12.0" androidx-appcompat = "1.6.1" androidx-legacy-support = "1.0.0" diff --git a/modules/games b/modules/games index a5f408cc..b2cc09df 160000 --- a/modules/games +++ b/modules/games @@ -1 +1 @@ -Subproject commit a5f408cc093f729b32f351e29d010a31242eef8e +Subproject commit b2cc09df06d90baa9836b8789c38de569e2e8f8f From e25e9e11a8aad4a3c2492ce4a3300f0a589ca2c0 Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Mon, 25 Aug 2025 17:57:58 +0700 Subject: [PATCH 57/65] Fix(#227): Crash when launching MoonPay Widget (#126) Refactored the MoonPay widget integration to a dedicated Composable (`MoonPayWidgetLauncher`) to ensure proper state handling and loading behavior. - Added `MoonPayWidgetLauncher.kt` with Composable and ViewModel for managing signed URL fetch and Custom Tab launch. - Ensures loading state covers the whole screen, preventing UI crashes. - Removed legacy static method `LegacyNavigation.showMoonPayWidget`. - Updated `ReceiveDialog.kt` and `BuyLitecoinScreen.kt` to use the new Composable. - Minor cleanup in `LegacyNavigation.kt`. --- .../navigation/LegacyNavigation.kt | 62 +---------- .../navigation/MoonPayWidgeLauncher.kt | 103 ++++++++++++++++++ .../screens/buylitecoin/BuyLitecoinScreen.kt | 20 ++-- .../ui/screens/home/receive/ReceiveDialog.kt | 19 ++-- 4 files changed, 123 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/navigation/MoonPayWidgeLauncher.kt diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index a46e3261..21c82cda 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -1,26 +1,14 @@ package com.brainwallet.navigation import android.app.Activity -import android.app.ProgressDialog import android.content.Context import android.content.Intent -import android.widget.Toast -import androidx.browser.customtabs.CustomTabsIntent -import androidx.core.net.toUri -import com.brainwallet.BuildConfig import com.brainwallet.R -import com.brainwallet.data.repository.LtcRepository -import com.brainwallet.di.AppModule.getKoinInstance import com.brainwallet.presenter.activities.BreadActivity import com.brainwallet.ui.BrainwalletActivity -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import timber.log.Timber import com.google.firebase.analytics.FirebaseAnalytics - //provide old navigation using intent activity object LegacyNavigation { @@ -67,52 +55,4 @@ object LegacyNavigation { ) = BrainwalletActivity.createIntent(context, destination).also { context.startActivity(it) } - - @JvmOverloads - @JvmStatic - fun showMoonPayWidget( - context: Context, - params: Map = mapOf(), - isDarkMode: Boolean = true, - ) { - val ltcRepository: LtcRepository = getKoinInstance() - val progressDialog = ProgressDialog(context).apply { - setMessage(context.getString(R.string.loading)) - setCancelable(false) - show() - } - - CoroutineScope(Dispatchers.Main).launch { - try { - val result = withContext(Dispatchers.IO) { - ltcRepository.fetchMoonpaySignedUrl( - params = params.toMutableMap().apply { - put("theme", if (isDarkMode) "dark" else "light") - } - ) - } - - val widgetUri = result.toUri().buildUpon() - .apply { - if (BuildConfig.DEBUG) { - authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com - } - } - .build() - val intent = CustomTabsIntent.Builder() - .setColorScheme(if (isDarkMode) CustomTabsIntent.COLOR_SCHEME_DARK else CustomTabsIntent.COLOR_SCHEME_LIGHT) - .build() - intent.launchUrl(context, widgetUri) - } catch (e: Exception) { - Toast.makeText( - context, - "Failed to load: ${e.message}, please try again later", - Toast.LENGTH_LONG - ).show() - } finally { - progressDialog.dismiss() - } - } - } - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/navigation/MoonPayWidgeLauncher.kt b/app/src/main/java/com/brainwallet/navigation/MoonPayWidgeLauncher.kt new file mode 100644 index 00000000..7677a4de --- /dev/null +++ b/app/src/main/java/com/brainwallet/navigation/MoonPayWidgeLauncher.kt @@ -0,0 +1,103 @@ +package com.brainwallet.navigation + +import android.net.Uri +import android.widget.Toast +import androidx.browser.customtabs.CustomTabsIntent +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.core.net.toUri +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.brainwallet.BuildConfig +import com.brainwallet.data.repository.LtcRepository +import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.ui.composable.LoadingDialog +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel +import org.koin.compose.viewmodel.koinViewModel + +@KoinViewModel +class MoonPayWidgetLauncherViewModel( + private val settingRepository: SettingRepository, + private val ltcRepository: LtcRepository, + private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO +) : ViewModel() { + + private val _isLoading = MutableStateFlow(false) + val isLoading = _isLoading.asStateFlow() + + private val _result = Channel>>() + val result = _result.receiveAsFlow() + + fun launch(params: Map) { + _isLoading.update { true } + viewModelScope.launch(ioDispatcher) { + val isDarkMode = settingRepository.isDarkMode() + _result.send(ltcRepository.runCatching { + val result = ltcRepository.fetchMoonpaySignedUrl( + params = params.toMutableMap().apply { + put("theme", if (isDarkMode) "dark" else "light") + } + ) + isDarkMode to result.toUri().buildUpon() + .apply { + if (BuildConfig.DEBUG) { + authority("buy-sandbox.moonpay.com")//replace base url from buy.moonpay.com + } + } + .build() + }) + _isLoading.update { false } + } + } +} + +@Composable +fun MoonPayWidgetLauncher( + modifier: Modifier = Modifier, + viewModel: MoonPayWidgetLauncherViewModel = koinViewModel(), + onResult: () -> Unit = {} +) { + val context = LocalContext.current + val isLoading by viewModel.isLoading.collectAsState() + + AnimatedVisibility(isLoading, modifier = modifier) { + LoadingDialog() + } + + LaunchedEffect(Unit) { + viewModel.result.collect { result -> + result.fold( + onSuccess = { (isDarkMode, uri) -> + val intent = CustomTabsIntent.Builder() + .setColorScheme( + if (isDarkMode) CustomTabsIntent.COLOR_SCHEME_DARK + else CustomTabsIntent.COLOR_SCHEME_LIGHT + ) + .build() + intent.launchUrl(context, uri) + }, + onFailure = { e -> + Toast.makeText( + context, + "Failed to load: ${e.message}, please try again later", + Toast.LENGTH_LONG + ).show() + } + ) + onResult.invoke() + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt index ad6b3cf5..e1aa80a0 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/buylitecoin/BuyLitecoinScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Done import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -26,22 +25,22 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import com.brainwallet.R -import com.brainwallet.navigation.LegacyNavigation +import com.brainwallet.navigation.MoonPayWidgetLauncher +import com.brainwallet.navigation.MoonPayWidgetLauncherViewModel import com.brainwallet.navigation.OnNavigate import com.brainwallet.navigation.UiEffect import com.brainwallet.ui.composable.BrainwalletScaffold import com.brainwallet.ui.composable.BrainwalletTopAppBar import com.brainwallet.ui.composable.LargeButton -import com.brainwallet.ui.composable.LoadingDialog -import com.brainwallet.ui.screens.home.receive.ReceiveDialogEvent import com.brainwallet.ui.theme.BrainwalletTheme -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel //TODO: wip @Composable fun BuyLitecoinScreen( onNavigate: OnNavigate, - viewModel: BuyLitecoinViewModel = koinInject() + viewModel: BuyLitecoinViewModel = koinViewModel(), + moonPayWidgetLauncherViewModel: MoonPayWidgetLauncherViewModel = koinViewModel() ) { val state by viewModel.state.collectAsState() val loadingState by viewModel.loadingState.collectAsState() @@ -148,21 +147,20 @@ fun BuyLitecoinScreen( modifier = Modifier.align(Alignment.BottomCenter), enabled = loadingState.visible.not(), onClick = { - //open bread activity first then open moonpay widget - LegacyNavigation.restartBreadActivity(context) - LegacyNavigation.showMoonPayWidget( - context = context, + moonPayWidgetLauncherViewModel.launch( params = mapOf( "baseCurrencyCode" to appSetting.currency.code, "baseCurrencyAmount" to state.fiatAmount.toString(), "language" to appSetting.languageCode, "walletAddress" to state.address - ) + ), + ) } ) { Text(stringResource(R.string.buy_litecoin_button_moonpay)) } } + MoonPayWidgetLauncher(viewModel = moonPayWidgetLauncherViewModel) } } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt index e96a1f2a..86389cea 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt @@ -63,7 +63,8 @@ import androidx.fragment.app.FragmentManager import com.brainwallet.R import com.brainwallet.data.model.getFormattedText import com.brainwallet.data.model.isCustom -import com.brainwallet.navigation.LegacyNavigation +import com.brainwallet.navigation.MoonPayWidgetLauncher +import com.brainwallet.navigation.MoonPayWidgetLauncherViewModel import com.brainwallet.navigation.UiEffect import com.brainwallet.ui.composable.MoonpayBuyButton import com.brainwallet.ui.composable.VerticalWheelPicker @@ -77,13 +78,14 @@ import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import org.koin.android.ext.android.inject -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel import timber.log.Timber @Composable fun ReceiveDialog( onDismissRequest: () -> Unit, - viewModel: ReceiveDialogViewModel = koinInject() + viewModel: ReceiveDialogViewModel = koinViewModel(), + moonPayWidgetLauncherViewModel: MoonPayWidgetLauncherViewModel = koinViewModel() ) { val state by viewModel.state.collectAsState() val loadingState by viewModel.loadingState.collectAsState() @@ -369,24 +371,23 @@ fun ReceiveDialog( //todo: revisit this later //viewModel.onEvent(ReceiveDialogEvent.OnMoonpayButtonClick) - LegacyNavigation.showMoonPayWidget( - context = context, + moonPayWidgetLauncherViewModel.launch( params = mapOf( "baseCurrencyCode" to state.selectedFiatCurrency.code, "baseCurrencyAmount" to state.fiatAmount.toString(), "language" to appSetting.languageCode, "walletAddress" to state.address, ), - isDarkMode = appSetting.isDarkMode ) - onDismissRequest.invoke() }, ) // } } - - + MoonPayWidgetLauncher( + viewModel = moonPayWidgetLauncherViewModel, + onResult = onDismissRequest + ) } } From e0aebb533ad39733b19ba992dad8e678175e7754 Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Mon, 25 Aug 2025 18:51:58 +0700 Subject: [PATCH 58/65] feat(#138): Improve Unlock Screen UI and add dark mode toggle (#122) --- app/build.gradle.kts | 3 + .../com/brainwallet/navigation/UiEffect.kt | 1 + .../com/brainwallet/tools/qrcode/QRUtils.java | 48 +- .../ui/composable/BrainWalletLogo.kt | 39 ++ .../ui/composable/DarkModeToggleButton.kt | 29 +- .../brainwallet/ui/composable/Foundation.kt | 2 + .../ui/composable/PasscodeIndicator.kt | 7 +- .../ui/screens/home/receive/ReceiveDialog.kt | 548 +++++++++--------- .../home/receive/ReceiveDialogFragment.kt | 66 +++ .../ui/screens/unlock/UnLockEvent.kt | 5 +- .../ui/screens/unlock/UnLockScreen.kt | 187 ++---- .../ui/screens/unlock/UnLockState.kt | 1 + .../ui/screens/unlock/UnLockViewModel.kt | 35 +- .../unlock/components/UnLockScreenBody.kt | 111 ++++ .../unlock/components/UnLockScreenFooter.kt | 89 +++ .../unlock/components/UnLockScreenHeader.kt | 51 ++ .../java/com/brainwallet/ui/theme/Theme.kt | 7 +- .../brainwallet/util/CurrencyDataGetter.kt | 41 ++ .../brainwallet/util/VersionCodeProvider.kt | 22 + .../brainwallet_logotype_color.webp | Bin 0 -> 13554 bytes .../brainwallet_logotype_color.webp | Bin 0 -> 5224 bytes .../brainwallet_logotype_color.webp | Bin 0 -> 7898 bytes .../brainwallet_logotype_color.webp | Bin 0 -> 20550 bytes .../brainwallet_logotype_color.webp | Bin 0 -> 35226 bytes .../brainwallet_logotype_color.webp | Bin 0 -> 56492 bytes app/src/main/res/drawable/ic_clickable_qr.xml | 9 + app/src/main/res/values/strings.xml | 2 +- .../ui/screens/unlock/UnLockViewModelTest.kt | 359 ++++++++++++ .../util/CurrencyDataGetterTest.kt | 125 ++++ .../brainwallet/util/MainDispatcherRule.kt | 23 + .../util/VersionCodeProviderTest.kt | 44 ++ gradle/libs.versions.toml | 5 + 32 files changed, 1429 insertions(+), 430 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/ui/composable/BrainWalletLogo.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogFragment.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenBody.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenFooter.kt create mode 100644 app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenHeader.kt create mode 100644 app/src/main/java/com/brainwallet/util/CurrencyDataGetter.kt create mode 100644 app/src/main/java/com/brainwallet/util/VersionCodeProvider.kt create mode 100644 app/src/main/res/drawable-hdpi/brainwallet_logotype_color.webp create mode 100644 app/src/main/res/drawable-ldpi/brainwallet_logotype_color.webp create mode 100644 app/src/main/res/drawable-mdpi/brainwallet_logotype_color.webp create mode 100644 app/src/main/res/drawable-xhdpi/brainwallet_logotype_color.webp create mode 100644 app/src/main/res/drawable-xxhdpi/brainwallet_logotype_color.webp create mode 100644 app/src/main/res/drawable-xxxhdpi/brainwallet_logotype_color.webp create mode 100644 app/src/main/res/drawable/ic_clickable_qr.xml create mode 100644 app/src/test/java/com/brainwallet/ui/screens/unlock/UnLockViewModelTest.kt create mode 100644 app/src/test/java/com/brainwallet/util/CurrencyDataGetterTest.kt create mode 100644 app/src/test/java/com/brainwallet/util/MainDispatcherRule.kt create mode 100644 app/src/test/java/com/brainwallet/util/VersionCodeProviderTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 253c6aca..aac3d3e6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -220,6 +220,7 @@ dependencies { implementation(libs.bundles.google.play.feature.delivery) implementation(libs.bundles.google.play.review) implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.coroutines.android) implementation (libs.airbnb.lottie.compose) implementation(platform(libs.koin.bom)) implementation(libs.bundles.koin) @@ -243,6 +244,8 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockk) + testImplementation(libs.turbine) + testImplementation(libs.kotlinx.coroutines.tests) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.bundles.androidx.compose.ui.test) diff --git a/app/src/main/java/com/brainwallet/navigation/UiEffect.kt b/app/src/main/java/com/brainwallet/navigation/UiEffect.kt index 4ac64282..6e28b2e5 100644 --- a/app/src/main/java/com/brainwallet/navigation/UiEffect.kt +++ b/app/src/main/java/com/brainwallet/navigation/UiEffect.kt @@ -19,6 +19,7 @@ sealed class UiEffect { } data class ShowDialog(val name: String): UiEffect() + data object ShowMoonPayDialog: UiEffect() data class ShowMessage( val message: String, diff --git a/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java b/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java index a0e9fd5f..d426ea80 100644 --- a/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java +++ b/app/src/main/java/com/brainwallet/tools/qrcode/QRUtils.java @@ -7,6 +7,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Point; import android.view.Display; import android.view.WindowManager; @@ -66,6 +67,51 @@ public static Bitmap encodeAsBitmap(String content, int dimension) { return bitmap; } + public static Bitmap encodeAsTransparentBitmap(String content, int dimension) { + if (content == null) { + return null; + } + + Map hints = new EnumMap<>(EncodeHintType.class); + String encoding = guessAppropriateEncoding(content); + if (encoding != null) { + hints.put(EncodeHintType.CHARACTER_SET, encoding); + } + hints.put(EncodeHintType.MARGIN, 1); + + BitMatrix result; + try { + result = new MultiFormatWriter().encode( + content, + BarcodeFormat.QR_CODE, + dimension, + dimension, + hints + ); + } catch (IllegalArgumentException | WriterException e) { + Timber.e(e); + return null; + } + + if (result == null) return null; + + int width = result.getWidth(); + int height = result.getHeight(); + int[] pixels = new int[width * height]; + + for (int y = 0; y < height; y++) { + int offset = y * width; + for (int x = 0; x < width; x++) { + // Black pixels stay black, white becomes transparent + pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.TRANSPARENT; + } + } + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, width, 0, 0, width, height); + return bitmap; + } + public static boolean generateQR(Context ctx, String bitcoinURL, ImageView qrcode) { if (qrcode == null || bitcoinURL == null || bitcoinURL.isEmpty()) return false; WindowManager manager = (WindowManager) ctx.getSystemService(Activity.WINDOW_SERVICE); @@ -94,7 +140,7 @@ public static Bitmap generateQR(Context ctx, String litecoinUrl) { int smallerDimension = Math.min(width, height); smallerDimension = (int) (smallerDimension * 0.45f); Bitmap bitmap = null; - bitmap = QRUtils.encodeAsBitmap(litecoinUrl, smallerDimension); + bitmap = QRUtils.encodeAsTransparentBitmap(litecoinUrl, smallerDimension); return bitmap; } diff --git a/app/src/main/java/com/brainwallet/ui/composable/BrainWalletLogo.kt b/app/src/main/java/com/brainwallet/ui/composable/BrainWalletLogo.kt new file mode 100644 index 00000000..b22a053c --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/BrainWalletLogo.kt @@ -0,0 +1,39 @@ +package com.brainwallet.ui.composable + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.ui.theme.BrainwalletAppTheme +import com.brainwallet.ui.theme.BrainwalletTheme +import com.brainwallet.ui.theme.LocalDarkModeFlag + +@Composable +fun BrainWalletLogo(modifier: Modifier = Modifier) { + val iconLogo = if (LocalDarkModeFlag.current) { + R.drawable.brainwallet_logotype_white + } else { + R.drawable.brainwallet_logotype_color + } + Image( + painterResource(iconLogo), + contentDescription = "brainwallet_logo", + modifier = modifier + ) +} + +@PreviewLightDark +@Composable +private fun BrainWalletLogoPreview() { + BrainwalletAppTheme(appSetting = AppSetting(isDarkMode = isSystemInDarkTheme())) { + Box(modifier = Modifier.background(BrainwalletTheme.colors.background)) { + BrainWalletLogo() + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt b/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt index 05b89e53..2a9688d5 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt @@ -1,10 +1,12 @@ package com.brainwallet.ui.composable + import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon import androidx.compose.material3.IconToggleButton @@ -14,8 +16,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.ui.theme.BrainwalletAppTheme import com.brainwallet.ui.theme.BrainwalletTheme @Composable @@ -23,18 +28,17 @@ fun DarkModeToggleButton( checked: Boolean, onCheckedChange: (Boolean) -> Unit, modifier: Modifier = Modifier, + iconButtonSizeInDp: Int = 32 ) { - val iconButtonSize = 32 - IconToggleButton( checked = checked, onCheckedChange = onCheckedChange, - modifier = modifier, + modifier = modifier.size(iconButtonSizeInDp.dp), ) { Box( modifier = Modifier .fillMaxSize() - .width(iconButtonSize.dp) + .size(iconButtonSizeInDp.dp) .aspectRatio(1f) .clip(CircleShape) .border( @@ -47,12 +51,21 @@ fun DarkModeToggleButton( Icon( modifier = Modifier .align(Alignment.Center) - .width(iconButtonSize.dp) - .aspectRatio(1f), + .size((iconButtonSizeInDp * 0.6).dp), tint = if (checked) BrainwalletTheme.colors.warn else BrainwalletTheme.colors.surface, painter = painterResource(if (checked) R.drawable.ic_light_mode else R.drawable.ic_dark_mode), contentDescription = stringResource(R.string.toggle_dark_mode), ) } } -} \ No newline at end of file +} + +@PreviewLightDark +@Composable +private fun DarkModeToggleButtonPreview() { + BrainwalletAppTheme(AppSetting(isDarkMode = isSystemInDarkTheme())) { + Box(modifier = Modifier.background(BrainwalletTheme.colors.background)) { + DarkModeToggleButton(checked = isSystemInDarkTheme(), onCheckedChange = {}, ) + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt b/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt index f72137f5..16f92a0e 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/Foundation.kt @@ -27,6 +27,7 @@ import com.brainwallet.ui.theme.BrainwalletTheme fun BrainwalletScaffold( modifier: Modifier = Modifier, topBar: @Composable () -> Unit = {}, + bottomBar: @Composable () -> Unit = {}, floatingActionButton: @Composable () -> Unit = {}, content: @Composable (PaddingValues) -> Unit ) { @@ -35,6 +36,7 @@ fun BrainwalletScaffold( containerColor = BrainwalletTheme.colors.surface, contentColor = BrainwalletTheme.colors.content, topBar = topBar, + bottomBar = bottomBar, floatingActionButton = floatingActionButton, content = content ) diff --git a/app/src/main/java/com/brainwallet/ui/composable/PasscodeIndicator.kt b/app/src/main/java/com/brainwallet/ui/composable/PasscodeIndicator.kt index 32aead18..9837d962 100644 --- a/app/src/main/java/com/brainwallet/ui/composable/PasscodeIndicator.kt +++ b/app/src/main/java/com/brainwallet/ui/composable/PasscodeIndicator.kt @@ -3,17 +3,20 @@ package com.brainwallet.ui.composable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @Composable fun PasscodeIndicator( - passcode: List + passcode: List, + modifier: Modifier = Modifier, ) { Row( + modifier = modifier, horizontalArrangement = Arrangement.spacedBy(12.dp) ) { passcode.forEach { digit -> PinDotItem(checked = digit > -1) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt index 86389cea..64f7446e 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialog.kt @@ -2,15 +2,12 @@ package com.brainwallet.ui.screens.home.receive -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import android.widget.Toast import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -49,26 +46,28 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.FragmentManager import com.brainwallet.R +import com.brainwallet.data.model.AppSetting import com.brainwallet.data.model.getFormattedText import com.brainwallet.data.model.isCustom import com.brainwallet.navigation.MoonPayWidgetLauncher import com.brainwallet.navigation.MoonPayWidgetLauncherViewModel import com.brainwallet.navigation.UiEffect +import com.brainwallet.ui.LoadingState import com.brainwallet.ui.composable.MoonpayBuyButton import com.brainwallet.ui.composable.VerticalWheelPicker import com.brainwallet.ui.composable.WheelPickerFocusVertical +import com.brainwallet.ui.composable.WheelPickerState import com.brainwallet.ui.composable.rememberWheelPickerState import com.brainwallet.ui.theme.BrainwalletAppTheme import com.brainwallet.ui.theme.BrainwalletTheme @@ -77,13 +76,13 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter -import org.koin.android.ext.android.inject import org.koin.compose.viewmodel.koinViewModel import timber.log.Timber @Composable fun ReceiveDialog( onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, viewModel: ReceiveDialogViewModel = koinViewModel(), moonPayWidgetLauncherViewModel: MoonPayWidgetLauncherViewModel = koinViewModel() ) { @@ -123,52 +122,94 @@ fun ReceiveDialog( viewModel.onEvent(ReceiveDialogEvent.OnFiatCurrencyChange(state.fiatCurrencies[it])) } } + ReceiveDialog( + state = state, + loadingState = loadingState, + modifier = modifier, + appSetting = appSetting, + wheelPickerFiatCurrencyState = wheelPickerFiatCurrencyState, + onDismissRequest = onDismissRequest, + onMoonPayLaunch = moonPayWidgetLauncherViewModel::launch, + onEvent = viewModel::onEvent + ) + MoonPayWidgetLauncher( + viewModel = moonPayWidgetLauncherViewModel, + onResult = onDismissRequest + ) +} - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - .fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - CenterAlignedTopAppBar( - colors = TopAppBarDefaults.centerAlignedTopAppBarColors( - containerColor = BrainwalletTheme.colors.content //invert surface +@Composable +private fun ReceiveDialog( + state: ReceiveDialogState, + modifier: Modifier = Modifier, + appSetting: AppSetting = AppSetting(), + loadingState: LoadingState = LoadingState(), + wheelPickerFiatCurrencyState: WheelPickerState = rememberWheelPickerState(0), + onDismissRequest: () -> Unit = {}, + onMoonPayLaunch: (Map) -> Unit = {}, + onEvent: (ReceiveDialogEvent) -> Unit = {} +) { + val context = LocalContext.current + Box( + modifier = modifier + .background( + BrainwalletTheme.colors.content, + shape = BrainwalletTheme.shapes.large + ) + .border( + width = 1.dp, + color = BrainwalletTheme.colors.surface, + shape = BrainwalletTheme.shapes.large ), - expandedHeight = 56.dp, - title = { - Text( - text = stringResource(R.string.bottom_nav_item_buy_receive_title).uppercase(), - style = BrainwalletTheme.typography.titleSmall - ) - }, - navigationIcon = { - if (state.moonpayWidgetVisible()) { - IconButton(onClick = { - viewModel.onEvent(ReceiveDialogEvent.OnSignedUrlClear) - }) { + ) { + Column( + modifier = Modifier + .padding(12.dp) + .verticalScroll(rememberScrollState()) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + CenterAlignedTopAppBar( + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = BrainwalletTheme.colors.content //invert surface + ), + expandedHeight = 56.dp, + title = { + Text( + text = stringResource(R.string.bottom_nav_item_buy_receive_title).uppercase(), + style = BrainwalletTheme.typography.titleSmall.copy( + color = BrainwalletTheme.colors.surface + ) + ) + }, + navigationIcon = { + if (state.moonpayWidgetVisible()) { + IconButton(onClick = { + onEvent(ReceiveDialogEvent.OnSignedUrlClear) + }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.back) + ) + } + } + }, + actions = { + IconButton( + modifier = Modifier.testTag("buttonClose"), + onClick = onDismissRequest + ) { Icon( - Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.back) + Icons.Default.Close, + contentDescription = stringResource(R.string.AccessibilityLabels_close), + tint = BrainwalletTheme.colors.surface ) } } - }, - actions = { - IconButton( - modifier = Modifier.testTag("buttonClose"), - onClick = onDismissRequest - ) { - Icon( - Icons.Default.Close, - contentDescription = stringResource(R.string.AccessibilityLabels_close), - tint = BrainwalletTheme.colors.surface - ) - } - } - ) + ) - //moonpay widget - //todo: revisit this later + //moonpay widget + //todo: revisit this later // AnimatedVisibility(visible = state.moonpayWidgetVisible()) { // state.moonpayBuySignedUrl?.let { signedUrl -> // MoonpayBuyWidget( @@ -179,278 +220,227 @@ fun ReceiveDialog( // } - //buy / receive + //buy / receive // AnimatedVisibility(visible = state.moonpayWidgetVisible().not()) { - Column { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically - ) { - state.qrBitmap?.asImageBitmap()?.let { imageBitmap -> - Image( + Column { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + state.qrBitmap?.asImageBitmap()?.let { imageBitmap -> + Image( + modifier = Modifier + .weight(1f), + bitmap = imageBitmap, + contentDescription = "address", + colorFilter = ColorFilter.tint(BrainwalletTheme.colors.surface) + ) + } ?: Box( modifier = Modifier - .weight(1f), - bitmap = imageBitmap, - contentDescription = "address" + .weight(1f) + .height(180.dp) + .background(Color.Gray) ) - } ?: Box( - modifier = Modifier - .weight(1f) - .height(180.dp) - .background(Color.Gray) - ) - Column( - modifier = Modifier - .weight(1f), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = state.address, - style = BrainwalletTheme.typography.bodyLarge.copy( - fontWeight = FontWeight.Bold, - color = BrainwalletTheme.colors.surface - ), - maxLines = 4, - overflow = TextOverflow.Ellipsis - ) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(4.dp) + Column( + modifier = Modifier + .weight(1f), + verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( - text = stringResource(R.string.new_address).uppercase(), - style = BrainwalletTheme.typography.bodySmall.copy( - color = BrainwalletTheme.colors.surface, + text = state.address, + style = BrainwalletTheme.typography.bodyLarge.copy( + fontWeight = FontWeight.Bold, + color = BrainwalletTheme.colors.surface ), - modifier = Modifier.weight(1f) + maxLines = 4, + overflow = TextOverflow.Ellipsis ) - OutlinedIconButton( - modifier = Modifier.size(32.dp), - onClick = { - viewModel.onEvent(ReceiveDialogEvent.OnCopyClick(context)) - Toast.makeText( - context, - R.string.Receive_copied, - Toast.LENGTH_SHORT - ) - .show() - }, - colors = IconButtonDefaults.outlinedIconButtonColors( - containerColor = BrainwalletTheme.colors.content.copy(alpha = 0.5f) - ), + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - Icon( - painter = androidx.compose.ui.res.painterResource(id = R.drawable.ic_copy), - contentDescription = stringResource(R.string.URLHandling_copy), - tint = BrainwalletTheme.colors.surface + Text( + text = stringResource(R.string.new_address).uppercase(), + style = BrainwalletTheme.typography.bodySmall.copy( + color = BrainwalletTheme.colors.surface, + ), + modifier = Modifier.weight(1f) ) + OutlinedIconButton( + modifier = Modifier.size(32.dp), + onClick = { + onEvent(ReceiveDialogEvent.OnCopyClick(context)) + Toast.makeText( + context, + R.string.Receive_copied, + Toast.LENGTH_SHORT + ) + .show() + }, + colors = IconButtonDefaults.outlinedIconButtonColors( + containerColor = BrainwalletTheme.colors.content.copy(alpha = 0.5f) + ), + ) { + Icon( + painter = androidx.compose.ui.res.painterResource(id = R.drawable.ic_copy), + contentDescription = stringResource(R.string.URLHandling_copy), + tint = BrainwalletTheme.colors.surface + ) + } } } } - } - HorizontalDivider() + HorizontalDivider() - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - VerticalWheelPicker( - modifier = Modifier.weight(1f), - focus = { - WheelPickerFocusVertical( - dividerColor = BrainwalletTheme.colors.surface.copy( - alpha = 0.5f - ) - ) - }, - unfocusedCount = 1, - count = state.fiatCurrencies.size, - state = wheelPickerFiatCurrencyState, - ) { index -> - Text( - text = state.fiatCurrencies[index].code, - fontWeight = FontWeight.Bold, - color = BrainwalletTheme.colors.surface - ) - } - - Column( - modifier = Modifier.weight(1f), - horizontalAlignment = Alignment.CenterHorizontally + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center ) { - Text( - text = state.getLtcAmountFormatted(loadingState.visible), - style = BrainwalletTheme.typography.titleLarge.copy( + VerticalWheelPicker( + modifier = Modifier.weight(1f), + focus = { + WheelPickerFocusVertical( + dividerColor = BrainwalletTheme.colors.surface.copy( + alpha = 0.5f + ) + ) + }, + unfocusedCount = 1, + count = state.fiatCurrencies.size, + state = wheelPickerFiatCurrencyState, + ) { index -> + Text( + text = state.fiatCurrencies[index].code, fontWeight = FontWeight.Bold, color = BrainwalletTheme.colors.surface ) - ) - Text( - text = state.getRatesUpdatedAtFormatted(), - style = BrainwalletTheme.typography.bodySmall.copy( - color = BrainwalletTheme.colors.surface + } + + Column( + modifier = Modifier.weight(1f), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = state.getLtcAmountFormatted(loadingState.visible), + style = BrainwalletTheme.typography.titleLarge.copy( + fontWeight = FontWeight.Bold, + color = BrainwalletTheme.colors.surface + ) ) - ) + Text( + text = state.getRatesUpdatedAtFormatted(), + style = BrainwalletTheme.typography.bodySmall.copy( + color = BrainwalletTheme.colors.surface + ) + ) + } } - } - LazyRow( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - itemsIndexed(items = state.getQuickFiatAmountOptions()) { index, quickFiatAmountOption -> - AssistChip( - enabled = loadingState.visible.not(), - onClick = { - viewModel.onEvent( - ReceiveDialogEvent.OnFiatAmountOptionIndexChange( - index, - quickFiatAmountOption + LazyRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + itemsIndexed(items = state.getQuickFiatAmountOptions()) { index, quickFiatAmountOption -> + AssistChip( + enabled = loadingState.visible.not(), + onClick = { + onEvent( + ReceiveDialogEvent.OnFiatAmountOptionIndexChange( + index, + quickFiatAmountOption + ) ) - ) - }, - label = { + }, + label = { + Text( + text = if (quickFiatAmountOption.isCustom()) + stringResource(R.string.custom) + else quickFiatAmountOption.getFormattedText(), + style = BrainwalletTheme.typography.bodyMedium.copy( + color = BrainwalletTheme.colors.surface + ) + ) + }, + leadingIcon = { + if (index == state.selectedQuickFiatAmountOptionIndex) { + Icon(Icons.Default.Check, contentDescription = null) + } + } + ) + } + } + + + AnimatedVisibility(visible = state.isQuickFiatAmountOptionCustom()) { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + prefix = { Text( - text = if (quickFiatAmountOption.isCustom()) - stringResource(R.string.custom) - else quickFiatAmountOption.getFormattedText() + text = state.selectedFiatCurrency.symbol, + style = BrainwalletTheme.typography.bodyMedium.copy(color = BrainwalletTheme.colors.surface) ) }, - leadingIcon = { - if (index == state.selectedQuickFiatAmountOptionIndex) { - Icon(Icons.Default.Check, contentDescription = null) + trailingIcon = { + IconButton(onClick = { + onEvent(ReceiveDialogEvent.OnFiatAmountChange(state.fiatAmount)) + }) { + Icon(Icons.Default.Done, contentDescription = null) + } + }, + textStyle = BrainwalletTheme.typography.bodyMedium.copy(color = BrainwalletTheme.colors.surface), + value = "${if (state.fiatAmount < 1) "" else state.fiatAmount}", + singleLine = true, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + onValueChange = { input -> + val amount = input.toFloatOrNull() ?: 0f + onEvent(ReceiveDialogEvent.OnFiatAmountChange(amount, false)) + }, + shape = BrainwalletTheme.shapes.large, + isError = state.errorFiatAmountStringId != null, + supportingText = { + state.errorFiatAmountStringId?.let { + Text(stringResource(it, state.fiatAmount)) } } ) } - } - - AnimatedVisibility(visible = state.isQuickFiatAmountOptionCustom()) { - OutlinedTextField( + MoonpayBuyButton( modifier = Modifier.fillMaxWidth(), - prefix = { - Text( - text = state.selectedFiatCurrency.symbol, - style = BrainwalletTheme.typography.bodyMedium.copy(color = BrainwalletTheme.colors.surface) + enabled = loadingState.visible.not(), + onClick = { + + //todo: revisit this later + //viewModel.onEvent(ReceiveDialogEvent.OnMoonpayButtonClick) + onMoonPayLaunch( + mapOf( + "baseCurrencyCode" to state.selectedFiatCurrency.code, + "baseCurrencyAmount" to state.fiatAmount.toString(), + "language" to appSetting.languageCode, + "walletAddress" to state.address, + ) ) }, - trailingIcon = { - IconButton(onClick = { - viewModel.onEvent(ReceiveDialogEvent.OnFiatAmountChange(state.fiatAmount)) - }) { - Icon(Icons.Default.Done, contentDescription = null) - } - }, - textStyle = BrainwalletTheme.typography.bodyMedium.copy(color = BrainwalletTheme.colors.surface), - value = "${if (state.fiatAmount < 1) "" else state.fiatAmount}", - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - onValueChange = { input -> - val amount = input.toFloatOrNull() ?: 0f - viewModel.onEvent(ReceiveDialogEvent.OnFiatAmountChange(amount, false)) - }, - shape = BrainwalletTheme.shapes.large, - isError = state.errorFiatAmountStringId != null, - supportingText = { - state.errorFiatAmountStringId?.let { - Text(stringResource(it, state.fiatAmount)) - } - } ) - } - - MoonpayBuyButton( - modifier = Modifier.fillMaxWidth(), - enabled = loadingState.visible.not(), - onClick = { - - //todo: revisit this later - //viewModel.onEvent(ReceiveDialogEvent.OnMoonpayButtonClick) - - moonPayWidgetLauncherViewModel.launch( - params = mapOf( - "baseCurrencyCode" to state.selectedFiatCurrency.code, - "baseCurrencyAmount" to state.fiatAmount.toString(), - "language" to appSetting.languageCode, - "walletAddress" to state.address, - ), - ) - }, - ) // } - } - MoonPayWidgetLauncher( - viewModel = moonPayWidgetLauncherViewModel, - onResult = onDismissRequest - ) - } -} - -/** - * describe [ReceiveDialogFragment] for backward compat, - * since we are still using [com.brainwallet.presenter.activities.BreadActivity] - */ -class ReceiveDialogFragment : DialogFragment() { - - private val viewModel: ReceiveDialogViewModel by inject() - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - return ComposeView(requireContext()).apply { - setContent { - val appSetting by viewModel.appSetting.collectAsState() - /** - * we need this theme inside this fragment, - * because we are still using fragment to display ReceiveDialog composable - * pls check BreadActivity.handleNavigationItemSelected - */ - BrainwalletAppTheme(appSetting = appSetting) { - Box( - modifier = Modifier - .padding(12.dp) - .background( - BrainwalletTheme.colors.content, - shape = BrainwalletTheme.shapes.large - ) - .border( - width = 1.dp, - color = BrainwalletTheme.colors.surface, - shape = BrainwalletTheme.shapes.large - ) - .padding(12.dp), - ) { - ReceiveDialog( - viewModel = viewModel, - onDismissRequest = { dismiss() } - ) - } - } } } } +} - override fun onStart() { - super.onStart() - dialog?.window?.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT +@PreviewLightDark +@Composable +private fun ReceiveDialogPreview() { + val appSetting = AppSetting(isDarkMode = isSystemInDarkTheme()) + BrainwalletAppTheme(appSetting) { + ReceiveDialog( + modifier = Modifier.padding(12.dp), + state = ReceiveDialogState(), + appSetting = appSetting ) - dialog?.window?.setBackgroundDrawableResource(android.R.color.transparent) - isCancelable = false } - - companion object { - @JvmStatic - fun show(manager: FragmentManager) { - ReceiveDialogFragment().show(manager, "ReceiveDialogFragment") - } - } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogFragment.kt b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogFragment.kt new file mode 100644 index 00000000..6cfb2a19 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/receive/ReceiveDialogFragment.kt @@ -0,0 +1,66 @@ +package com.brainwallet.ui.screens.home.receive + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.unit.dp +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.viewModels +import com.brainwallet.ui.theme.BrainwalletAppTheme +import org.koin.compose.viewmodel.koinViewModel + +/** + * describe [ReceiveDialogFragment] for backward compat, + * since we are still using [com.brainwallet.presenter.activities.BreadActivity] + */ +class ReceiveDialogFragment : DialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return ComposeView(requireContext()).apply { + setContent { + val viewModel = koinViewModel() + val appSetting by viewModel.appSetting.collectAsState() + /** + * we need this theme inside this fragment, + * because we are still using fragment to display ReceiveDialog composable + * pls check BreadActivity.handleNavigationItemSelected + */ + BrainwalletAppTheme(appSetting = appSetting) { + ReceiveDialog( + modifier = Modifier.padding(12.dp), + viewModel = viewModel, + onDismissRequest = { dismiss() } + ) + } + } + } + } + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + dialog?.window?.setBackgroundDrawableResource(android.R.color.transparent) + isCancelable = false + } + + companion object { + @JvmStatic + fun show(manager: FragmentManager) { + ReceiveDialogFragment().show(manager, "ReceiveDialogFragment") + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt index c83406f9..bd090257 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt @@ -1,16 +1,15 @@ package com.brainwallet.ui.screens.unlock -import android.content.Context - sealed class UnLockEvent { data class OnLoad( - val context: Context, val isUpdatePin: Boolean = false, ) : UnLockEvent() data class OnPinDigitChange( val digit: Int, val isValidPin: (String) -> Boolean ) : UnLockEvent() + object OnToggleDarkMode : UnLockEvent() + object OnQrClicked : UnLockEvent() object OnDeletePinDigit : UnLockEvent() } diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt index 0ea4da7e..204716e8 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt @@ -2,168 +2,105 @@ package com.brainwallet.ui.screens.unlock - -import android.widget.Toast -import androidx.compose.foundation.Image +import androidx.activity.ComponentActivity +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp +import androidx.fragment.app.FragmentActivity import com.brainwallet.R +import com.brainwallet.data.model.AppSetting import com.brainwallet.navigation.OnNavigate import com.brainwallet.navigation.UiEffect -import com.brainwallet.tools.manager.AnalyticsManager -import com.brainwallet.tools.security.AuthManager -import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.composable.BrainwalletScaffold -import com.brainwallet.ui.composable.BrainwalletTopAppBar -import com.brainwallet.ui.composable.PasscodeIndicator -import com.brainwallet.ui.composable.PasscodeKeypad -import com.brainwallet.ui.composable.PasscodeKeypadEvent -import com.brainwallet.ui.theme.BrainwalletTheme -import org.koin.compose.koinInject +import com.brainwallet.ui.screens.home.receive.ReceiveDialogFragment +import com.brainwallet.ui.screens.unlock.components.UnLockScreenBody +import com.brainwallet.ui.screens.unlock.components.UnLockScreenFooter +import com.brainwallet.ui.screens.unlock.components.UnLockScreenHeader +import com.brainwallet.ui.theme.BrainwalletAppTheme +import org.koin.compose.viewmodel.koinViewModel @Composable fun UnLockScreen( onNavigate: OnNavigate, + modifier: Modifier = Modifier, isUpdatePin: Boolean = false, - viewModel: UnLockViewModel = koinInject() + viewModel: UnLockViewModel = koinViewModel() ) { - val state by viewModel.state.collectAsState() - val context = LocalContext.current - + val fragmentManager = (LocalContext.current as? FragmentActivity)?.supportFragmentManager + val uiState by viewModel.state.collectAsState() LaunchedEffect(Unit) { - viewModel.onEvent(UnLockEvent.OnLoad(context, isUpdatePin)) + viewModel.onEvent(UnLockEvent.OnLoad(isUpdatePin)) viewModel.uiEffect.collect { effect -> when (effect) { is UiEffect.Navigate -> onNavigate.invoke(effect) + is UiEffect.ShowMoonPayDialog -> fragmentManager?.let { + ReceiveDialogFragment.show(it) + } else -> Unit } } } + UnLockScreen(uiState = uiState, modifier = modifier, onEvent = viewModel::onEvent) +} - LaunchedEffect(state.passcode.all { it > -1 }) { +@Composable +private fun UnLockScreen( + uiState: UnLockState, + modifier: Modifier = Modifier, + onEvent: (UnLockEvent) -> Unit = {}, +) { + LaunchedEffect(uiState.passcode.all { it > -1 }) { // } - - /// Layout values - val columnPadding = 18 val horizontalVerticalSpacing = 8 - BrainwalletScaffold( + modifier = modifier, topBar = { - BrainwalletTopAppBar( - navigationIcon = { - /// No-op Retained spacing for remote banner - }) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .padding(columnPadding.dp) - .fillMaxSize() - .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), - ) { - - Image( - modifier = Modifier - .fillMaxWidth(0.80f) - .padding(horizontalVerticalSpacing.dp), - painter = painterResource(R.drawable.brainwallet_logotype_white), - contentDescription = stringResource(R.string.logo), - colorFilter = ColorFilter.tint( - BrainwalletTheme.colors.content, + UnLockScreenHeader( + modifier = Modifier.padding(16.dp), + formattedLtcPrice = stringResource( + R.string.Login_ltcPrice, + uiState.formattedCurrency ), ) - Spacer(modifier = Modifier.weight(1f)) - - if (state.isUpdatePin) { - Text(stringResource(R.string.UpdatePin_enterCurrent)) - } else { - Text(stringResource(R.string.Login_ltcPrice, state.formattedCurrency)) - Text(stringResource(R.string.Login_currentLtcPrice, state.iso)) - } - - // TODO - // https://developer.android.com/develop/ui/compose/animation/customize - // Box( - // modifier = Modifier - // .fillMaxWidth() - // .height(100.dp) - // .background(Color.White) - // ) { - // //todo - // Text("todo") - // } - - Spacer(modifier = Modifier.weight(1f)) - - PasscodeIndicator(passcode = state.passcode) - - Spacer(Modifier.height(16.dp)) - - PasscodeKeypad { passcodeKeypadEvent -> - when (passcodeKeypadEvent) { - PasscodeKeypadEvent.OnDelete -> viewModel.onEvent(UnLockEvent.OnDeletePinDigit) - is PasscodeKeypadEvent.OnPressed -> viewModel.onEvent( - UnLockEvent.OnPinDigitChange( - digit = passcodeKeypadEvent.digit, - isValidPin = { pin -> - - //provide old logic here, its like on the BrainwalletActivity.onUnlock - return@OnPinDigitChange AuthManager.getInstance() - .checkAuth(pin, context).also { isValid -> - if (isValid) { - AuthManager.getInstance().authSuccess(context) - AnalyticsManager.logCustomEvent(BRConstants._20200217_DUWB) - AnalyticsManager.logCustomEvent(BRConstants._20200217_DUWB) - - } else { - AuthManager.getInstance().authFail(context) - //for now just toast - Toast.makeText( - context, - R.string.incorrect_passcode, - Toast.LENGTH_SHORT - ).show() - } - } - } - ) - ) - } - } - - Spacer(modifier = Modifier.weight(1f)) - - //app version - Text( - text = BRConstants.APP_VERSION_NAME_CODE, - style = MaterialTheme.typography.bodyMedium.copy(textAlign = TextAlign.Center) + }, + bottomBar = { + UnLockScreenFooter( + uiState.formattedVersion, + modifier = Modifier.padding(bottom = 26.dp), + onEvent = onEvent ) } + ) { paddingValues -> + UnLockScreenBody( + passcode = uiState.passcode, + isUpdatePin = uiState.isUpdatePin, + verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), + modifier = Modifier.padding(paddingValues) + .padding(top = 16.dp), + onEvent = onEvent + ) + } +} + +@PreviewLightDark +@Composable +private fun UnLockScreenPreview() { + BrainwalletAppTheme(appSetting = AppSetting(isDarkMode = isSystemInDarkTheme())) { + UnLockScreen(uiState = UnLockState( + isUpdatePin = true, + formattedCurrency = "$90.00", + formattedVersion = "v4.0.0 (202501201)" + )) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt index ff12dab1..7483e3ab 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt @@ -6,6 +6,7 @@ data class UnLockState( val iso: String = "USD", val formattedCurrency: String = "", val isUpdatePin: Boolean = false, + val formattedVersion: String = "" ) fun UnLockState.isPasscodeFilled(): Boolean = passcode.all { it > -1 } diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt index 30e3274a..0405c4ba 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt @@ -1,17 +1,18 @@ package com.brainwallet.ui.screens.unlock import androidx.lifecycle.viewModelScope +import com.brainwallet.data.repository.SettingRepository import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect -import com.brainwallet.tools.manager.BRSharedPrefs -import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.tools.util.BRConstants -import com.brainwallet.tools.util.BRCurrency import com.brainwallet.ui.BrainwalletViewModel +import com.brainwallet.util.CurrencyDataGetter import com.brainwallet.util.EventBus +import com.brainwallet.util.VersionCodeProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch @@ -20,9 +21,14 @@ import timber.log.Timber import java.math.BigDecimal @KoinViewModel -class UnLockViewModel : BrainwalletViewModel() { +class UnLockViewModel( + versionCodeProvider: VersionCodeProvider, + private val settingRepository: SettingRepository, + private val currencyDataGetter: CurrencyDataGetter +) : BrainwalletViewModel() { - private val _state = MutableStateFlow(UnLockState()) + private val _state = + MutableStateFlow(UnLockState(formattedVersion = versionCodeProvider.getFormatted())) val state: StateFlow = _state.asStateFlow() override fun onEvent(event: UnLockEvent) { @@ -73,17 +79,16 @@ class UnLockViewModel : BrainwalletViewModel() { } is UnLockEvent.OnLoad -> { - val iso = BRSharedPrefs.getIsoSymbol(event.context) + val iso = currencyDataGetter.getIsoSymbol() var formattedCurrency: String? = null - val currency = CurrencyDataSource.getInstance(event.context).getCurrencyByIso(iso) + val currency = currencyDataGetter.getCurrencyByIso(iso) if (currency != null) { val roundedPriceAmount: BigDecimal = BigDecimal(currency.rate.toDouble()).multiply(BigDecimal(100)) .divide(BigDecimal(100), 2, BRConstants.ROUNDING_MODE) formattedCurrency = - BRCurrency.getFormattedCurrencyString( - event.context, + currencyDataGetter.getFormattedCurrencyString( iso, roundedPriceAmount ) @@ -102,6 +107,16 @@ class UnLockViewModel : BrainwalletViewModel() { } } } + + UnLockEvent.OnToggleDarkMode -> viewModelScope.launch { + settingRepository.settings.firstOrNull()?.let { + settingRepository.save( + it.copy(isDarkMode = it.isDarkMode.not()) + ) + } + } + + UnLockEvent.OnQrClicked -> sendUiEffect(UiEffect.ShowMoonPayDialog) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenBody.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenBody.kt new file mode 100644 index 00000000..cdf2f09c --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenBody.kt @@ -0,0 +1,111 @@ +package com.brainwallet.ui.screens.unlock.components + +import android.widget.Toast +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.tools.manager.AnalyticsManager +import com.brainwallet.tools.security.AuthManager +import com.brainwallet.tools.util.BRConstants +import com.brainwallet.ui.composable.PasscodeIndicator +import com.brainwallet.ui.composable.PasscodeKeypad +import com.brainwallet.ui.composable.PasscodeKeypadEvent +import com.brainwallet.ui.screens.unlock.UnLockEvent +import com.brainwallet.ui.theme.BrainwalletAppTheme +import com.brainwallet.ui.theme.BrainwalletTheme +import com.google.common.collect.ImmutableList + +@Composable +fun UnLockScreenBody( + passcode: List, + isUpdatePin: Boolean, + modifier: Modifier = Modifier, + verticalArrangement: Arrangement.Vertical = Arrangement.Center, + onEvent: (UnLockEvent) -> Unit = {} +) { + val context = LocalContext.current + Column( + modifier = modifier + .padding(18.dp) + .fillMaxSize() + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = verticalArrangement, + ) { + AnimatedVisibility(isUpdatePin) { + Text( + stringResource(R.string.UpdatePin_enterCurrent), + modifier = Modifier + ) + } + Spacer(modifier = Modifier.weight(1f)) + PasscodeIndicator(passcode = passcode, modifier = Modifier) + Spacer(modifier = Modifier.weight(1f)) + PasscodeKeypad { passcodeKeypadEvent -> + when (passcodeKeypadEvent) { + PasscodeKeypadEvent.OnDelete -> onEvent(UnLockEvent.OnDeletePinDigit) + is PasscodeKeypadEvent.OnPressed -> onEvent( + UnLockEvent.OnPinDigitChange( + digit = passcodeKeypadEvent.digit, + isValidPin = { pin -> + + //provide old logic here, its like on the BrainwalletActivity.onUnlock + return@OnPinDigitChange AuthManager.getInstance() + .checkAuth(pin, context).also { isValid -> + if (isValid) { + AuthManager.getInstance().authSuccess(context) + AnalyticsManager.logCustomEvent(BRConstants._20200217_DUWB) + AnalyticsManager.logCustomEvent(BRConstants._20200217_DUWB) + + } else { + AuthManager.getInstance().authFail(context) + //for now just toast + Toast.makeText( + context, + R.string.incorrect_passcode, + Toast.LENGTH_SHORT + ).show() + } + } + } + ) + ) + } + } + Spacer(modifier = Modifier.weight(1f)) + } +} + +@PreviewLightDark +@Composable +private fun UnLockScreenBodyPreview() { + BrainwalletAppTheme(AppSetting(isDarkMode = isSystemInDarkTheme())) { + Box( + modifier = Modifier + .background(BrainwalletTheme.colors.background) + .fillMaxWidth() + ) { + UnLockScreenBody(isUpdatePin = true, passcode = ImmutableList.of(1, 2)) + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenFooter.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenFooter.kt new file mode 100644 index 00000000..733f2068 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenFooter.kt @@ -0,0 +1,89 @@ +package com.brainwallet.ui.screens.unlock.components + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.ui.composable.DarkModeToggleButton +import com.brainwallet.ui.screens.unlock.UnLockEvent +import com.brainwallet.ui.theme.BrainwalletAppTheme +import com.brainwallet.ui.theme.BrainwalletTheme +import com.brainwallet.ui.theme.LocalDarkModeFlag + +@Composable +fun UnLockScreenFooter( + version: String, + modifier: Modifier = Modifier, + onEvent: (UnLockEvent) -> Unit = {} +) { + Column( + modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row(modifier = Modifier + .padding(bottom = 24.dp) + .padding(horizontal = 85.dp)) { + DarkModeToggleButton( + checked = LocalDarkModeFlag.current, + onCheckedChange = { + onEvent(UnLockEvent.OnToggleDarkMode) + }, + iconButtonSizeInDp = 43 + ) + Spacer(modifier = Modifier.weight(1f)) + Image( + painterResource(R.drawable.ic_clickable_qr), + contentDescription = "clickable_qr", + modifier = Modifier.size(39.dp).clickable { + onEvent(UnLockEvent.OnQrClicked) + }, + colorFilter = ColorFilter.tint( + BrainwalletTheme.colors.border + ) + ) + } + Text( + version, + modifier = Modifier.fillMaxWidth(), + style = MaterialTheme.typography + .bodyMedium + .copy( + textAlign = TextAlign.Center, + color = BrainwalletTheme.colors.border + ) + ) + } +} + +@PreviewLightDark +@Composable +private fun UnLockScreenFooterPreview() { + BrainwalletAppTheme(AppSetting(isDarkMode = isSystemInDarkTheme())) { + Box( + modifier = Modifier + .background(BrainwalletTheme.colors.background) + .fillMaxWidth() + ) { + UnLockScreenFooter(version = "v4.0.0 (202501201)") + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenHeader.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenHeader.kt new file mode 100644 index 00000000..81aa128e --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/components/UnLockScreenHeader.kt @@ -0,0 +1,51 @@ +package com.brainwallet.ui.screens.unlock.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import com.brainwallet.data.model.AppSetting +import com.brainwallet.ui.composable.BrainWalletLogo +import com.brainwallet.ui.theme.BrainwalletAppTheme +import com.brainwallet.ui.theme.BrainwalletTheme + +@Composable +fun UnLockScreenHeader( + formattedLtcPrice: String, + modifier: Modifier = Modifier, +) { + Column( + modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + modifier = Modifier + .padding(bottom = 52.dp) + .fillMaxWidth(), + text = formattedLtcPrice, + textAlign = TextAlign.End, + color = BrainwalletTheme.colors.border + ) + BrainWalletLogo(modifier = Modifier.width(268.dp)) + } +} + +@PreviewLightDark +@Composable +private fun UnLockScreenHeaderPreview() { + BrainwalletAppTheme(appSetting = AppSetting(isDarkMode = isSystemInDarkTheme())) { + Box(modifier = Modifier.background(BrainwalletTheme.colors.background)) { + UnLockScreenHeader(formattedLtcPrice = "100") + } + } +} diff --git a/app/src/main/java/com/brainwallet/ui/theme/Theme.kt b/app/src/main/java/com/brainwallet/ui/theme/Theme.kt index 36afabbe..9b421ce5 100644 --- a/app/src/main/java/com/brainwallet/ui/theme/Theme.kt +++ b/app/src/main/java/com/brainwallet/ui/theme/Theme.kt @@ -59,6 +59,10 @@ val LocalLanguageCode = staticCompositionLocalOf { Language.ENGLISH.code //default } +val LocalDarkModeFlag = staticCompositionLocalOf { + false +} + @Composable fun BrainwalletAppTheme( appSetting: AppSetting = AppSetting(), @@ -68,7 +72,8 @@ fun BrainwalletAppTheme( CompositionLocalProvider( LocalBrainwalletColors provides colors, - LocalLanguageCode provides appSetting.languageCode + LocalLanguageCode provides appSetting.languageCode, + LocalDarkModeFlag provides appSetting.isDarkMode, ) { MaterialTheme( typography = AppTypography, diff --git a/app/src/main/java/com/brainwallet/util/CurrencyDataGetter.kt b/app/src/main/java/com/brainwallet/util/CurrencyDataGetter.kt new file mode 100644 index 00000000..4c6ebf21 --- /dev/null +++ b/app/src/main/java/com/brainwallet/util/CurrencyDataGetter.kt @@ -0,0 +1,41 @@ +package com.brainwallet.util + +import android.content.Context +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.tools.util.BRCurrency +import org.koin.core.annotation.Single +import java.math.BigDecimal + +@Single +class CurrencyDataGetter( + private val context: Context, + private val currencyDataSource: CurrencyDataSource = CurrencyDataSource.getInstance(context), + private val isoSymbolGetter: (Context) -> String = { BRSharedPrefs.getIsoSymbol(context) }, + private val formattedCurrencyStringGetter: (Context, String, BigDecimal) -> String? = + { context, isoCurrencyCode, amount -> + BRCurrency.getFormattedCurrencyString( + context, + isoCurrencyCode, + amount + ) + } +) { + fun getIsoSymbol(): String { + return isoSymbolGetter.invoke(context) + } + + fun getCurrencyByIso( + iso: String + ): CurrencyEntity? { + return currencyDataSource.getCurrencyByIso(iso) + } + + fun getFormattedCurrencyString( + isoCurrencyCode: String, + amount: BigDecimal + ): String? { + return formattedCurrencyStringGetter.invoke(context, isoCurrencyCode, amount) + } +} diff --git a/app/src/main/java/com/brainwallet/util/VersionCodeProvider.kt b/app/src/main/java/com/brainwallet/util/VersionCodeProvider.kt new file mode 100644 index 00000000..264ccccf --- /dev/null +++ b/app/src/main/java/com/brainwallet/util/VersionCodeProvider.kt @@ -0,0 +1,22 @@ +package com.brainwallet.util + +import com.brainwallet.BuildConfig +import org.koin.core.annotation.Factory + +@Factory +class VersionCodeProvider( + private val versionCodeGetter: () -> Int = { BuildConfig.VERSION_CODE }, + private val versionNameGetter: () -> String = { BuildConfig.VERSION_NAME } +) { + fun getVersionCode(): Int { + return versionCodeGetter() + } + + fun getVersionName(): String { + return versionNameGetter() + } + + fun getFormatted(): String { + return "${getVersionName()} (${getVersionCode()})" + } +} diff --git a/app/src/main/res/drawable-hdpi/brainwallet_logotype_color.webp b/app/src/main/res/drawable-hdpi/brainwallet_logotype_color.webp new file mode 100644 index 0000000000000000000000000000000000000000..dfc5fa0c709b7da9189d124d4cedf18856119927 GIT binary patch literal 13554 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 s&Z7rKus@Ap!JZKS09Veh*`5D^m~k1Z23 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�zD;yOR#mu6nn2tCES=Q} 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 E0Nd0`YXATM literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/brainwallet_logotype_color.webp b/app/src/main/res/drawable-xhdpi/brainwallet_logotype_color.webp new file mode 100644 index 0000000000000000000000000000000000000000..acc02566264fa4722eec1444c899c54a7bbddc74 GIT binary patch literal 20550 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�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�wLzFQv`q`f7}Cl>lr|a z5do0-p@%YHkTY_fA|NXH@E!*Q+sFw6riMfSmGfM;Sv;ZsYo{=?YL=&MJ`EdyKO!R6;?0^$C?U*O zcQl2S^`jQ1x2Y=Ob}7HfUv_T_2v%_hR2Ww(nqdYtRYc}Q1cYrsTmrDDB&U^d9^hvn ztOJ~j0P>GmUnKHTUY`=KD^VQ4S%4=&SQrucQ);PLa~R*(0Hm%(h5-Ci!W{so(QyKx zML^tNvj~Vf5Qc|oK1KCGiF}IX7DHL~;NQv)A|Uw!Q?u9i)B zH3jTJ(3ld1KynlW>j0GjE@Tvd$>NwPd$%Nrlun~>knI$BT#A$se1{2Ax`9Y2v{{-8?*HCW0(g)@ z+*MGp8D<4KKJbu8IrLJ8N|6$zJ^;sS&8F6_q-1aJC?X@*{85HP1Y{SK+D>OXN$IAR z%2e77$b-A@PbENZfq;rgX|0EVsHK*gQV6hyQIPW{MWh@7ggGQ408%AqwwoNJU;zIw z1t7zp4QCc!G!dXqcM$>91-e4^c9PQV%Voj}TLn3}Ql#AS^L~^eky0%u)jgL{aTFB| zrHJKcXlib3*FpDbWH5EToH6TO(Qk4I)u&fs>^lH81X6U#5|He=yVM|*8zk%GXdqiC%sE!16_ow8?p}C2)k!y4!j8FwmVZwwzTYwYWHD&!S}S+k4(ak z%$y(jDX&i`w#pm>-}9ln=Ev6DGS3SkX5Z%|Ke7|csC=?>Uaa>!d|y@k$W1O=_WQe5 zT5_nlW$`03O^)VAF3}yE9^TcML4M@NmidvL^XKXS+j$hccWv3j@Mqe=Za$@vyGG3S z{{6Y-VP@|32LNzg1&bkSAA}bGTt8EgI#ifb5X|n61~3tbDJmMhO0){1QxIlv8AN9a zT2`TXeX0^SsaY5$*XpkMo*&{gzGwUH+A=?KGkz2mrb1_m3bP+@Hb9sH;0nO(BUcNT zm2{7CLt-M|v&cvDK;QyMo`Ns~;1vkdAeB^JkEmcOTY;5bcWs#;xmj;+%C<_(fFH%l zWy^d|$GY1na;cfIEnDVCA<-3&G`8|7*p+AJmM!x=H`_htW%emfFC$Z)2{=4$Sl|CL zKQi;a7hFsQAvE7>Lm+$i13sH)3QHcVU~&HjR%oNZ1@dnhD@rj7!i&}r6J}E~$lGi{ zSPlZ6yhlCgk3m@pskRB6UghH|fMpQOE!3r}z%8qCp8($qsGBOPj0xb>DqMyxWx=;H z+Lez159lh4gBLpL_66XA(-Ja*6$>KFYFNYelc{F{lC=ru4DcX4eX9X3nGq{3s*GpH z-4wtkY})}$5J157&B+;=ZXT3p?lLwiRv>Jer51eBTG#&$07llSp?7;bNdP4cGO2-2 z6qrkv?7Un^2^<3hN3Pa8qS8akBgD*XCq5Ct6Fl zW$%m8_O*#3>}de^SQ?q7<`Kk{AtUEbk1d7wWKcDlE)8Cyr0FnV+bp$$-vscU67scT ZH4=+Y60!1617J@ENE@*k6^j-g)W$1t_z3_2 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/brainwallet_logotype_color.webp b/app/src/main/res/drawable-xxhdpi/brainwallet_logotype_color.webp new file mode 100644 index 0000000000000000000000000000000000000000..868fac8e4cc207b1df65fdb27375b1457aca143c GIT binary patch literal 35226 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 + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8323d2ac..443eee4f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -740,7 +740,7 @@ Balance - 1 LTC = %1$s + %1$s = 1Ł Current LTC value in %1$s Languages Are you sure you want to change the language to English? diff --git a/app/src/test/java/com/brainwallet/ui/screens/unlock/UnLockViewModelTest.kt b/app/src/test/java/com/brainwallet/ui/screens/unlock/UnLockViewModelTest.kt new file mode 100644 index 00000000..fe266cc9 --- /dev/null +++ b/app/src/test/java/com/brainwallet/ui/screens/unlock/UnLockViewModelTest.kt @@ -0,0 +1,359 @@ +package com.brainwallet.ui.screens.unlock + +import app.cash.turbine.test +import com.brainwallet.data.model.AppSetting +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.navigation.Route +import com.brainwallet.navigation.UiEffect +import com.brainwallet.util.CurrencyDataGetter +import com.brainwallet.util.EventBus +import com.brainwallet.util.MainDispatcherRule +import com.brainwallet.util.VersionCodeProvider +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.mockkObject +import io.mockk.unmockkAll +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class UnLockViewModelTest { + + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + + @MockK + private lateinit var mockVersionCodeProvider: VersionCodeProvider + + @MockK + private lateinit var mockSettingRepository: SettingRepository + + @RelaxedMockK + private lateinit var mockCurrencyDataGetter: CurrencyDataGetter + + private lateinit var viewModel: UnLockViewModel + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxUnitFun = true) + every { mockVersionCodeProvider.getFormatted() } returns "v4.7.1" + + viewModel = UnLockViewModel( + versionCodeProvider = mockVersionCodeProvider, + settingRepository = mockSettingRepository, + currencyDataGetter = mockCurrencyDataGetter + ) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given viewModel initialization when created then state contains formatted version`() = + runTest { + viewModel.state.test { + val initialState = awaitItem() + + assert(initialState.formattedVersion == "v4.7.1") { + "Expected formatted version to be 'v4.7.1' but was '${initialState.formattedVersion}'" + } + assert(initialState.passcode == List(4) { -1 }) { + "Expected passcode to be empty list of -1 values but was '${initialState.passcode}'" + } + assert(initialState.iso == "USD") { + "Expected default ISO to be 'USD' but was '${initialState.iso}'" + } + assert(!initialState.isUpdatePin) { + "Expected isUpdatePin to be false but was '${initialState.isUpdatePin}'" + } + } + } + + @Test + fun `given valid pin digit when OnPinDigitChange event then passcode updates correctly`() = + runTest { + viewModel.state.test { + awaitItem() // Skip initial state + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 5, isValidPin = { false })) + + val updatedState = awaitItem() + assert(updatedState.passcode[0] == 5) { + "Expected first digit to be 5 but was '${updatedState.passcode[0]}'" + } + assert(updatedState.passcode.drop(1).all { it == -1 }) { + "Expected remaining digits to be -1 but were '${updatedState.passcode.drop(1)}'" + } + } + } + + @Test + fun `given multiple pin digits when OnPinDigitChange events then passcode fills sequentially`() = + runTest { + viewModel.state.test { + awaitItem() + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 1, isValidPin = { false })) + awaitItem() + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 2, isValidPin = { false })) + awaitItem() + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 3, isValidPin = { false })) + val thirdDigitState = awaitItem() + + assert(thirdDigitState.passcode == listOf(1, 2, 3, -1)) { + "Expected passcode to be [1, 2, 3, -1] but was '${thirdDigitState.passcode}'" + } + } + } + + @Test + fun `given invalid digit when OnPinDigitChange with digit less than -1 then passcode remains unchanged`() = + runTest { + viewModel.state.test { + val initialState = awaitItem() + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = -5, isValidPin = { false })) + + expectNoEvents() + assert(initialState.passcode == List(4) { -1 }) { + "Expected passcode to remain unchanged but was modified" + } + } + } + + @Test + fun `given full passcode when OnPinDigitChange then no additional digits accepted`() = runTest { + viewModel.state.test { + awaitItem() + + repeat(4) { index -> + viewModel.onEvent( + UnLockEvent.OnPinDigitChange( + digit = index + 1, + isValidPin = { false }) + ) + awaitItem() + } + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 9, isValidPin = { false })) + + expectNoEvents() + } + } + + @Test + fun `given filled passcode in update mode with valid pin when OnPinDigitChange then navigates to SetPasscode`() = + runTest { + mockkObject(EventBus) + + viewModel.state.test { + awaitItem() + + viewModel.onEvent(UnLockEvent.OnLoad(isUpdatePin = true)) + awaitItem() + + repeat(3) { index -> + viewModel.onEvent( + UnLockEvent.OnPinDigitChange( + digit = index + 1, + isValidPin = { true }) + ) + awaitItem() + } + + viewModel.onEvent( + UnLockEvent.OnPinDigitChange( + digit = 4, + isValidPin = { true }) + ) + awaitItem() + } + + viewModel.uiEffect.test { + val effect = awaitItem() + assert(effect is UiEffect.Navigate) { + "Expected Navigate effect but was '${effect::class.simpleName}'" + } + val navigateEffect = effect as UiEffect.Navigate + assert(navigateEffect.destinationRoute is Route.SetPasscode) { + "Expected navigation to SetPasscode but was '${ + navigateEffect.destinationRoute!!::class.simpleName + }'" + } + } + } + + @Test + fun `given filled passcode in normal mode when OnPinDigitChange then emits LegacyUnLock event`() = + runTest { + mockkObject(EventBus) + coEvery { EventBus.emit(any()) } returns Unit + + viewModel.state.test { + awaitItem() + + repeat(3) { index -> + viewModel.onEvent( + UnLockEvent.OnPinDigitChange( + digit = index + 1, + isValidPin = { false }) + ) + awaitItem() + } + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 4, isValidPin = { false })) + awaitItem() + } + + testScheduler.advanceUntilIdle() + + coVerify { + EventBus.emit(match { event -> + event.passcode == listOf(1, 2, 3, 4) + }) + } + } + + @Test + fun `given passcode with digits when OnDeletePinDigit then removes last entered digit`() = + runTest { + viewModel.state.test { + awaitItem() + + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 7, isValidPin = { false })) + awaitItem() + viewModel.onEvent(UnLockEvent.OnPinDigitChange(digit = 8, isValidPin = { false })) + awaitItem() + + viewModel.onEvent(UnLockEvent.OnDeletePinDigit) + val stateAfterDelete = awaitItem() + + assert(stateAfterDelete.passcode == listOf(7, -1, -1, -1)) { + "Expected passcode to be [7, -1, -1, -1] after deletion but was '${stateAfterDelete.passcode}'" + } + } + } + + @Test + fun `given empty passcode when OnDeletePinDigit then passcode remains unchanged`() = runTest { + viewModel.state.test { + val initialState = awaitItem() + + viewModel.onEvent(UnLockEvent.OnDeletePinDigit) + + expectNoEvents() + assert(initialState.passcode == List(4) { -1 }) { + "Expected empty passcode to remain unchanged after delete" + } + } + } + + @Test + fun `given OnLoad event with context when processed then updates state with currency information`() = + runTest { + val mockCurrency = CurrencyEntity(rate = 1.2f) + + every { mockCurrencyDataGetter.getIsoSymbol() } returns "EUR" + every { mockCurrencyDataGetter.getCurrencyByIso("EUR") } returns mockCurrency + every { + mockCurrencyDataGetter.getFormattedCurrencyString( + "EUR", + any() + ) + } returns "€1.20" + + viewModel.state.test { + awaitItem() + + viewModel.onEvent(UnLockEvent.OnLoad(isUpdatePin = false)) + + val updatedState = awaitItem() + assert(updatedState.iso == "EUR") { + "Expected ISO to be 'EUR' but was '${updatedState.iso}'" + } + assert(updatedState.formattedCurrency == "€1.20") { + "Expected formatted currency to be '€1.20' but was '${updatedState.formattedCurrency}'" + } + assert(updatedState.isUpdatePin == false) { + "Expected isUpdatePin to be false but was '${updatedState.isUpdatePin}'" + } + } + } + + + @Test + fun `given OnLoad event with null currency when processed then state remains unchanged`() = + runTest { + every { mockCurrencyDataGetter.getIsoSymbol() } returns "INVALID" + every { mockCurrencyDataGetter.getCurrencyByIso("INVALID") } returns null + + viewModel.state.test { + val initialState = awaitItem() + + viewModel.onEvent(UnLockEvent.OnLoad(isUpdatePin = false)) + + expectNoEvents() + assert(initialState.iso == "USD") { + "Expected ISO to remain 'USD' when currency is null" + } + } + } + + @Test + fun `given OnToggleDarkMode event when settings exist then toggles dark mode setting`() = + runTest { + val mockSettings = AppSetting(isDarkMode = false) + + coEvery { mockSettingRepository.settings } returns flowOf(mockSettings) + coEvery { mockSettingRepository.save(any()) } returns Unit + + viewModel.onEvent(UnLockEvent.OnToggleDarkMode) + testScheduler.advanceUntilIdle() + + coVerify { + mockSettingRepository.save(match { it.isDarkMode }) + } + } + + @Test + fun `given OnQrClicked event when processed then sends ShowMoonPayDialog effect`() = runTest { + viewModel.onEvent(UnLockEvent.OnQrClicked) + + viewModel.uiEffect.test { + val effect = awaitItem() + assert(effect is UiEffect.ShowMoonPayDialog) { + "Expected ShowMoonPayDialog effect but was '${effect::class.simpleName}'" + } + } + } + + @Test + fun `given isPasscodeFilled extension when all digits are filled then returns true`() { + val filledState = UnLockState(passcode = listOf(1, 2, 3, 4)) + assert(filledState.isPasscodeFilled()) { + "Expected isPasscodeFilled to return true for filled passcode" + } + } + + @Test + fun `given isPasscodeFilled extension when passcode has empty digits then returns false`() { + val partialState = UnLockState(passcode = listOf(1, 2, -1, -1)) + assert(!partialState.isPasscodeFilled()) { + "Expected isPasscodeFilled to return false for partially filled passcode" + } + } +} diff --git a/app/src/test/java/com/brainwallet/util/CurrencyDataGetterTest.kt b/app/src/test/java/com/brainwallet/util/CurrencyDataGetterTest.kt new file mode 100644 index 00000000..0bdf4cd0 --- /dev/null +++ b/app/src/test/java/com/brainwallet/util/CurrencyDataGetterTest.kt @@ -0,0 +1,125 @@ +package com.brainwallet.util + +import android.content.Context +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.tools.sqlite.CurrencyDataSource +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.unmockkAll +import io.mockk.verify +import org.junit.After +import org.junit.Before +import org.junit.Test +import java.math.BigDecimal + +class CurrencyDataGetterTest { + + @MockK + private lateinit var mockContext: Context + + @MockK + private lateinit var mockCurrencyDataSource: CurrencyDataSource + + @MockK + private lateinit var mockIsoSymbolGetter: (Context) -> String + + @MockK + private lateinit var mockFormattedCurrencyStringGetter: (Context, String, BigDecimal) -> String? + + private lateinit var currencyDataGetter: CurrencyDataGetter + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxUnitFun = true) + currencyDataGetter = CurrencyDataGetter( + context = mockContext, + currencyDataSource = mockCurrencyDataSource, + isoSymbolGetter = mockIsoSymbolGetter, + formattedCurrencyStringGetter = mockFormattedCurrencyStringGetter + ) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given valid context when getting iso symbol then returns expected symbol`() { + val expectedIsoSymbol = "USD" + every { mockIsoSymbolGetter.invoke(mockContext) } returns expectedIsoSymbol + + val actualIsoSymbol = currencyDataGetter.getIsoSymbol() + assert(actualIsoSymbol == expectedIsoSymbol) { + "Expected ISO symbol to be '$expectedIsoSymbol' but was '$actualIsoSymbol'" + } + verify(exactly = 1) { mockIsoSymbolGetter.invoke(mockContext) } + } + + @Test + fun `given valid iso code when getting currency by iso then returns currency entity`() { + val isoCode = "EUR" + val expectedCurrency = CurrencyEntity().apply { + code = isoCode + name = "Euro" + } + every { mockCurrencyDataSource.getCurrencyByIso(isoCode) } returns expectedCurrency + + val actualCurrency = currencyDataGetter.getCurrencyByIso(isoCode) + + assert(actualCurrency == expectedCurrency) { + "Expected currency entity with code '$isoCode' but was '$actualCurrency'" + } + verify(exactly = 1) { mockCurrencyDataSource.getCurrencyByIso(isoCode) } + } + + @Test + fun `given invalid iso code when getting currency by iso then returns null`() { + val invalidIsoCode = "INVALID" + every { mockCurrencyDataSource.getCurrencyByIso(invalidIsoCode) } returns null + + val actualCurrency = currencyDataGetter.getCurrencyByIso(invalidIsoCode) + + assert(actualCurrency == null) { + "Expected null for invalid ISO code '$invalidIsoCode' but was '$actualCurrency'" + } + verify(exactly = 1) { mockCurrencyDataSource.getCurrencyByIso(invalidIsoCode) } + } + + @Test + fun `given valid currency code and amount when getting formatted string then returns formatted currency`() { + val currencyCode = "GBP" + val amount = BigDecimal("123.45") + val expectedFormattedString = "£123.45" + every { + mockFormattedCurrencyStringGetter.invoke(mockContext, currencyCode, amount) + } returns expectedFormattedString + + val actualFormattedString = currencyDataGetter.getFormattedCurrencyString(currencyCode, amount) + + assert(actualFormattedString == expectedFormattedString) { + "Expected formatted currency '$expectedFormattedString' but was '$actualFormattedString'" + } + verify(exactly = 1) { + mockFormattedCurrencyStringGetter.invoke(mockContext, currencyCode, amount) + } + } + + @Test + fun `given invalid currency code when getting formatted string then returns null`() { + val invalidCurrencyCode = "INVALID" + val amount = BigDecimal("100.00") + every { + mockFormattedCurrencyStringGetter.invoke(mockContext, invalidCurrencyCode, amount) + } returns null + val actualFormattedString = currencyDataGetter.getFormattedCurrencyString(invalidCurrencyCode, amount) + + assert(actualFormattedString == null) { + "Expected null for invalid currency code '$invalidCurrencyCode' but was '$actualFormattedString'" + } + verify(exactly = 1) { + mockFormattedCurrencyStringGetter.invoke(mockContext, invalidCurrencyCode, amount) + } + } +} diff --git a/app/src/test/java/com/brainwallet/util/MainDispatcherRule.kt b/app/src/test/java/com/brainwallet/util/MainDispatcherRule.kt new file mode 100644 index 00000000..a06c45c8 --- /dev/null +++ b/app/src/test/java/com/brainwallet/util/MainDispatcherRule.kt @@ -0,0 +1,23 @@ +package com.brainwallet.util + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule( + val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), +) : TestWatcher() { + override fun starting(description: Description) { + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + } +} diff --git a/app/src/test/java/com/brainwallet/util/VersionCodeProviderTest.kt b/app/src/test/java/com/brainwallet/util/VersionCodeProviderTest.kt new file mode 100644 index 00000000..31503883 --- /dev/null +++ b/app/src/test/java/com/brainwallet/util/VersionCodeProviderTest.kt @@ -0,0 +1,44 @@ +package com.brainwallet.util + +import io.mockk.every +import io.mockk.mockk +import junit.framework.TestCase.assertEquals +import org.junit.Test + +class VersionCodeProviderTest { + + @Test + fun `Given a version code, When getVersionCode called, Then return that version code`() { + val versionCodeGetter: () -> Int = mockk() + every { versionCodeGetter.invoke() } returns 123 + val provider = VersionCodeProvider(versionCodeGetter = versionCodeGetter) + + val result = provider.getVersionCode() + assertEquals(123, result) + } + + @Test + fun `Given a version name, When getVersionName called, Then return that version name`() { + val versionNameGetter: () -> String = mockk() + every { versionNameGetter.invoke() } returns "1.2.3" + val provider = VersionCodeProvider(versionNameGetter = versionNameGetter) + + val result = provider.getVersionName() + assertEquals("1.2.3", result) + } + + @Test + fun `Given version code and name, When getFormatted called, Then return formatted string`() { + val versionCodeGetter: () -> Int = mockk() + val versionNameGetter: () -> String = mockk() + every { versionCodeGetter.invoke() } returns 456 + every { versionNameGetter.invoke() } returns "2.0.0" + val provider = VersionCodeProvider( + versionCodeGetter = versionCodeGetter, + versionNameGetter = versionNameGetter + ) + + val result = provider.getFormatted() + assertEquals("2.0.0 (456)", result) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f1ff0cc4..f18f2b70 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,6 +33,8 @@ mockk = "1.13.13" koin-bom = "4.0.2" koin-annotation-bom = "2.1.0" ksp = "2.0.0-1.0.24" +turbine = "1.2.1" +coroutines = "1.10.2" [libraries] androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" } @@ -117,6 +119,9 @@ koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel" } koin-annotation-bom = { module = "io.insert-koin:koin-annotations-bom", version.ref = "koin-annotation-bom" } koin-annotation = { module = "io.insert-koin:koin-annotations" } koin-annotation-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-annotation-bom" } +turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } +kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } +kotlinx-coroutines-tests = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } [bundles] androidx-lifecycle = ["androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel", "androidx-lifecycle-viewmodel-compose"] From 7d8dd142aaf381106c27c02732a09f147f8b5f3e Mon Sep 17 00:00:00 2001 From: Josi Kie <54074780+josikie@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:29:46 +0700 Subject: [PATCH 59/65] Redesign welcome screen (#123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Redesign welcome screen * Redesign ready screen * 🚀[Release v4.7.2] Merge into Develop (#127) * 🚀[Release v4.4.7] Merge into Main (#70) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington --------- Co-authored-by: andhikayuana * 🚀[Release v4.5.0] Merge into Main (#78) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.5.4] Merge into Main (#87) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * Updated README * code bump * chore: open bread activity first then open moonpay widget (#88) * code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.5.5] Merge into Main (#101) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Update build.gradle.kts --------- Co-authored-by: andhikayuana * 🚀[Release v4.6.0] Merge into Main (#104) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * version bump * code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.6.1] Merge into Main (#107) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * updated metadata (#105) * chore: remove screen lock detection (#106) * build bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.6.2] Merge into Main (#110) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * updated metadata (#105) * chore: remove screen lock detection (#106) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * 🧰 Fx/seed words UI polish (#108) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * Removed unused audio files * polished tests * removed unused asset pack * code bump * code bump * ❇️ Feat/add polish punjabi farsi (#109) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * Removed unused audio files * polished tests * removed unused asset pack * code bump * broke out completion of the seed phrase and navigation - Feedback was a user could complete seed phrase and not tap "Game and Sync" - Forced users to start all over - Saved a correct seed phrase confirmation into memory * code bump * fix for https://console.firebase.google.com/project/brainwallet-mobile/crashlytics/app/android:ltd.grunt.brainwallet/issues/1386f366ab35e9112a6b742d629bb0be?time=last-seven-days&types=crash&sessionEventKey=685DA96C00BF00015A7AFEA30E0DB49C_2098799426616143441 * measure where users tap * code bump * fix: fix YourSeedProveItState.isWordUsedCorrectly * Cleaned commented out BuyLitecoinscreen * code bump --------- Co-authored-by: andhikayuana * 🚀[Release v4.7.0] Merge into Main (#115) * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * Add version and code to welcome screen * reset padding * Revert "Updated the APIManager" This reverts commit 4e252ac29cfb6c3ab26ae5ea4a8f6de154311f2e. # Conflicts: # app/src/main/java/com/brainwallet/tools/manager/APIManager.kt * Reverted the Kotlin APIManager. * fix: fix crash when FragmentSignal dismissed * fix: fix sync after wipe * fix: fix wrong lifecycle to trigger callback at FragmentSignal * Update issue templates * updated core changes per @andhikayuana * Rename .java to .kt * chore: refactor BRApiManager & APIClient * chore: remove unused part at APIClient * feat: wip new peer discovery * feat: implement selected peer ip address from cache (fetched from API) * feat: implement selected peer ip address from cache (fetched from API) * feat: filter out peers with NODE_NETWORK, NODE_BLOOM * fix: race condition when clear shared prefs values after wipeAll * Updating the core library from the new peer discovery (v4.2.0) * Chore/revert pre peer discovery (Android) (#69) * chore: update core submodule * chore: resolve conflict * Update build.gradle.kts version and code bump * chore: for now at BRPeerManager.wrapConnectV2 only using connect, since the core using hardcoded peers * fix: fix write down confirm screen (#63) * fix: fix write down confirm screen * fix: fix allow seed word item not unique * chore: cherry picked and adjust from - f2fa8e1e4fb9c7429fa86461b24b4463a7969ecf - 98644c425b2fdae7b8b424708fb1a61ad983a9d8 - 93969278da8f95adc0c9f0f8411c8a27876a4d77 - 7ad4b9853b7d1bf7ddbaa576242d8800615a48fb - 8e57d2a67420565b40b753dec5a533776da4821f * fix: fix crash can't parse response inside LtcRepository.fetchRates * fix: fix crash (failed parse) when SelectedPeersRepository.fetchSelectedPeers got unsuccessful response * code bump * fix: ConcurrentModificationException at BRPeerManager.txStatusUpdate * feat: implement new API * code bump --------- Co-authored-by: Kerry Washington * feat: remove unused activity (ImportActivity) at AndroidManifest.xml (#71) * fix: fix crash IllegalStateException: cannot make a new request because the previous response is still open (#73) * code bump * Feat/move tx fee (#74) * chore: add new translations at strings.xml * feat: move network fee to HomeSettingDrawerSheet & remove unused code * fix: fix dismiss allow state loss (#76) * fix: fix typo at strings.xml (#75) * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * version and code bump * Added support url (#81) - changed the language - code bump * version and code bump * Revert from eda0f532 & cherry pick (#86) * version bump * feat: new UI for receive and topup flow (moonpay integration) (#72) * feat: [WIP][UI] new UI for receive and topup flow * feat: [WIP][UI] implement copy address and some refactor * feat: replace webview using CustomTabsIntent from androidx.browser * feat: replace webview using CustomTabsIntent from androidx.browser * feat: add PickerWheel * chore: rename param at QRUtils.generateQR * chore: revert default startDestination at BrainwalletActivity * feat: wip moonpay integration * feat: wip moonpay integration * chore: new UI for ReceiveDialog * chore: parse error from response API at BrainwalletViewModel * chore: add /moonpay/buy-quote and remove dev base url * chore: make LegacyNavigation.showMoonPayWidget receive params for the widget url * chore: add GetMoonpayBuyQuoteResponse * chore: wip moonpay integration to call buy-quote * fix: fix wheel picker for IDR at ReceiveDialog * fix: fix invalid signature * feat: moonpay integration at onboarding flow at BuyLitecoinScreen also fix some stuffs * chore: replace base url for moonpay buy integration when debug * chore: introduce LocalCacheSource.kt and cache fetch limits * chore: adjustment receive dialog UI - debounce fiat currency to 2s - increment in 10 - remove decimal places - default value to 10% of range * chore: reorder bottom navigation item and add new strings * chore: add new translations * chore: refactor UI for buy and receive dialog * chore: cleanup ReceiveDialogViewModel * chore: using MoonpayBuyWidget * chore: adjustment moonpaywidget * chore: for now moonpay widget using CustomTabsIntent * chore: set allowSpend to false when recommend rescan click * fix: add delete transaction data from local database * Removed chatty event * chore: add analytics at BRWalletManager.publishCallback * chore: make sure calculation and static fee same as iOS, add setting for selected fee type --------- Co-authored-by: Kerry Washington * build bump * chore: open bread activity first then open moonpay widget (#88) * Adjustment for circleci (#89) * chore: wip adjustment for screengrab * chore: [circleci] adjust config.yml * chore: [circleci] update config.yml, Fastfile, Gemfile.lock, RecoverWalletScreenGrabsTest.kt * chore: [circleci] for now just unit-test * fix: android: Footer version label is obfuscated (#92) * fix: android: Footer version label is obfuscated * fix: [#92] android: Footer version label is obfuscated * fix: You saved it right screen reset button covers words (#93) * fix: [#84] change seed words layout to lazy vertical grid * fix: [#84] refactor seed words layout * tiny resizing (#94) * code and version bump * change break (#97) adds a android user agent and externalID * build code number fix: [#96] remove bottom_nav_menu_us and just using bottom_nav_menu for consistency (#98) * fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99) * Chore/update device data (#100) * change break adds a android user agent and externalID * Update ReceiveDialogViewModel.kt * chore: refactor request params for fetchMoonpaySignedUrl --------- Co-authored-by: andhikayuana * Add agent string obfuscation (#103) * updated metadata (#105) * chore: remove screen lock detection (#106) * 🧰 Fx/seed words UI polish (#108) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * ❇️ Feat/add polish punjabi farsi (#109) * changed to tap * Added instruction label -added localizations * Added 'empty string for when confirm is completed * version and code bump * fix typo replaced click file with mp3 added error sound * added 3 languages * Removed unused audio files * polished tests * removed unused asset pack * code bump * fix: fix YourSeedProveItState.isWordUsedCorrectly (#111) * Upgrade targetSdk 36 (#113) * chore: change drawable with density for brainwallet_logotype_white * chore: adjustment WelcomeScreen.kt * chore: adjustment for targetSdk 36 also support 16KB page size * bump clean extra semicolon * Update pro-guard-rules * Updated the version --------- Co-authored-by: andhikayuana * Updated games module to v1.1.0 * Updated the games submodule * Renamed and tested with user skips --------- Co-authored-by: andhikayuana * Fix(#227): Crash when launching MoonPay Widget (#126) Refactored the MoonPay widget integration to a dedicated Composable (`MoonPayWidgetLauncher`) to ensure proper state handling and loading behavior. - Added `MoonPayWidgetLauncher.kt` with Composable and ViewModel for managing signed URL fetch and Custom Tab launch. - Ensures loading state covers the whole screen, preventing UI crashes. - Removed legacy static method `LegacyNavigation.showMoonPayWidget`. - Updated `ReceiveDialog.kt` and `BuyLitecoinScreen.kt` to use the new Composable. - Minor cleanup in `LegacyNavigation.kt`. * feat(#138): Improve Unlock Screen UI and add dark mode toggle (#122) --------- Co-authored-by: Kerry Washington Co-authored-by: andhikayuana Co-authored-by: Joseph Sanjaya --- .../ui/screens/ready/ReadyScreen.kt | 27 +++++++++---------- .../ui/screens/welcome/WelcomeScreen.kt | 2 +- app/src/main/res/values-ar/strings.xml | 10 +++---- app/src/main/res/values-de/strings.xml | 10 +++---- app/src/main/res/values-es/strings.xml | 10 +++---- app/src/main/res/values-fa/strings.xml | 10 +++---- app/src/main/res/values-fr/strings.xml | 10 +++---- app/src/main/res/values-hi/strings.xml | 10 +++---- app/src/main/res/values-in/strings.xml | 8 +++--- app/src/main/res/values-it/strings.xml | 10 +++---- app/src/main/res/values-ja/strings.xml | 10 +++---- app/src/main/res/values-ko/strings.xml | 8 +++--- app/src/main/res/values-pa/strings.xml | 10 +++---- app/src/main/res/values-pl/strings.xml | 10 +++---- app/src/main/res/values-pt/strings.xml | 10 +++---- app/src/main/res/values-ru/strings.xml | 10 +++---- app/src/main/res/values-sv/strings.xml | 10 +++---- app/src/main/res/values-tr/strings.xml | 10 +++---- app/src/main/res/values-uk/strings.xml | 10 +++---- app/src/main/res/values-zh-rCN/strings.xml | 10 +++---- app/src/main/res/values-zh-rTW/strings.xml | 10 +++---- app/src/main/res/values/strings.xml | 10 +++---- 22 files changed, 112 insertions(+), 113 deletions(-) diff --git a/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyScreen.kt index 1201b0a7..4be9e0dc 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/ready/ReadyScreen.kt @@ -55,10 +55,10 @@ fun ReadyScreen( } /// Layout values - val leadingCopyPadding = 16 + val leadingCopyPadding = 18 val horizontalVerticalSpacing = 8 - val spacerHeight = 90 + val spacerHeight = 40 val activeRowHeight = 70 @@ -89,7 +89,7 @@ fun ReadyScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(horizontalVerticalSpacing.dp), ) { - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(0.5f)) Row { Icon( Icons.AutoMirrored.Filled.ArrowForward, @@ -101,28 +101,27 @@ fun ReadyScreen( scaleY = 2f ) ) - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(0.3f)) } + Spacer(modifier = Modifier.height(16.dp)) + Text( text = stringResource(R.string.ready_setup), style = MaterialTheme.typography.displaySmall.copy(textAlign = TextAlign.Left), - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + fontWeight = FontWeight.Bold ) Text( text = buildAnnotatedString { append(stringResource(R.string.ready_setup_details_1)) - append(" ") - withStyle( - style = SpanStyle( - fontWeight = FontWeight.Bold, - ) - ) { - append(stringResource(R.string.ready_setup_details_2)) + append("\n\n") + append(stringResource(R.string.ready_setup_details_2)) + append("\n\n") + withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { + append(stringResource(R.string.ready_setup_details_3)) } - append(". ") - append(stringResource(R.string.ready_setup_details_3)) }, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index d5a1fd2b..3c9773fb 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -205,7 +205,7 @@ fun WelcomeScreen( ) { Text( - text = stringResource(R.string.ready), + text = stringResource(R.string.MenuViewController_createButton), fontSize = buttonFontSize.sp, fontWeight = FontWeight.SemiBold, ) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 4c1e559c..82a13420 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -386,10 +386,10 @@ لقد أنقذته، أليس كذلك؟ أثبت ذلك!\nاسحب الكلمات بالترتيب الصحيح. اللعبة والمزامنة - مستعد؟ - افعل هذا من أجلك. من فضلك افعلها - وحيد - أحضر قلمًا وورقة و5 دقائق + ؟هل أنت مستعد للبدء؟ + هذا لك وحدك. + قم بإعداد رمز مرور التطبيق، ثم افتح مدير كلمات المرور الخاص بك أو استخدم قلمًا لتسجيله وعبارة البذرة الجديدة. + نحن لا نعرفه وليس لدينا نسخة منه! رمز مرور تطبيق الإعداد اختر رمز مرور لفتح Brainwallet الخاص بك ليس رمز قفل الهاتف! @@ -406,7 +406,7 @@ يتأكد أنت لم تنسى أليس كذلك؟ أدخله مرة أخرى. أو، العودة للبدء من جديد. مستعد - يعيد + استعادة باستخدام عبارة البذور رمز المرور غير صحيح، يرجى المحاولة مرة أخرى! سهم لأسفل لليسار شعار diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 31708d56..cd1386df 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -748,10 +748,10 @@ Du hast es gespeichert, oder? Beweisen Sie es!\nZiehen Sie die Wörter in die richtige Reihenfolge. Spiel & Synchronisierung - Bereit? - Tun Sie dies für Sie. Bitte tun Sie es - allein - Schnappen Sie sich einen Stift, Papier und 5 Minuten + Bereit zum Start? + Das ist nur für dich. + Richten Sie den App-Passcode ein, öffnen Sie Ihren Passwort-Manager oder nehmen Sie einen Stift, um ihn und Ihre neue Seed-Phrase aufzuzeichnen. + Wir kennen es nicht und haben auch keine Kopie! App-Passcode einrichten Wählen Sie einen Passcode, um Ihr Brainwallet zu entsperren Kein Telefonsperrcode! @@ -768,7 +768,7 @@ Bestätigen Du hast es nicht vergessen, oder? Geben Sie es erneut ein. Oder gehen Sie zurück, um von vorne zu beginnen. Bereit - Wiederherstellen + Mit Seed-Phrase wiederherstellen Falscher Passcode, bitte versuchen Sie es erneut! Pfeil nach unten links Logo diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 3eaded9b..e4363ff4 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -747,10 +747,10 @@ Lo guardaste, ¿verdad? ¡Pruébalo!\nArrastra las palabras en el orden correcto. Juego y sincronización - ¿Listo? - Haz esto por ti. por favor hazlo - solo - Coge bolígrafo, papel y 5 minutos. + ¿Listo para empezar? + Esto es solo para ti. + Configura el código de acceso de la aplicación, abre tu administrador de contraseñas o toma un bolígrafo para registrarlo junto con tu nueva frase inicial. + ¡No lo sabemos ni tenemos copia! Configurar el código de acceso de la aplicación Elija una contraseña para desbloquear su Brainwallet ¡No es un código de bloqueo del teléfono! @@ -767,7 +767,7 @@ Confirmar No lo olvidaste ¿verdad? Ingrese nuevamente. O regrese para empezar de nuevo. Listo - Restaurar + Restaurar con frase semilla Código de acceso incorrecto, ¡inténtelo de nuevo! flecha abajo-izquierda logo diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 8f82d491..b70bfedc 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -777,10 +777,10 @@ اثباتش کن! کلمات را به ترتیب صحیح بکشید. بازی و همگام‌سازی - آماده‌اید؟ - برای شما انجام می‌دهم. لطفاً انجامش بده - تنها - یک قلم، کاغذ و ۵ دقیقه بردارید + آماده برای شروع؟ + این فقط برای توئه. + کد عبور برنامه را تنظیم کنید، مدیر رمز عبور خود را باز کنید یا یک خودکار بردارید و آن و عبارت بازیابی جدید خود را یادداشت کنید. + ما نه آن را می‌شناسیم و نه نمونه‌ای از آن داریم! تنظیم رمز عبور برنامه یک رمز عبور را برای باز کردن قفل کیف پول مغزی خود انتخاب کنید قفل تلفن نیست! @@ -803,7 +803,7 @@ تایید فراموش نکردی، مگه نه؟ وارد کنید دوباره. یا، به عقب برگردید تا از ابتدا شروع کنید. آماده - بازیابی + بازیابی با عبارت Seed رمز عبور نادرست، لطفاً دوباره تلاش کنید! فلش به سمت پایین و چپ لوگو diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2d0343e3..92b63a25 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -748,10 +748,10 @@ Vous l\'avez sauvegardé, n\'est-ce pas ? Prouvez-le !\nFaites glisser les mots dans le bon ordre. Jeu et synchronisation - Prêt? - Faites cela pour vous. S\'il te plaît, fais-le - seul - Prenez un stylo, du papier et 5 minutes + Prêt à commencer? + Ceci est pour toi seul. + Configurez le mot de passe de l\'application, ouvrez votre gestionnaire de mots de passe ou prenez un stylo pour l\'enregistrer ainsi que votre nouvelle phrase de départ. + Nous ne le savons pas et n’en avons pas de copie ! Configurer le mot de passe de l\'application Choisissez un mot de passe pour déverrouiller votre Brainwallet Pas un code de verrouillage du téléphone ! @@ -768,7 +768,7 @@ Confirmer Vous n\'avez pas oublié, n\'est-ce pas ? Entrez-le à nouveau. Ou revenez en arrière pour recommencer. Prêt - Restaurer + Restaurer avec une phrase de départ Code d\'accès incorrect, veuillez réessayer ! flèche bas-gauche logo diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index cb889a37..73407e9f 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -386,10 +386,10 @@ आपने इसे सहेज लिया, है ना? इसे साबित करें!\nशब्दों को सही क्रम में खींचें। गेम और सिंक - तैयार? - यह आपके लिए करें. कृपया इसे करते हैं - अकेला - एक कलम, कागज़ और 5 मिनट पकड़ें + शुरू करने के लिए तैयार हैं? + यह केवल आपके लिए है. + ऐप पासकोड सेट करें, अपना पासवर्ड मैनेजर खोलें या इसे और अपने नए बीज वाक्यांश को रिकॉर्ड करने के लिए एक पेन लें। + हमें इसकी जानकारी नहीं है और न ही हमारे पास इसकी कोई प्रति है! ऐप पासकोड सेटअप करें अपने ब्रेनवॉलेट को अनलॉक करने के लिए एक पासकोड चुनें फ़ोन लॉक कोड नहीं! @@ -406,7 +406,7 @@ पुष्टि करना तुम भूले तो नहीं? इसे दोबारा दर्ज करें. या, दोबारा शुरू करने के लिए वापस जाएं। तैयार - पुनर्स्थापित करना + बीज वाक्यांश के साथ पुनर्स्थापित करें ग़लत पासकोड, कृपया पुनः प्रयास करें! नीचे-बाएँ-तीर प्रतीक चिन्ह diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 73f60f4d..e89fb5f4 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -750,10 +750,10 @@ Anda menyimpannya, kan? Buktikan!\nSeret kata-kata dalam urutan yang benar. Permainan & Sinkronisasi - Siap? + Siap untuk memulai? Lakukan ini untukmu. Tolong lakukan itu - sendiri - Ambil pena, kertas, dan 5 menit + Atur kode sandi aplikasi, buka pengelola kata sandi Anda atau ambil pena untuk mencatatnya & frasa benih baru Anda. + Kami tidak mengetahuinya dan kami tidak memiliki salinannya! Siapkan kode sandi aplikasi Pilih kode sandi untuk membuka kunci Brainwallet Anda Bukan kode kunci telepon! @@ -770,7 +770,7 @@ Mengonfirmasi Kamu tidak lupa kan? Masukkan lagi. Atau, kembali untuk memulai kembali. Siap - Memulihkan + Pulihkan dengan Seed Phrase Kode Sandi salah, silakan coba lagi! panah kiri bawah logo diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 69116bf1..3a15ed68 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -748,10 +748,10 @@ L\'hai salvato, vero? Dimostralo!\nTrascina le parole nell\'ordine corretto. Gioco e sincronizzazione - Pronto? - Fallo per te. Per favore, fallo - solo - Prendi carta, penna e 5 minuti + Pronto per iniziare? + Questo è solo per te. + Imposta il codice di accesso dell\'app, apri il tuo gestore di password o prendi una penna per registrarlo insieme alla tua nuova frase seed. + Non lo sappiamo e non ne abbiamo una copia! Imposta il codice di accesso dell\'app Scegli un passcode per sbloccare il tuo Brainwallet Non è un codice di blocco del telefono! @@ -768,7 +768,7 @@ Confermare Non te ne sei dimenticato, vero? Inseriscilo di nuovo. Oppure torna indietro per ricominciare da capo. Pronto - Ripristinare + Ripristina con la frase Seed Codice di accesso errato, riprova! freccia giù a sinistra logo diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5550e8f1..097163d0 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -748,10 +748,10 @@ 保存したんですよね? 証明してください!\n正しい順序で単語をドラッグしてください。 ゲームと同期 - 準備ができて? - あなたのためにこれをしてください。やってください - 一人で - ペンと紙を用意して 5 分 + 시작할 준비가 되셨나요? + これはあなただけのためのものです。 + アプリのパスコードを設定し、パスワード マネージャーを開くか、ペンを用意してパスコードと新しいシード フレーズを記録します。 + 私たちはそれを知りませんし、コピーも持っていません! アプリのパスコードを設定する パスコードを選択してブレインウォレットのロックを解除します 携帯電話のロックコードではありません。 @@ -768,7 +768,7 @@ 確認する 忘れてませんでしたよね?もう一度入力してください。または、戻って最初からやり直します。 準備ができて - 復元する + シードフレーズで復元 パスコードが間違っています。もう一度お試しください。 左下矢印 ロゴ diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 693a92ae..aafc1c57 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -749,9 +749,9 @@ 증명해보세요!\n올바른 순서로 단어를 드래그하세요. 게임 및 동기화 준비가 된? - 당신을 위해 이것을하십시오. 꼭 해주세요 - 홀로 - 펜과 종이를 들고 5분 + 이건 당신만을 위한 거예요. + 앱 비밀번호를 설정하고 비밀번호 관리자를 열거나 펜을 가져와서 비밀번호와 새로운 시드 문구를 기록하세요. + 우리는 그것을 모르고 사본도 없습니다! 앱 비밀번호 설정 Brainwallet을 잠금 해제하려면 비밀번호를 선택하세요 전화 잠금 코드가 아닙니다! @@ -768,7 +768,7 @@ 확인하다 잊지 않았지? 다시 입력하세요. 아니면 돌아가서 다시 시작하세요. 준비가 된 - 복원하다 + 시드 프레이즈로 복원 잘못된 비밀번호입니다. 다시 시도해 주세요! 아래쪽 왼쪽 화살표 심벌 마크 diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 4e8aa15c..98248e3e 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -769,10 +769,10 @@ تُسیں اِس نُوں بچا لیا، ٹھیک؟ ثابت کرو! \nالفاظ نوں صحیح ترتیب وچ کھچو۔ گیم اینڈ سنک - تیار؟ - اے اپنے لئی کرو۔ براہ کرم یہ کریں۔ - اکیلا - قلم، کاغذ تے 5 منٹ لَے لو۔ + شروع کرنے کے لیے تیار ہیں؟ + یہ صرف آپ کے لیے ہے۔ + ایپ پاس کوڈ سیٹ اپ کریں، اپنا پاس ورڈ مینیجر کھولیں یا اسے اور اپنے نئے سیڈ فقرے کو ریکارڈ کرنے کے لیے قلم پکڑیں۔ + ہم اسے نہیں جانتے اور نہ ہی ہمارے پاس کوئی کاپی ہے! ایپ پاسکوڈ سیٹ کریں اپنے برین والٹ کو ان لاک کرنے کے لیے ایک پاس کوڈ منتخب کریں۔ فون لاک کوڈ نہیں! @@ -796,7 +796,7 @@ تُہانوں 5,444,517,950,000,000,000,000,000,000,000,000,000,000,000,000,000 کوششاں لگن گیاں۔ تصدیق کریں۔ تُسیں بھلّے تاں نئیں؟ اسے دوبارہ داخل کریں۔ یا، واپس جا کر دوبارہ شروع کرو۔ - تیار + بیج کے جملے کے ساتھ بحال کریں۔ بحال کرو غلط پاسکوڈ، براہ کرم دوبارہ کوشش کریں! نیچے-کھبے-تیر diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index d1646132..fe6e4805 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -766,10 +766,10 @@ Uratowałeś go, prawda? Udowodnij to! \nPrzeciągnij słowa w odpowiedniej kolejności. Gra i synchronizacja - Gotowy? - Zrób to dla siebie. Proszę, zrób to - sam - Weź długopis, papier i 5 minut + Gotowy zacząć? + Detta är bara för dig. + Ställ in appens lösenord, öppna lösenordshanteraren eller ta en penna för att anteckna det och din nya fröfras. + Vi vet det inte och har inte heller någon kopia! Konfiguracja kodu aplikacji Wybierz hasło, aby odblokować Brainwallet Nie kod blokady telefonu! @@ -792,7 +792,7 @@ Potwierdzenie Nie zapomniałeś, prawda? Wprowadź go ponownie. Albo wrócić i zacząć od nowa. Gotowy - Przywracanie + Przywróć za pomocą frazy początkowej Nieprawidłowe hasło, spróbuj ponownie! strzałka w dół-lewo logo diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 1e68ec84..dcbb7c14 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -747,10 +747,10 @@ Você salvou, certo? Prove!\nArraste as palavras na ordem correta. Jogo e sincronização - Preparar? - Faça isso por você. Por favor faça isso - sozinho - Pegue uma caneta, papel e 5 minutos + Pronto para começar? + Isto é somente para você. + Configure a senha do aplicativo, abra seu gerenciador de senhas ou pegue uma caneta para registrá-la junto com sua nova frase-semente. + Não sabemos e nem temos uma cópia! Configurar senha do aplicativo Escolha uma senha para desbloquear seu Brainwallet Não é um código de bloqueio do telefone! @@ -767,7 +767,7 @@ Confirmar Você não esqueceu, não é? Digite novamente. Ou volte para começar de novo. Preparar - Restaurar + Restaurar com frase semente Senha incorreta, tente novamente! seta para baixo à esquerda logotipo diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 183a5c30..ad65ef57 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -748,10 +748,10 @@ Ты сохранил это, да? Докажите это!\nПеретащите слова в правильном порядке. Игра и синхронизация - Готовый? - Сделайте это для себя. Пожалуйста, сделай это - один - Возьмите ручку, бумагу и 5 минут. + Готовы начать? + Это только для тебя. + Установите код доступа к приложению, откройте менеджер паролей или возьмите ручку, чтобы записать его и новую начальную фразу. + Мы этого не знаем и у нас нет копии! Установить пароль приложения Выберите пароль, чтобы разблокировать свой Brainwallet Это не код блокировки телефона! @@ -768,7 +768,7 @@ Подтверждать Ты ведь не забыл? Введите его еще раз. Или вернитесь, чтобы начать все сначала. Готовый - Восстановить + Восстановить с помощью Seed-фразы Неправильный пароль, попробуйте еще раз! стрелка вниз-влево логотип diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 1e7f0342..6e155cf2 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -386,10 +386,10 @@ Du sparade det, eller hur? Bevisa det!\nDra orden i rätt ordning. Spel och synkronisering - Redo? - Gör det här åt dig. Snälla gör det - ensam - Ta en penna, papper och 5 minuter + Redo att börja? + Detta är bara för dig. + Ställ in appens lösenord, öppna lösenordshanteraren eller ta en penna för att anteckna det och din nya fröfras. + Vi vet det inte och vi har ingen kopia! Konfigurera appens lösenord Välj ett lösenord för att låsa upp din Brainwallet Inte en telefonlåskod! @@ -406,7 +406,7 @@ Bekräfta Du glömde väl inte? Skriv in det igen. Eller gå tillbaka för att börja om. Redo - Återställa + Återställ med Seed Phrase Felaktigt lösenord, försök igen! ned-vänster-pil logotyp diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index cd3a9eaf..71f767b1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -770,10 +770,10 @@ Onu kurtardın, değil mi? Kanıtlayın!\nKelimeleri doğru sıraya göre sürükleyin. Oyun ve Senkronizasyon - Hazır? - Bunu kendin için yap. Lütfen yap - yalnız - Bir kalem, kağıt alın ve 5 dakika + Başlamaya hazır mısınız? + Bu sadece sana özel. + Uygulama şifrenizi ayarlayın, şifre yöneticinizi açın veya bir kalem alıp şifrenizi ve yeni başlangıç ​​cümlenizi kaydedin. + Biz bunu bilmiyoruz, kopyası da bizde yok! Uygulama şifresini ayarla Beyin Cüzdanınızın kilidini açmak için bir şifre seçin Telefon kilit kodu değil! @@ -790,7 +790,7 @@ Onaylamak Unutmadın değil mi? Tekrar girin. Veya baştan başlamak için geri dönün. Hazır - Eski haline getirmek + Tohum İfadesi ile Geri Yükle Yanlış Şifre, lütfen tekrar deneyin! sol aşağı ok logo diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index cd63237d..311e84e9 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -754,10 +754,10 @@ Ви зберегли його, правда? Доведіть це!\nПеретягніть слова в правильному порядку. Гра та синхронізація - готовий - Зробіть це для вас. Будь ласка, зробіть це - поодинці - Візьміть ручку, папір і 5 хвилин + Готові почати? + Це тільки для тебе. + Налаштуйте пароль програми, відкрийте менеджер паролів або візьміть ручку, щоб записати його та нову початкову фразу. + Ми цього не знаємо і не маємо копії! Налаштуйте пароль програми Виберіть пароль, щоб розблокувати свій Brainwallet Не код блокування телефону! @@ -774,7 +774,7 @@ Підтвердити Ви не забули? Введіть його знову. Або поверніться, щоб почати спочатку. Готовий - Відновити + Відновлення за початкової фрази Неправильний пароль, спробуйте ще раз! стрілка вниз-ліворуч логотип diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 4f28b512..e43d6b0f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -748,10 +748,10 @@ 你救了它,对吗? 证明一下!\n按正确的顺序拖动单词。 游戏与同步 - 准备好? - 为你做这件事。请这样做 - 独自的 - 拿起笔、纸和 5 分钟 + 准备好开始了吗? + 这是只属于你一个人的。 + 设置应用程序密码,打开密码管理器或拿一支笔记录它和你的新种子短语。 + 我们不知道,也没有副本! 设置应用程序密码 选择密码来解锁您的 Brainwallet 不是手机锁码! @@ -768,7 +768,7 @@ 确认 你没有忘记吧?再次输入。或者,返回重新开始。 准备好 - 恢复 + 使用种子短语恢复 密码错误,请重试! 左下箭头 标识 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 378bc1aa..8e29fb69 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -747,10 +747,10 @@ 你救了它,對嗎? 證明一下! 遊戲與同步 - 準備好? - 為你做這件事。請這樣做 - 獨自的 - 拿起筆、紙和 5 分鐘 + 準備好開始了嗎? + 我們不知道,也沒有副本! + 設定應用程式密碼,打開密碼管理器或拿一支筆記錄它和你的新種子短語。 + 我們不知道,也沒有副本! 設定應用程式密碼 選擇密碼來解鎖您的 Brainwallet 不是手機鎖碼! @@ -767,7 +767,7 @@ 確認 你沒有忘記吧?再次輸入。或者,返回重新開始。 準備好 - 恢復 + 使用種子短語恢復 密碼錯誤,請重試! 左下箭頭 標識 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 443eee4f..cb798919 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -785,10 +785,10 @@ You saved it, right? Prove it!\nDrag the words in the correct order. Game & Sync - Ready? - Do this for you. Please do it - alone - Grab a pen, paper and 5 minutes + Ready to start? + This is for you alone. + Setup the app passcode, open your password manager or grab a pen to record it & your new seed phrase. + We do not know it nor do we have a copy! Setup app passcode Pick a passcode to unlock your Brainwallet Not a phone lock code! @@ -811,7 +811,7 @@ Confirm You didn’t forget did you? Enter it again. Or, go back to start over. Ready - Restore + Restore With Seed Phrase Incorrect Passcode, please try again! down-left-arrow logo From 18df29329942d52f7cbaa0a4c22524c788a1a415 Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Tue, 26 Aug 2025 15:05:43 +0700 Subject: [PATCH 60/65] fix(#226): android test failure on RecoverWalletScreenGrabsTest (#130) Move SCREENGRAB_PAPERKEY build config to debug build type The `SCREENGRAB_PAPERKEY` build configuration field, used for screengrab tests, was previously defined in both the `debug` and `screengrab` build types. This commit moves the definition solely to the `debug` build type, as the `screengrab` build type inherits from `debug` and thus already has access to this field. Additionally, unused imports were removed from `BrainwalletScreengrabApp.kt`. --- app/build.gradle.kts | 14 +++++++------- .../com/brainwallet/BrainwalletScreengrabApp.kt | 3 --- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index aac3d3e6..8c8ae5bb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -71,6 +71,13 @@ android { firebaseCrashlytics { nativeSymbolUploadEnabled = true } + buildConfigField("String[]", "SCREENGRAB_PAPERKEY", + "new String[] {${ + localProperties.getProperty("SCREENGRAB_PAPERKEY", "") + .split(" ") + .joinToString { "\"$it\"" } + }}" + ) } val release by getting { @@ -125,13 +132,6 @@ android { applicationId = "ltd.grunt.brainwallet.screengrab" versionNameSuffix = "-screengrab" resValue("string", "app_name", "Brainwallet (screengrab)") - buildConfigField("String[]", "SCREENGRAB_PAPERKEY", - "new String[] {${ - localProperties.getProperty("SCREENGRAB_PAPERKEY", "") - .split(" ") - .joinToString { "\"$it\"" } - }}" - ) externalNativeBuild { cmake { diff --git a/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt b/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt index 6e14bcf3..c181d83e 100644 --- a/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt +++ b/app/src/screengrab/kotlin/com/brainwallet/BrainwalletScreengrabApp.kt @@ -1,9 +1,6 @@ package com.brainwallet import com.brainwallet.data.source.RemoteConfigSource -import com.brainwallet.di.appModule -import com.brainwallet.di.dataModule -import com.brainwallet.di.viewModelModule import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.GlobalContext.startKoin From 9b191b777b5e40a92b0629a74ade4e385a48c93b Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Tue, 26 Aug 2025 15:50:12 +0700 Subject: [PATCH 61/65] fix(#223): fix issue on test environment SLF4J + agent warnings in test env (#129) - Added `slf4j-android` as a test dependency to provide a proper SLF4J binding and avoid "StaticLoggerBinder" warnings. - Configured JVM args for Gradle test tasks to enable dynamic agent loading, suppressing Byte Buddy agent warnings during test runs. --- app/build.gradle.kts | 8 +++++++- gradle/libs.versions.toml | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8c8ae5bb..abf18b73 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -245,12 +245,14 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockk) testImplementation(libs.turbine) + testImplementation(libs.slf4j.android) testImplementation(libs.kotlinx.coroutines.tests) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(libs.bundles.android.test) androidTestImplementation(libs.fastlane.screengrab) + androidTestImplementation(libs.slf4j.android) } val ktlintCheck by tasks.registering(JavaExec::class) { @@ -283,4 +285,8 @@ tasks.register("ktlintFormat") { "**.kts", "!**/build/**", ) -} \ No newline at end of file +} + +tasks.withType { + jvmArgs("-XX:+EnableDynamicAgentLoading") +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f18f2b70..a0f2aba6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,6 +35,7 @@ koin-annotation-bom = "2.1.0" ksp = "2.0.0-1.0.24" turbine = "1.2.1" coroutines = "1.10.2" +slf4j = "1.7.36" [libraries] androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" } @@ -122,6 +123,7 @@ koin-annotation-compiler = { module = "io.insert-koin:koin-ksp-compiler", versio turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } kotlinx-coroutines-tests = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } +slf4j-android = { module = "org.slf4j:slf4j-android", version.ref = "slf4j" } [bundles] androidx-lifecycle = ["androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel", "androidx-lifecycle-viewmodel-compose"] From c9b1ef036881f56db34a2a874db7c5eb672e18eb Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Sat, 30 Aug 2025 14:13:07 +0700 Subject: [PATCH 62/65] feat(#225): Send sync duration in Firebase Analytics as a custom event and in Settings row (#131) * feat(#225): Send sync duration in Firebase Analytics as a custom event and in Settings row This commit introduces analytics tracking for the sync process. It includes: - `TimeProvider`: A utility class for getting the current time, allowing for easier testing. - `AnalyticsSource`: An interface for logging analytics events. - `FirebaseAnalyticsSource`: An implementation of `AnalyticsSource` that uses Firebase Analytics. - `SyncAnalyticsRepository`: A repository to manage and persist sync-related analytics data, and log events. - `startSync()`: Records the start time of a sync. - `stopSync()`: Records the stop time of a sync and accumulates the duration if the sync is paused/resumed. - `completeSync()`: Persists the total sync duration, end timestamp, and a unique ID. It then logs a "user_did_complete_sync" event with these details and the current block height. - `getLastSyncMetadata()`: Retrieves the metadata of the last completed sync. - Unit tests for the new classes. - Integration of `SyncAnalyticsRepository` into `SyncManager` to call the respective methods at the start, stop, and completion of the sync process. - `FakeSharedPreferences`: A testing utility for mocking SharedPreferences. * chore(#225): Move SyncMetadata formatting to Formatter class This commit introduces a `Formatter` class within `SyncAnalyticsRepository.SyncMetadata` to handle the formatting of sync metadata. The `getFormatted()` method has been removed from `SyncAnalyticsRepository.SyncMetadata` and its logic is now encapsulated in the `SyncMetadata.Formatter.format()` method. This change improves the separation of concerns and makes the formatting logic more testable. The `HomeSettingDrawerSheet` has been updated to use the new `Formatter` class. Unit tests have been added to `SyncAnalyticsRepositoryTest` to verify the correctness of the `SyncMetadata.Formatter`. --- .../repository/SyncAnalyticsRepository.kt | 106 ++++++++++ .../data/source/AnalyticsSource.kt | 6 + .../data/source/FirebaseAnalyticsSource.kt | 33 +++ .../data/source/PeerManagerSource.kt | 17 ++ .../tools/manager/SyncManager.java | 13 +- .../ui/screens/home/SettingsEvent.kt | 4 +- .../ui/screens/home/SettingsState.kt | 4 +- .../home/composable/HomeSettingDrawerSheet.kt | 14 +- .../java/com/brainwallet/util/TimeProvider.kt | 12 ++ .../repository/SyncAnalyticsRepositoryTest.kt | 192 ++++++++++++++++++ .../source/FirebaseAnalyticsSourceTest.kt | 46 +++++ .../data/source/PeerManagerSourceTest.kt | 42 ++++ .../brainwallet/util/FakeSharedPreferences.kt | 107 ++++++++++ .../com/brainwallet/util/TimeProviderTest.kt | 16 ++ 14 files changed, 606 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/repository/SyncAnalyticsRepository.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/AnalyticsSource.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/FirebaseAnalyticsSource.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/PeerManagerSource.kt create mode 100644 app/src/main/java/com/brainwallet/util/TimeProvider.kt create mode 100644 app/src/test/java/com/brainwallet/data/repository/SyncAnalyticsRepositoryTest.kt create mode 100644 app/src/test/java/com/brainwallet/data/source/FirebaseAnalyticsSourceTest.kt create mode 100644 app/src/test/java/com/brainwallet/data/source/PeerManagerSourceTest.kt create mode 100644 app/src/test/java/com/brainwallet/util/FakeSharedPreferences.kt create mode 100644 app/src/test/java/com/brainwallet/util/TimeProviderTest.kt diff --git a/app/src/main/java/com/brainwallet/data/repository/SyncAnalyticsRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SyncAnalyticsRepository.kt new file mode 100644 index 00000000..3486dd02 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/SyncAnalyticsRepository.kt @@ -0,0 +1,106 @@ +package com.brainwallet.data.repository + +import android.content.SharedPreferences +import androidx.core.content.edit +import com.brainwallet.data.source.AnalyticsSource +import com.brainwallet.data.source.PeerManagerSource +import org.koin.core.annotation.Single +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.UUID + +@Single +class SyncAnalyticsRepository( + private val analyticsSource: AnalyticsSource, + private val peerManagerSource: PeerManagerSource, + private val prefs: SharedPreferences, +) { + fun startSync() { + // Record the start time of the current sync segment. + prefs.edit { + putLong(KEY_CURRENT_SYNC_START_TIMESTAMP, peerManagerSource.getLastBlockTimestamp()) + } + } + + fun stopSync() { + val start = prefs.getLong(KEY_CURRENT_SYNC_START_TIMESTAMP, 0L) + if (start != 0L) { + val duration = peerManagerSource.getLastBlockTimestamp() - start + val accumulated = prefs.getLong(KEY_ACCUMULATED_DURATION, 0L) + prefs.edit { + putLong(KEY_ACCUMULATED_DURATION, accumulated + duration) + remove(KEY_CURRENT_SYNC_START_TIMESTAMP) + } + } + } + + fun completeSync() { + // Capture the duration of the final segment. + stopSync() + + val totalDuration = prefs.getLong(KEY_ACCUMULATED_DURATION, 0L) + if (totalDuration == 0L) return + + val endTimestamp = peerManagerSource.getLastBlockTimestamp() + val endBlockHeight = peerManagerSource.getCurrentBlockHeight() + val uuid = UUID.randomUUID().toString() + val totalDurationInMillis = totalDuration * 1000 + + prefs.edit { + putString(KEY_LAST_UUID, uuid) + putLong(KEY_LAST_DURATION, totalDurationInMillis) + putLong(KEY_LAST_END, endTimestamp) + remove(KEY_ACCUMULATED_DURATION) + } + + val params = mapOf( + KEY_UUID to uuid, + KEY_DURATION_MILLIS to (totalDurationInMillis), + KEY_END_TIMESTAMP to endTimestamp, + KEY_END_BLOCK_HEIGHT to endBlockHeight + ) + analyticsSource.logEventWithParams(KEY_EVENT, params) + } + + fun getLastSyncMetadata(): SyncMetadata? { + val uuid = prefs.getString(KEY_LAST_UUID, null) ?: return null + val duration = prefs.getLong(KEY_LAST_DURATION, 0L) + val end = prefs.getLong(KEY_LAST_END, 0L) + return SyncMetadata(uuid, duration, end) + } + + data class SyncMetadata( + val uuid: String, + val durationMillis: Long, + val endTimestamp: Long + ) { + class Formatter( + private val dateFormat: SimpleDateFormat = SimpleDateFormat( + "MMMM dd, yyyy h:mm:ss a", + Locale.getDefault() + ) + ) { + fun format(syncMetadata: SyncMetadata): String { + val durationSeconds = syncMetadata.durationMillis / 1000.0 + val date = Date(syncMetadata.endTimestamp * 1000) + val dateString = dateFormat.format(date) + + return "Duration: %.1f seconds\nTimestamp: %s".format(durationSeconds, dateString) + } + } + } + + companion object { + private const val KEY_CURRENT_SYNC_START_TIMESTAMP = "current_sync_start_timestamp" + private const val KEY_ACCUMULATED_DURATION = "accumulated_sync_duration" + private const val KEY_LAST_UUID = "last_sync_uuid" + private const val KEY_LAST_DURATION = "last_sync_duration" + private const val KEY_LAST_END = "last_sync_end_timestamp" + private const val KEY_DURATION_MILLIS = "duration_millis" + private const val KEY_END_TIMESTAMP = "end_timestamp" + private const val KEY_END_BLOCK_HEIGHT = "end_block_height" + private const val KEY_UUID = "uuid" + private const val KEY_EVENT = "user_did_complete_sync" + } +} diff --git a/app/src/main/java/com/brainwallet/data/source/AnalyticsSource.kt b/app/src/main/java/com/brainwallet/data/source/AnalyticsSource.kt new file mode 100644 index 00000000..8449f188 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/AnalyticsSource.kt @@ -0,0 +1,6 @@ +package com.brainwallet.data.source + +interface AnalyticsSource { + fun logEvent(event: String) + fun logEventWithParams(event: String, params: Map) +} diff --git a/app/src/main/java/com/brainwallet/data/source/FirebaseAnalyticsSource.kt b/app/src/main/java/com/brainwallet/data/source/FirebaseAnalyticsSource.kt new file mode 100644 index 00000000..0360d489 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/FirebaseAnalyticsSource.kt @@ -0,0 +1,33 @@ +package com.brainwallet.data.source + +import android.content.Context +import android.os.Bundle +import com.google.firebase.analytics.FirebaseAnalytics +import org.koin.core.annotation.Single + +@Single +class FirebaseAnalyticsSource( + private val context: Context, + private val analytics: FirebaseAnalytics = FirebaseAnalytics.getInstance(context) +) : AnalyticsSource { + + override fun logEvent(event: String) { + analytics.logEvent(event, null) + } + + override fun logEventWithParams(event: String, params: Map) { + val bundle = Bundle().apply { + params.forEach { (key, value) -> + when (value) { + is String -> putString(key, value) + is Int -> putInt(key, value) + is Long -> putLong(key, value) + is Double -> putDouble(key, value) + is Boolean -> putBoolean(key, value) + // add more types if needed + } + } + } + analytics.logEvent(event, bundle) + } +} diff --git a/app/src/main/java/com/brainwallet/data/source/PeerManagerSource.kt b/app/src/main/java/com/brainwallet/data/source/PeerManagerSource.kt new file mode 100644 index 00000000..10eaf13b --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/PeerManagerSource.kt @@ -0,0 +1,17 @@ +package com.brainwallet.data.source + +import com.brainwallet.wallet.BRPeerManager +import org.koin.core.annotation.Single + +interface BRPeerManagerProxy { + fun getCurrentBlockHeight(): Int + fun getLastBlockTimestamp(): Long +} + +@Single +class PeerManagerSource( + private val proxy: BRPeerManagerProxy = object : BRPeerManagerProxy { + override fun getCurrentBlockHeight(): Int = BRPeerManager.getCurrentBlockHeight() + override fun getLastBlockTimestamp(): Long = BRPeerManager.getInstance().lastBlockTimestamp + } +) : BRPeerManagerProxy by proxy diff --git a/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java b/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java index ace9dcc1..c33fc2c5 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/SyncManager.java @@ -1,5 +1,6 @@ package com.brainwallet.tools.manager; +import static com.brainwallet.data.source.RemoteConfigSource.KEY_FEATURE_SELECTED_PEERS_ENABLED; import static com.brainwallet.tools.manager.BRSharedPrefs.putSyncMetadata; import android.app.AlarmManager; @@ -9,6 +10,8 @@ import android.os.Build; import android.os.Bundle; +import com.brainwallet.data.repository.SyncAnalyticsRepository; +import com.brainwallet.data.source.RemoteConfigSource; import com.brainwallet.tools.listeners.SyncReceiver; import com.brainwallet.tools.util.BRConstants; import com.brainwallet.tools.util.Utils; @@ -16,6 +19,8 @@ import com.brainwallet.presenter.activities.BreadActivity; import com.brainwallet.wallet.BRPeerManager; +import org.koin.java.KoinJavaComponent; + import java.util.concurrent.TimeUnit; import timber.log.Timber; @@ -34,6 +39,10 @@ public static SyncManager getInstance() { private SyncManager() { } + public static SyncAnalyticsRepository getSyncAnalyticsRepository() { + return KoinJavaComponent.get(SyncAnalyticsRepository.class); + } + public synchronized void startSyncingProgressThread(Context app) { try { if (syncTask != null) { @@ -45,6 +54,7 @@ public synchronized void startSyncingProgressThread(Context app) { syncTask = null; } syncTask = new SyncProgressTask(); + getSyncAnalyticsRepository().startSync(); syncTask.start(); updateStartSyncData(app); } catch (IllegalThreadStateException ex) { @@ -59,10 +69,11 @@ private synchronized void updateStartSyncData(Context app) { private synchronized void markFinishedSyncData(Context app) { Timber.d("timber: || SYNC ELAPSE markFinish threadname:%s", Thread.currentThread().getName()); final double progress = BRPeerManager.syncProgress(BRSharedPrefs.getStartHeight(app)); + getSyncAnalyticsRepository().completeSync(); } public synchronized void stopSyncingProgressThread(Context app) { - + getSyncAnalyticsRepository().stopSync(); if (app == null) { Timber.i("timber: || stopSyncingProgressThread: ctx is null"); return; diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt index cf6b1d31..36ef087f 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt @@ -3,10 +3,12 @@ package com.brainwallet.ui.screens.home import com.brainwallet.data.model.CurrencyEntity import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.SyncAnalyticsRepository + sealed class SettingsEvent { data class OnLoad( val shareAnalyticsDataEnabled: Boolean = false, - val lastSyncMetadata: String? = null, + val lastSyncMetadata: SyncAnalyticsRepository.SyncMetadata? = null, ) : SettingsEvent() object OnSecurityUpdatePinClick : SettingsEvent() object OnSecuritySeedPhraseClick : SettingsEvent() diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt index d0336bff..b1e82c75 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt @@ -7,6 +7,8 @@ import com.brainwallet.data.model.Language import com.brainwallet.data.model.toFeeOptions import com.brainwallet.tools.manager.FeeManager +import com.brainwallet.data.repository.SyncAnalyticsRepository + data class SettingsState( val darkMode: Boolean = true, val selectedLanguage: Language = Language.ENGLISH, @@ -19,7 +21,7 @@ data class SettingsState( val languageSelectorBottomSheetVisible: Boolean = false, val fiatSelectorBottomSheetVisible: Boolean = false, val shareAnalyticsDataEnabled: Boolean = false, - val lastSyncMetadata: String? = null, + val lastSyncMetadata: SyncAnalyticsRepository.SyncMetadata? = null, val currentFeeOptions: List = Fee.Default.toFeeOptions(), val selectedFeeType: String = FeeManager.LUXURY ) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt index d96cda42..fbb01438 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -28,6 +28,7 @@ import androidx.lifecycle.coroutineScope import androidx.lifecycle.findViewTreeLifecycleOwner import com.brainwallet.R import com.brainwallet.data.model.AppSetting +import com.brainwallet.data.repository.SyncAnalyticsRepository import com.brainwallet.tools.manager.BRSharedPrefs import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.screens.home.SettingsEvent @@ -48,12 +49,14 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel import org.koin.java.KoinJavaComponent.inject @Composable fun HomeSettingDrawerSheet( modifier: Modifier = Modifier, - viewModel: SettingsViewModel = koinInject() + syncAnalyticsRepository: SyncAnalyticsRepository = koinInject(), + viewModel: SettingsViewModel = koinViewModel() ) { val state by viewModel.state.collectAsState() val context = LocalContext.current @@ -61,7 +64,7 @@ fun HomeSettingDrawerSheet( LaunchedEffect(Unit) { viewModel.onEvent(SettingsEvent.OnLoad( shareAnalyticsDataEnabled = BRSharedPrefs.getShareData(context), //currently just load analytics share data here - lastSyncMetadata = BRSharedPrefs.getSyncMetadata(context), //currently just load sync metadata here + lastSyncMetadata = syncAnalyticsRepository.getLastSyncMetadata(), //currently just load sync metadata here )) } @@ -192,10 +195,15 @@ fun HomeSettingDrawerSheet( } item { + val description = state.lastSyncMetadata?.let { + SyncAnalyticsRepository.SyncMetadata.Formatter() + .format(it) + } ?: "No sync metadata" + SettingRowItem( modifier = Modifier.height(100.dp), title = stringResource(R.string.settings_title_sync_metadata), - description = state.lastSyncMetadata ?: "No sync metadata" + description = description ) } diff --git a/app/src/main/java/com/brainwallet/util/TimeProvider.kt b/app/src/main/java/com/brainwallet/util/TimeProvider.kt new file mode 100644 index 00000000..0fdebf7d --- /dev/null +++ b/app/src/main/java/com/brainwallet/util/TimeProvider.kt @@ -0,0 +1,12 @@ +package com.brainwallet.util + +import org.koin.core.annotation.Single + +@Single +class TimeProvider( + private val nowGetter: () -> Long = { System.currentTimeMillis() } +) { + fun now(): Long { + return nowGetter() + } +} diff --git a/app/src/test/java/com/brainwallet/data/repository/SyncAnalyticsRepositoryTest.kt b/app/src/test/java/com/brainwallet/data/repository/SyncAnalyticsRepositoryTest.kt new file mode 100644 index 00000000..0167e25f --- /dev/null +++ b/app/src/test/java/com/brainwallet/data/repository/SyncAnalyticsRepositoryTest.kt @@ -0,0 +1,192 @@ +package com.brainwallet.data.repository + +import android.content.SharedPreferences +import com.brainwallet.data.source.AnalyticsSource +import com.brainwallet.data.source.PeerManagerSource +import com.brainwallet.util.FakeSharedPreferences +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockkStatic +import io.mockk.slot +import io.mockk.unmockkAll +import io.mockk.verify +import org.junit.After +import org.junit.Before +import org.junit.Test +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.TimeZone +import java.util.UUID + +class SyncAnalyticsRepositoryTest { + private lateinit var prefs: SharedPreferences + + @MockK + private lateinit var analyticsSource: AnalyticsSource + + @MockK + private lateinit var peerManagerSource: PeerManagerSource + + private lateinit var repository: SyncAnalyticsRepository + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxUnitFun = true) + prefs = FakeSharedPreferences() + repository = SyncAnalyticsRepository( + analyticsSource = analyticsSource, + peerManagerSource = peerManagerSource, + prefs = prefs + ) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given sync started when startSync called then start timestamp stored`() { + every { peerManagerSource.getLastBlockTimestamp() } returns 1000L + + repository.startSync() + + val stored = prefs.getLong("current_sync_start_timestamp", -1L) + assert(stored == 1000L) { "expected 1000L but was $stored" } + } + + @Test + fun `given sync started and stopped when stopSync called then duration accumulated`() { + prefs.edit().putLong("current_sync_start_timestamp", 1000L).apply() + prefs.edit().putLong("accumulated_sync_duration", 200L).apply() + every { peerManagerSource.getLastBlockTimestamp() } returns 1500L + + repository.stopSync() + + val accumulated = prefs.getLong("accumulated_sync_duration", 0L) + val startRemoved = prefs.getLong("current_sync_start_timestamp", -1L) + assert(accumulated == 700L) { "expected 700L but was $accumulated" } + assert(startRemoved == -1L) { "expected current_sync_start_timestamp to be removed" } + } + + @Test + fun `given sync never started when stopSync called then nothing stored`() { + prefs.edit().putLong("current_sync_start_timestamp", 0L).apply() + + repository.stopSync() + + val accumulated = prefs.getLong("accumulated_sync_duration", 0L) + assert(accumulated == 0L) { "expected no accumulation but was $accumulated" } + } + + @Test + fun `given accumulated duration when completeSync called then metadata persisted and event logged`() { + prefs.edit().putLong("accumulated_sync_duration", 5000L).apply() + every { peerManagerSource.getLastBlockTimestamp() } returns 6000L + every { peerManagerSource.getCurrentBlockHeight() } returns 456 + + mockkStatic(UUID::class) + every { UUID.randomUUID().toString() } returns "uuid-123" + + repository.completeSync() + + val lastUuid = prefs.getString("last_sync_uuid", null) + val lastDuration = prefs.getLong("last_sync_duration", 0L) + val lastEnd = prefs.getLong("last_sync_end_timestamp", 0L) + val accumulatedCleared = prefs.getLong("accumulated_sync_duration", -1L) + + assert(lastUuid == "uuid-123") { "expected uuid-123 but was $lastUuid" } + assert(lastDuration == 5000000L) { "expected duration=5000000 but was $lastDuration" } + assert(lastEnd == 6000L) { "expected end=6000 but was $lastEnd" } + assert(accumulatedCleared == -1L) { "expected accumulated_sync_duration removed" } + + val paramsSlot = slot>() + + verify { + analyticsSource.logEventWithParams( + "user_did_complete_sync", + capture(paramsSlot) + ) + } + + val captured = paramsSlot.captured + println("captured: $captured") + + assert(captured["uuid"] == "uuid-123") { "uuid should match" } + assert(captured["duration_millis"] == 5000000L) { "duration should match" } + assert(captured["end_timestamp"] == 6000L) { "end timestamp should match" } + assert(captured["end_block_height"] == 456) { "end block height should match" } + } + + @Test + fun `given metadata stored when getLastSyncMetadata called then correct SyncMetadata returned`() { + prefs.edit() + .putString("last_sync_uuid", "uuid-999") + .putLong("last_sync_duration", 8888L) + .putLong("last_sync_end_timestamp", 9999L) + .apply() + + val metadata = repository.getLastSyncMetadata() + + assert(metadata != null) { "expected metadata to be not null" } + assert(metadata!!.uuid == "uuid-999") { "expected uuid=uuid-999 but was ${metadata.uuid}" } + assert(metadata.durationMillis == 8888L) { "expected duration=8888 but was ${metadata.durationMillis}" } + assert(metadata.endTimestamp == 9999L) { "expected endTimestamp=9999 but was ${metadata.endTimestamp}" } + } + + @Test + fun `given no metadata stored when getLastSyncMetadata called then null returned`() { + val metadata = repository.getLastSyncMetadata() + assert(metadata == null) { "expected metadata to be null" } + } + + @Test + fun `given sync metadata when format then return formatted string containing correct duration and timestamp`() { + val fixedDateFormat = SimpleDateFormat("MMMM dd, yyyy h:mm:ss a", Locale.US).apply { + timeZone = TimeZone.getTimeZone("UTC") + } + val formatter = SyncAnalyticsRepository.SyncMetadata.Formatter(fixedDateFormat) + + val syncMetadata = SyncAnalyticsRepository.SyncMetadata( + uuid = "1234", + durationMillis = 2500L, + endTimestamp = 1633072800L + ) + + val formattedOutput = formatter.format(syncMetadata) + + assert(formattedOutput.contains("Duration: 2.5 seconds")) { + "Expected formatted string to contain 'Duration: 2.5 seconds' but got '$formattedOutput'" + } + + val expectedDatePart = fixedDateFormat.format(Date(syncMetadata.endTimestamp * 1000)) + assert(formattedOutput.contains(expectedDatePart)) { + "Expected formatted string to contain '$expectedDatePart' but got '$formattedOutput'" + } + } + + @Test + fun `given sync metadata when format then return exactly formatted string with correct structure`() { + val fixedDateFormat = SimpleDateFormat("MMMM dd, yyyy h:mm:ss a", Locale.US).apply { + timeZone = TimeZone.getTimeZone("UTC") + } + val formatter = SyncAnalyticsRepository.SyncMetadata.Formatter(fixedDateFormat) + + val syncMetadata = SyncAnalyticsRepository.SyncMetadata( + uuid = "1234", + durationMillis = 2500L, + endTimestamp = 1633072800L + ) + + val actual = formatter.format(syncMetadata) + + val expectedDate = fixedDateFormat.format(Date(syncMetadata.endTimestamp * 1000)) + val expected = "Duration: 2.5 seconds\nTimestamp: $expectedDate" + + assert(actual == expected) { + "Expected exactly '$expected' but got '$actual'" + } + } +} diff --git a/app/src/test/java/com/brainwallet/data/source/FirebaseAnalyticsSourceTest.kt b/app/src/test/java/com/brainwallet/data/source/FirebaseAnalyticsSourceTest.kt new file mode 100644 index 00000000..c8d79346 --- /dev/null +++ b/app/src/test/java/com/brainwallet/data/source/FirebaseAnalyticsSourceTest.kt @@ -0,0 +1,46 @@ +package com.brainwallet.data.source + +import android.content.Context +import com.google.firebase.analytics.FirebaseAnalytics +import io.mockk.MockKAnnotations +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.verify +import org.junit.Before +import org.junit.Test + +class FirebaseAnalyticsSourceTest { + + @RelaxedMockK + private lateinit var context: Context + + @MockK + private lateinit var firebaseAnalytics: FirebaseAnalytics + private lateinit var sut: FirebaseAnalyticsSource + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxUnitFun = true) + sut = FirebaseAnalyticsSource(context, firebaseAnalytics) + } + + @Test + fun `given valid event name when logCustomEvent is called then event should be logged without params`() { + val eventName = "test_event" + + sut.logEvent(eventName) + + verify(exactly = 1) { firebaseAnalytics.logEvent(eventName, null) } + assert(true) { "Expected logEvent to be called with eventName=$eventName and params=null" } + } + + @Test + fun `given valid event name and params when logCustomEventWithParams is called then event should be logged with params`() { + val eventName = "test_event_with_params" + + sut.logEventWithParams(eventName, mapOf()) + + verify(exactly = 1) { firebaseAnalytics.logEvent(eventName, any()) } + assert(true) { "Expected logEvent to be called with eventName=$eventName and provided params" } + } +} diff --git a/app/src/test/java/com/brainwallet/data/source/PeerManagerSourceTest.kt b/app/src/test/java/com/brainwallet/data/source/PeerManagerSourceTest.kt new file mode 100644 index 00000000..a415847b --- /dev/null +++ b/app/src/test/java/com/brainwallet/data/source/PeerManagerSourceTest.kt @@ -0,0 +1,42 @@ +package com.brainwallet.data.source + +import io.mockk.every +import io.mockk.mockk +import org.junit.Before +import org.junit.Test + +class PeerManagerSourceTest { + + private lateinit var proxy: BRPeerManagerProxy + private lateinit var peerManagerSource: PeerManagerSource + + @Before + fun setUp() { + proxy = mockk() + peerManagerSource = PeerManagerSource(proxy) + } + + @Test + fun `Given proxy returns block height When calling getCurrentBlockHeight Then it should return expected block height`() { + val expectedHeight = 12345 + every { proxy.getCurrentBlockHeight() } returns expectedHeight + + val actualHeight = peerManagerSource.getCurrentBlockHeight() + + assert(actualHeight == expectedHeight) { + "Expected block height to be $expectedHeight but was $actualHeight" + } + } + + @Test + fun `Given proxy returns last block timestamp When calling getLastBlockTimestamp Then it should return expected timestamp`() { + val expectedTimestamp = 1699999999L + every { proxy.getLastBlockTimestamp() } returns expectedTimestamp + + val actualTimestamp = peerManagerSource.getLastBlockTimestamp() + + assert(actualTimestamp == expectedTimestamp) { + "Expected last block timestamp to be $expectedTimestamp but was $actualTimestamp" + } + } +} diff --git a/app/src/test/java/com/brainwallet/util/FakeSharedPreferences.kt b/app/src/test/java/com/brainwallet/util/FakeSharedPreferences.kt new file mode 100644 index 00000000..bebdffb3 --- /dev/null +++ b/app/src/test/java/com/brainwallet/util/FakeSharedPreferences.kt @@ -0,0 +1,107 @@ +package com.brainwallet.util + +import android.content.SharedPreferences + +class FakeSharedPreferences : SharedPreferences { + + private val data = mutableMapOf() + private val listeners = mutableSetOf() + + override fun getAll(): MutableMap = data.toMutableMap() + + override fun getString(key: String?, defValue: String?): String? = + data[key] as? String ?: defValue + + override fun getLong(key: String?, defValue: Long): Long = + (data[key] as? Long) ?: defValue + + override fun getInt(key: String?, defValue: Int): Int = + (data[key] as? Int) ?: defValue + + override fun getBoolean(key: String?, defValue: Boolean): Boolean = + (data[key] as? Boolean) ?: defValue + + override fun getFloat(key: String?, defValue: Float): Float = + (data[key] as? Float) ?: defValue + + override fun getStringSet(key: String?, defValues: MutableSet?): MutableSet? = + (data[key] as? MutableSet) ?: defValues + + override fun contains(key: String?): Boolean = data.containsKey(key) + + override fun edit(): SharedPreferences.Editor = FakeEditor() + + override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) { + listener?.let { listeners.add(it) } + } + + override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) { + listeners.remove(listener) + } + + inner class FakeEditor : SharedPreferences.Editor { + private val temp = mutableMapOf() + private val toRemove = mutableSetOf() + private var clear = false + + override fun putString(key: String?, value: String?): SharedPreferences.Editor { + temp[key!!] = value + return this + } + + override fun putLong(key: String?, value: Long): SharedPreferences.Editor { + temp[key!!] = value + return this + } + + override fun putInt(key: String?, value: Int): SharedPreferences.Editor { + temp[key!!] = value + return this + } + + override fun putBoolean(key: String?, value: Boolean): SharedPreferences.Editor { + temp[key!!] = value + return this + } + + override fun putFloat(key: String?, value: Float): SharedPreferences.Editor { + temp[key!!] = value + return this + } + + override fun putStringSet( + key: String?, + values: MutableSet? + ): SharedPreferences.Editor { + temp[key!!] = values + return this + } + + override fun remove(key: String?): SharedPreferences.Editor { + toRemove.add(key!!) + return this + } + + override fun clear(): SharedPreferences.Editor { + clear = true + return this + } + + override fun commit(): Boolean { + apply() + return true + } + + override fun apply() { + if (clear) { + data.clear() + } + toRemove.forEach { data.remove(it) } + data.putAll(temp) + // notify listeners + (temp.keys + toRemove).forEach { key -> + listeners.forEach { it.onSharedPreferenceChanged(this@FakeSharedPreferences, key) } + } + } + } +} diff --git a/app/src/test/java/com/brainwallet/util/TimeProviderTest.kt b/app/src/test/java/com/brainwallet/util/TimeProviderTest.kt new file mode 100644 index 00000000..1278c010 --- /dev/null +++ b/app/src/test/java/com/brainwallet/util/TimeProviderTest.kt @@ -0,0 +1,16 @@ +package com.brainwallet.util + +import org.junit.Test + +class TimeProviderTest { + + @Test + fun `returns provided nowGetter value`() { + val fixedTime = 123456789L + val timeProvider = TimeProvider { fixedTime } + + val result = timeProvider.now() + + assert(result == fixedTime) { "Expected $fixedTime but got $result" } + } +} From 58f0cd8422ba2d74d9fe2217999ae78913ed26e6 Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Sat, 30 Aug 2025 15:23:29 +0700 Subject: [PATCH 63/65] feat(#234): Implement language-specific Firebase messaging topics (#132) This commit introduces the ability to subscribe and unsubscribe from Firebase messaging topics based on the user's selected language. Key changes: - Added `MessagingTopicDataSource` to fetch topic configurations from a JSON file. - Added `MessagingTopicRepository` to manage topic data. - Added `MessagingTopicUseCase` to handle subscription logic. - Added `LanguageSwitcherUseCase` to orchestrate language switching and topic subscription updates. - Integrated topic subscription updates into `SettingsViewModel` and `ChangeLanguageBottomSheet`. - Added a `topics.json` asset file containing the topic definitions. - Included unit tests for the new data source, repository, and use cases. - Initialized messaging topics on app startup in `BrainwalletApp`. --- .../java/com/brainwallet/BrainwalletApp.kt | 3 + .../repository/MessagingTopicRepository.kt | 20 ++++ .../data/source/MessagingTopicDataSource.kt | 29 +++++ .../domain/LanguageSwitcherUseCase.kt | 16 +++ .../domain/MessagingTopicUseCase.kt | 36 ++++++ .../language/ChangeLanguageBottomSheet.kt | 4 +- .../ui/screens/home/SettingsViewModel.kt | 4 +- .../MessagingTopicRepositoryTest.kt | 71 ++++++++++++ .../source/MessagingTopicDataSourceTest.kt | 108 ++++++++++++++++++ .../domain/LanguageSwitcherUseCaseTest.kt | 39 +++++++ .../domain/MessagingTopicUseCaseTest.kt | 66 +++++++++++ 11 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/brainwallet/data/repository/MessagingTopicRepository.kt create mode 100644 app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt create mode 100644 app/src/main/java/com/brainwallet/domain/LanguageSwitcherUseCase.kt create mode 100644 app/src/main/java/com/brainwallet/domain/MessagingTopicUseCase.kt create mode 100644 app/src/test/java/com/brainwallet/data/repository/MessagingTopicRepositoryTest.kt create mode 100644 app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt create mode 100644 app/src/test/java/com/brainwallet/domain/LanguageSwitcherUseCaseTest.kt create mode 100644 app/src/test/java/com/brainwallet/domain/MessagingTopicUseCaseTest.kt diff --git a/app/src/main/java/com/brainwallet/BrainwalletApp.kt b/app/src/main/java/com/brainwallet/BrainwalletApp.kt index 9143a90f..e2f1db99 100644 --- a/app/src/main/java/com/brainwallet/BrainwalletApp.kt +++ b/app/src/main/java/com/brainwallet/BrainwalletApp.kt @@ -8,6 +8,7 @@ import android.content.res.Resources import com.appsflyer.AppsFlyerLib import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.di.AppModule +import com.brainwallet.domain.MessagingTopicUseCase import com.brainwallet.notification.NotificationHandler import com.brainwallet.presenter.activities.util.BRActivity import com.brainwallet.presenter.entities.ServiceItems @@ -32,6 +33,7 @@ open class BrainwalletApp : Application() { private val remoteConfigSource: RemoteConfigSource by inject() private val notificationHandler: NotificationHandler by inject() + private val messagingTopicHandler: MessagingTopicUseCase by inject() override fun onCreate() { super.onCreate() @@ -80,6 +82,7 @@ open class BrainwalletApp : Application() { modules(AppModule.dataModule, AppModule.module) } thread { remoteConfigSource.initialize() } + thread { messagingTopicHandler.initialize() } } // override fun attachBaseContext(base: Context) { diff --git a/app/src/main/java/com/brainwallet/data/repository/MessagingTopicRepository.kt b/app/src/main/java/com/brainwallet/data/repository/MessagingTopicRepository.kt new file mode 100644 index 00000000..25947009 --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/repository/MessagingTopicRepository.kt @@ -0,0 +1,20 @@ +package com.brainwallet.data.repository + +import com.brainwallet.data.model.Language +import com.brainwallet.data.source.MessagingTopicDataSource +import org.koin.core.annotation.Single + +@Single +class MessagingTopicRepository( + private val settingRepository: SettingRepository, + private val topicDataSource: MessagingTopicDataSource +) { + fun getCurrentTopics(): List { + val currentLanguage = settingRepository.getCurrentLanguage() + return topicDataSource.getTopicsByLanguageCode(currentLanguage.code) + } + + fun getTopicsByLanguage(language: Language): List { + return topicDataSource.getTopicsByLanguageCode(language.code) + } +} diff --git a/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt b/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt new file mode 100644 index 00000000..804b9aca --- /dev/null +++ b/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt @@ -0,0 +1,29 @@ +package com.brainwallet.data.source + +import com.brainwallet.data.model.Language +import org.koin.core.annotation.Single + +@Single +class MessagingTopicDataSource( + private val supportedLanguages: List = Language.entries, + private val defaultLanguage: Language = Language.ENGLISH +) { + fun getTopicsByLanguageCode(languageCode: String): List { + val baseLanguageCode = getBaseLanguageCode(languageCode) + return listOf( + "initial_$baseLanguageCode", + "news_$baseLanguageCode", + "promo_$baseLanguageCode", + "warn_$baseLanguageCode" + ) + } + + private fun getBaseLanguageCode(languageCode: String): String { + val normalizedLanguageCode = languageCode.split("_", "-").first().lowercase() + val targetLanguage = supportedLanguages.find { + it.code.split("-").first().lowercase() == normalizedLanguageCode + } ?: defaultLanguage + + return targetLanguage.code.split("-").first().lowercase() + } +} diff --git a/app/src/main/java/com/brainwallet/domain/LanguageSwitcherUseCase.kt b/app/src/main/java/com/brainwallet/domain/LanguageSwitcherUseCase.kt new file mode 100644 index 00000000..e1464759 --- /dev/null +++ b/app/src/main/java/com/brainwallet/domain/LanguageSwitcherUseCase.kt @@ -0,0 +1,16 @@ +package com.brainwallet.domain + +import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.SettingRepository +import org.koin.core.annotation.Single + +@Single +class LanguageSwitcherUseCase( + private val settingRepository: SettingRepository, + private val messagingTopicUseCase: MessagingTopicUseCase +) { + fun switchLanguage(newLanguage: Language) { + messagingTopicUseCase.subscribeByLanguage(newLanguage) + settingRepository.updateCurrentLanguage(newLanguage.code) + } +} diff --git a/app/src/main/java/com/brainwallet/domain/MessagingTopicUseCase.kt b/app/src/main/java/com/brainwallet/domain/MessagingTopicUseCase.kt new file mode 100644 index 00000000..7b1641cb --- /dev/null +++ b/app/src/main/java/com/brainwallet/domain/MessagingTopicUseCase.kt @@ -0,0 +1,36 @@ +package com.brainwallet.domain + +import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.MessagingTopicRepository +import com.google.firebase.messaging.FirebaseMessaging +import org.koin.core.annotation.Single + +@Single +class MessagingTopicUseCase( + private val messagingTopicRepository: MessagingTopicRepository, + private val firebaseMessaging: FirebaseMessaging = FirebaseMessaging.getInstance() +) { + fun initialize() { + val topics = messagingTopicRepository.getCurrentTopics() + subscribeToTopics(topics) + } + + fun subscribeByLanguage(newLanguage: Language) { + val currentTopics = messagingTopicRepository.getCurrentTopics() + unsubscribeFromTopics(currentTopics) + val newTopics = messagingTopicRepository.getTopicsByLanguage(newLanguage) + subscribeToTopics(newTopics) + } + + private fun subscribeToTopics(topics: List) { + topics.forEach { topic -> + firebaseMessaging.subscribeToTopic(topic) + } + } + + private fun unsubscribeFromTopics(topics: List) { + topics.forEach { topic -> + firebaseMessaging.unsubscribeFromTopic(topic) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/language/ChangeLanguageBottomSheet.kt b/app/src/main/java/com/brainwallet/presenter/language/ChangeLanguageBottomSheet.kt index 77bb688b..a1ff0249 100644 --- a/app/src/main/java/com/brainwallet/presenter/language/ChangeLanguageBottomSheet.kt +++ b/app/src/main/java/com/brainwallet/presenter/language/ChangeLanguageBottomSheet.kt @@ -10,6 +10,7 @@ import com.brainwallet.R import com.brainwallet.data.model.Language import com.brainwallet.data.repository.SettingRepository import com.brainwallet.databinding.ChangeLanguageBottomSheetBinding +import com.brainwallet.domain.LanguageSwitcherUseCase import com.brainwallet.navigation.LegacyNavigation import com.brainwallet.tools.util.Utils import com.brainwallet.tools.util.getString @@ -23,6 +24,7 @@ class ChangeLanguageBottomSheet : RoundedBottomSheetDialogFragment() { lateinit var binding: ChangeLanguageBottomSheetBinding private val settingRepository by inject() + private val languageSwitcherUseCase by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -65,7 +67,7 @@ class ChangeLanguageBottomSheet : RoundedBottomSheetDialogFragment() { binding.okButton.setOnClickListener { if (settingRepository.getCurrentLanguage() != adapter.selectedLanguage()) { - settingRepository.updateCurrentLanguage(adapter.selectedLanguage().code) + languageSwitcherUseCase.switchLanguage(adapter.selectedLanguage()) LegacyNavigation.openComposeScreen( context = requireContext(), ) diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt index 46f5c426..75f59e71 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt @@ -8,6 +8,7 @@ import com.brainwallet.data.model.Language import com.brainwallet.data.model.toFeeOptions import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.domain.LanguageSwitcherUseCase import com.brainwallet.tools.manager.FeeManager import com.brainwallet.ui.BrainwalletViewModel import com.brainwallet.util.EventBus @@ -27,6 +28,7 @@ import org.koin.android.annotation.KoinViewModel @KoinViewModel class SettingsViewModel( private val settingRepository: SettingRepository, + private val languageSwitcherUseCase: LanguageSwitcherUseCase, private val ltcRepository: LtcRepository ) : BrainwalletViewModel() { @@ -127,7 +129,7 @@ class SettingsViewModel( ) }.let { viewModelScope.launch { - settingRepository.save(appSetting.value.copy(languageCode = event.language.code)) + languageSwitcherUseCase.switchLanguage(event.language) AppCompatDelegate.setApplicationLocales( LocaleListCompat.forLanguageTags( event.language.code diff --git a/app/src/test/java/com/brainwallet/data/repository/MessagingTopicRepositoryTest.kt b/app/src/test/java/com/brainwallet/data/repository/MessagingTopicRepositoryTest.kt new file mode 100644 index 00000000..9e221314 --- /dev/null +++ b/app/src/test/java/com/brainwallet/data/repository/MessagingTopicRepositoryTest.kt @@ -0,0 +1,71 @@ +package com.brainwallet.data.repository + +import com.brainwallet.data.model.Language +import com.brainwallet.data.source.MessagingTopicDataSource +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.junit.Before +import org.junit.Test + +class MessagingTopicRepositoryTest { + + @MockK + private lateinit var mockSettingRepository: SettingRepository + + @MockK + private lateinit var mockTopicDataSource: MessagingTopicDataSource + + private lateinit var repository: MessagingTopicRepository + + private lateinit var fakeIndonesianTopics: List + private lateinit var fakeEnglishTopics: List + + @Before + fun setUp() { + MockKAnnotations.init(this) + fakeIndonesianTopics = listOf("initial_in", "news_in", "promo_in", "warn_in") + fakeEnglishTopics = listOf("initial_en", "news_en", "promo_en", "warn_en") + repository = MessagingTopicRepository(mockSettingRepository, mockTopicDataSource) + } + + @Test + fun `given current language code is in when getCurrentTopics called then repository should return topics for Indonesian`() { + every { mockSettingRepository.getCurrentLanguage().code } returns "in" + every { mockTopicDataSource.getTopicsByLanguageCode("in") } returns fakeIndonesianTopics + + val result = repository.getCurrentTopics() + + assert(result == fakeIndonesianTopics) { + "Expected repository to return topics for Indonesian but got $result" + } + verify(exactly = 1) { mockTopicDataSource.getTopicsByLanguageCode("in") } + } + + @Test + fun `given language object when getTopicsByLanguage called then repository should return topics for that language`() { + val language = Language.INDONESIAN + every { mockTopicDataSource.getTopicsByLanguageCode(language.code) } returns fakeIndonesianTopics + + val result = repository.getTopicsByLanguage(language) + + assert(result == fakeIndonesianTopics) { + "Expected repository to return topics for Indonesian language but got $result" + } + verify(exactly = 1) { mockTopicDataSource.getTopicsByLanguageCode(language.code) } + } + + @Test + fun `given English language when getTopicsByLanguage called then repository should return English topics`() { + val language = Language.ENGLISH + every { mockTopicDataSource.getTopicsByLanguageCode(language.code) } returns fakeEnglishTopics + + val result = repository.getTopicsByLanguage(language) + + assert(result == fakeEnglishTopics) { + "Expected repository to return topics for English language but got $result" + } + verify(exactly = 1) { mockTopicDataSource.getTopicsByLanguageCode(language.code) } + } +} diff --git a/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt b/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt new file mode 100644 index 00000000..cea284d5 --- /dev/null +++ b/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt @@ -0,0 +1,108 @@ +package com.brainwallet.data.source + +import com.brainwallet.data.model.Language +import org.junit.Before +import org.junit.Test + +class MessagingTopicDataSourceTest { + private lateinit var dataSource: MessagingTopicDataSource + + @Before + fun setUp() { + dataSource = MessagingTopicDataSource() + } + + @Test + fun `given locale with underscore when getTopicsByLanguageCode called then it should extract base language only`() { + val result = dataSource.getTopicsByLanguageCode("fr_FR") + + val expectedTopics = listOf("initial_fr", "news_fr", "promo_fr", "warn_fr") + assert(result == expectedTopics) { + "Expected topics for French language from 'fr_FR' but got $result" + } + } + + @Test + fun `given locale with hyphen when getTopicsByLanguageCode called then it should extract base language only`() { + val result = dataSource.getTopicsByLanguageCode("zh-CN") + + val expectedTopics = listOf("initial_zh", "news_zh", "promo_zh", "warn_zh") + assert(result == expectedTopics) { + "Expected topics for Chinese language from 'zh-CN' but got $result" + } + } + + @Test + fun `given uppercase language code when getTopicsByLanguageCode called then it should normalize to lowercase`() { + val result = dataSource.getTopicsByLanguageCode("FR") + + val expectedTopics = listOf("initial_fr", "news_fr", "promo_fr", "warn_fr") + assert(result == expectedTopics) { + "Expected topics for French language from uppercase 'FR' but got $result" + } + } + + @Test + fun `given mixed case locale when getTopicsByLanguageCode called then it should normalize to lowercase base`() { + val result = dataSource.getTopicsByLanguageCode("Es_ES") + + val expectedTopics = listOf("initial_es", "news_es", "promo_es", "warn_es") + assert(result == expectedTopics) { + "Expected topics for Spanish language from 'Es_ES' but got $result" + } + } + + @Test + fun `given empty string when getTopicsByLanguageCode called then it should default to English`() { + val result = dataSource.getTopicsByLanguageCode("") + + val expectedTopics = listOf("initial_en", "news_en", "promo_en", "warn_en") + assert(result == expectedTopics) { + "Expected topics to default to English for empty string but got $result" + } + } + + @Test + fun `given unsupported language code when getTopicsByLanguageCode called then it should default to English`() { + val result = dataSource.getTopicsByLanguageCode("unsupported") + + val expectedTopics = listOf("initial_en", "news_en", "promo_en", "warn_en") + assert(result == expectedTopics) { + "Expected topics to default to English for unsupported language but got $result" + } + } + + @Test + fun `given all supported languages when getTopicsByLanguageCode called then it should return correct base language topics`() { + val testCases = mapOf( + "en" to "en", + "es" to "es", + "in" to "in", + "ar" to "ar", + "uk" to "uk", + "ru" to "ru", + "pt" to "pt", + "hi" to "hi", + "de" to "de", + "fa" to "fa", + "pa" to "pa", + "pl" to "pl", + "ko" to "ko", + "fr" to "fr", + "zh-TW" to "zh", + "zh-CN" to "zh", + "tr" to "tr", + "ja" to "ja", + "it" to "it", + "sv" to "sv" + ) + + testCases.forEach { (input, expectedBase) -> + val result = dataSource.getTopicsByLanguageCode(input) + val expectedTopics = listOf("initial_$expectedBase", "news_$expectedBase", "promo_$expectedBase", "warn_$expectedBase") + assert(result == expectedTopics) { + "Expected topics for '$input' to have base '$expectedBase' but got $result" + } + } + } +} diff --git a/app/src/test/java/com/brainwallet/domain/LanguageSwitcherUseCaseTest.kt b/app/src/test/java/com/brainwallet/domain/LanguageSwitcherUseCaseTest.kt new file mode 100644 index 00000000..15dd7efd --- /dev/null +++ b/app/src/test/java/com/brainwallet/domain/LanguageSwitcherUseCaseTest.kt @@ -0,0 +1,39 @@ +package com.brainwallet.domain + +import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.SettingRepository +import io.mockk.MockKAnnotations +import io.mockk.impl.annotations.MockK +import io.mockk.verifyOrder +import org.junit.Before +import org.junit.Test + +class LanguageSwitcherUseCaseTest { + + private lateinit var useCase: LanguageSwitcherUseCase + + @MockK + private lateinit var mockSettingRepository: SettingRepository + + @MockK + private lateinit var mockMessagingTopicUseCase: MessagingTopicUseCase + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxUnitFun = true) + useCase = LanguageSwitcherUseCase(mockSettingRepository, mockMessagingTopicUseCase) + } + + @Test + fun `given new language when switchLanguage called then it should subscribe by language and update current language`() { + val newLanguage = Language.FRENCH + + useCase.switchLanguage(newLanguage) + + // Order is important to make old subscribed language still valid + verifyOrder { + mockMessagingTopicUseCase.subscribeByLanguage(newLanguage) + mockSettingRepository.updateCurrentLanguage(newLanguage.code) + } + } +} diff --git a/app/src/test/java/com/brainwallet/domain/MessagingTopicUseCaseTest.kt b/app/src/test/java/com/brainwallet/domain/MessagingTopicUseCaseTest.kt new file mode 100644 index 00000000..a026737f --- /dev/null +++ b/app/src/test/java/com/brainwallet/domain/MessagingTopicUseCaseTest.kt @@ -0,0 +1,66 @@ +package com.brainwallet.domain + +import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.MessagingTopicRepository +import com.google.firebase.messaging.FirebaseMessaging +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.verify +import org.junit.Before +import org.junit.Test + +class MessagingTopicUseCaseTest { + + private lateinit var useCase: MessagingTopicUseCase + + @MockK + private lateinit var mockRepository: MessagingTopicRepository + + @RelaxedMockK + private lateinit var mockFirebaseMessaging: FirebaseMessaging + private lateinit var currentTopics: List + private lateinit var newTopics: List + + @Before + fun setUp() { + MockKAnnotations.init(this) + currentTopics = listOf("initial_en", "news_en", "promo_en", "warn_en") + newTopics = listOf("initial_fr", "news_fr", "promo_fr", "warn_fr") + + useCase = MessagingTopicUseCase(mockRepository, mockFirebaseMessaging) + } + + @Test + fun `given current topics when initialize called then it should subscribe to all current topics`() { + every { mockRepository.getCurrentTopics() } returns currentTopics + + useCase.initialize() + + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("initial_en") } + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("news_en") } + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("promo_en") } + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("warn_en") } + } + + @Test + fun `given current topics and new language when subscribeByLanguage called then it should unsubscribe old and subscribe new`() { + every { mockRepository.getCurrentTopics() } returns currentTopics + every { mockRepository.getTopicsByLanguage(any()) } returns newTopics + + val newLanguage = Language.FRENCH + + useCase.subscribeByLanguage(newLanguage) + + verify(exactly = 1) { mockFirebaseMessaging.unsubscribeFromTopic("initial_en") } + verify(exactly = 1) { mockFirebaseMessaging.unsubscribeFromTopic("news_en") } + verify(exactly = 1) { mockFirebaseMessaging.unsubscribeFromTopic("promo_en") } + verify(exactly = 1) { mockFirebaseMessaging.unsubscribeFromTopic("warn_en") } + + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("initial_fr") } + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("news_fr") } + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("promo_fr") } + verify(exactly = 1) { mockFirebaseMessaging.subscribeToTopic("warn_fr") } + } +} From 4bb06cfa7c1a1a8815bbd77945dbb1972b48ddf8 Mon Sep 17 00:00:00 2001 From: Kerry Washington Date: Sat, 30 Aug 2025 11:07:50 +0100 Subject: [PATCH 64/65] bump code --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index abf18b73..6f6d2220 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,7 +21,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 36 - versionCode = 202506295 + versionCode = 202506296 versionName = "v4.7.2" multiDexEnabled = true From 9f4908b4a438b85a226d00dcf0b2afe3cec6abdc Mon Sep 17 00:00:00 2001 From: Joseph Sanjaya Date: Sat, 30 Aug 2025 17:33:14 +0700 Subject: [PATCH 65/65] chore(#234): normalize Indonesian language code to "id" (#133) The Indonesian language code "in" is normalized to "id" in `MessagingTopicDataSource` to align with the ISO 639-1 standard used by the backend. This ensures consistency in topic generation for Indonesian language users. Tests have been added to verify this normalization for both "in" and "in_ID" inputs. --- .../data/source/MessagingTopicDataSource.kt | 21 +++++++++- .../source/MessagingTopicDataSourceTest.kt | 38 +++++++++++++++++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt b/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt index 804b9aca..530d77a8 100644 --- a/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt +++ b/app/src/main/java/com/brainwallet/data/source/MessagingTopicDataSource.kt @@ -18,12 +18,29 @@ class MessagingTopicDataSource( ) } + /** + * Note: Indonesian language code is normalized from "in" to "id" to maintain + * consistency with backend batch messaging server which uses ISO 639-1 standard. + * Supports both "in" and "id" as input for Indonesian language. + */ private fun getBaseLanguageCode(languageCode: String): String { val normalizedLanguageCode = languageCode.split("_", "-").first().lowercase() + + // Handle reverse mapping: if "id" is passed, treat it as Indonesian + val searchCode = when (normalizedLanguageCode) { + "id" -> "in" + else -> normalizedLanguageCode + } + val targetLanguage = supportedLanguages.find { - it.code.split("-").first().lowercase() == normalizedLanguageCode + it.code.split("-").first().lowercase() == searchCode } ?: defaultLanguage - return targetLanguage.code.split("-").first().lowercase() + val baseCode = targetLanguage.code.split("-").first().lowercase() + + return when (baseCode) { + "in" -> "id" + else -> baseCode + } } } diff --git a/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt b/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt index cea284d5..57e51bd5 100644 --- a/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt +++ b/app/src/test/java/com/brainwallet/data/source/MessagingTopicDataSourceTest.kt @@ -1,6 +1,5 @@ package com.brainwallet.data.source -import com.brainwallet.data.model.Language import org.junit.Before import org.junit.Test @@ -72,12 +71,45 @@ class MessagingTopicDataSourceTest { } } + @Test + fun `given Indonesian language code when getTopicsByLanguageCode called then it should normalize to id for backend consistency`() { + val result = dataSource.getTopicsByLanguageCode("in") + + val expectedTopics = listOf("initial_id", "news_id", "promo_id", "warn_id") + assert(result == expectedTopics) { + "Expected Indonesian language code 'in' to be normalized to 'id' for backend consistency but got $result" + } + } + + @Test + fun `given Indonesian locale with region when getTopicsByLanguageCode called then it should normalize to id`() { + val result = dataSource.getTopicsByLanguageCode("in_ID") + + val expectedTopics = listOf("initial_id", "news_id", "promo_id", "warn_id") + assert(result == expectedTopics) { + "Expected Indonesian locale 'in_ID' to be normalized to 'id' for backend consistency but got $result" + } + } + + @Test + fun `given id language code when getTopicsByLanguageCode called then it should be recognized as Indonesian`() { + val result = dataSource.getTopicsByLanguageCode("id") + + val expectedTopics = listOf("initial_id", "news_id", "promo_id", "warn_id") + assert(result == expectedTopics) { + "Expected 'id' language code to be recognized as Indonesian and return Indonesian topics but got $result" + } + } + @Test fun `given all supported languages when getTopicsByLanguageCode called then it should return correct base language topics`() { val testCases = mapOf( "en" to "en", - "es" to "es", - "in" to "in", + "es" to "es", + // Check All possible indonesian combination + "in" to "id", + "in_ID" to "id", + "id" to "id", "ar" to "ar", "uk" to "uk", "ru" to "ru",

lq3k*XJLTkQC}g)aqX~= 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