Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/java/com/brainwallet/constants/BWConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ object BWConstants {
const val TOS_LINK: String = "https://www.brainwallet.co/privacypolicy"
const val LINKTREE_URL: String = "https://linktr.ee/brainwallet"

const val BITREFILL_URL: String = "https://www.bitrefill.com/?ref=bAshL935"
const val BITREFILL_URL: String = "https://www.bitrefill.com/"

/**
* API Hosts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import com.brainwallet.data.model.Fee
import com.brainwallet.data.model.LtcStats
import com.brainwallet.data.model.MoonpayCurrencyLimit
import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow

interface LtcRepository {

val rates: StateFlow<List<CurrencyEntity>>
val rates: SharedFlow<List<CurrencyEntity>>
val ltcStats: StateFlow<LtcStats>

suspend fun fetchRates(): List<CurrencyEntity>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,56 @@ import com.brainwallet.data.model.LtcStats
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.PeerManagerSource
import com.brainwallet.data.source.RemoteApiSource
import com.brainwallet.data.source.RemoteConfigSource
import com.brainwallet.data.source.fetchWithCache
import com.brainwallet.data.source.response.GetMoonpayBuyQuoteResponse
import com.brainwallet.di.AppModule.json
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 kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.koin.core.annotation.Single
import timber.log.Timber

@Single(binds = [LtcRepository::class])
class LtcRepositoryImpl(
private val context: Context,
private val remoteApiSource: RemoteApiSource,
private val remoteConfigSource: RemoteConfigSource,
private val currencyDataSource: CurrencyDataSource,
private val peerManagerSource: PeerManagerSource,
private val repositoryScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO),
private val sharedPreferences: SharedPreferences,
) : LtcRepository {

private val _rates = MutableStateFlow<List<CurrencyEntity>>(emptyList())
override val rates: StateFlow<List<CurrencyEntity>> = _rates.asStateFlow()
// private val _rates = MutableStateFlow<List<CurrencyEntity>>(
// currencyDataSource.getAllCurrencies(true) // seed from cache immediately
// )
private val _rates = MutableSharedFlow<List<CurrencyEntity>>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
).apply {
// seed with cached values immediately, same as before
tryEmit(currencyDataSource.getAllCurrencies(true))
}
override val rates: SharedFlow<List<CurrencyEntity>> = _rates.asSharedFlow()
private val _ltcStats = MutableStateFlow(
LtcStats(
0,
Expand All @@ -40,12 +68,48 @@ class LtcRepositoryImpl(
0
)
)

private var syncingDelay = 60_000L
private var nonSyncingDelay = 4_000L

@Serializable
private data class SyncPoolerContentWrapper(
@SerialName("sync_delay") val syncDelayValue: Long = 60_000L,
@SerialName("non_sync_delay") val nonSyncDelayValue: Long = 4_000L
)

override val ltcStats: StateFlow<LtcStats> = _ltcStats.asStateFlow()

init {

repositoryScope.launch {
runCatching { remoteConfigSource.fetchAndActivate() }
.onFailure { Timber.e(it, "RemoteConfig fetch failed") }

val rawJson = remoteConfigSource.getString(RemoteConfigSource.KEY_SYNC_POLLER)
runCatching {
val config = json.decodeFromString<SyncPoolerContentWrapper>(rawJson)
syncingDelay = config.syncDelayValue
nonSyncingDelay = config.nonSyncDelayValue
}.onFailure { Timber.e(it, "RemoteConfig parse failed") }

while (isActive) {
runCatching { fetchRates() }
.onFailure { Timber.e(it, "fetchRates failed") }

val delay = if (peerManagerSource.blockInfo.value.syncProgress <= 0.95f) {
syncingDelay
} else {
nonSyncingDelay
}
Timber.d("timber|| duration in fetching $syncingDelay $nonSyncingDelay")
delay(delay)
}
}
}
override suspend fun fetchRates(): List<CurrencyEntity> {
return runCatching {
val rates = remoteApiSource.getRates()

FeeManager.updateFeePerKb(context)
val selectedISO = BRSharedPrefs.getIsoSymbol(context)
rates.forEachIndexed { index, currencyEntity ->
Expand All @@ -62,7 +126,7 @@ class LtcRepositoryImpl(
}.getOrElse {
currencyDataSource.getAllCurrencies(true)
}.also { result ->
_rates.value = result
_rates.emit(result)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ interface RemoteConfigSource {
const val KEY_FEATURE_MENU_HIDDEN_EXAMPLE = "feature_menu_hidden_example"
const val KEY_FEATURE_SELECTED_PEERS_ENABLED = "feature_selected_peers_enabled"
const val KEY_FEATURE_GAMEHUB_CONTENT = "feature_gamehub_content"
const val PATH_SHOP_CONTENT = "path_shop_content"
const val KEY_SYNC_POLLER = "key_sync_poller"
const val KEY_API_BASEURL_PROD_NEW_ENABLED = "key_api_baseurl_prod_new_enabled"
const val KEY_FEATURE_LTC_BROWSER_CONTENT = "feature_ltc_browser_content"
const val KEY_KEYSTORE_MANAGER_ENABLED = "key_keystore_manager_enabled"
const val KEY_DEV_API_BASEURL = "key_dev_api_baseurl"
const val KEY_API_BASEURL_DEV_NEW_ENABLED = "key_api_baseurl_dev_new_enabled"
const val KEY_PROD_API_BASEURL = "key_prod_api_baseurl"
}

fun initialize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.os.LocaleListCompat;

import com.brainwallet.BrainwalletApp;
import com.brainwallet.data.repository.SettingRepository;
import com.brainwallet.presenter.activities.DisabledActivity;
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.InternetManager;
import com.brainwallet.tools.security.AuthManager;
Expand All @@ -24,7 +21,6 @@
import com.brainwallet.tools.threads.BRExecutor;
import com.brainwallet.constants.BWConstants;
import com.brainwallet.wallet.BRWalletManager;
import com.brainwallet.worker.CurrencyUpdateWorker;

import org.koin.java.KoinJavaComponent;

Expand Down Expand Up @@ -144,12 +140,6 @@ public void run() {
public static void init(Activity app) {
InternetManager.getInstance();


if (!(app instanceof RecoverActivity || app instanceof WriteDownActivity)) {
CurrencyUpdateWorker currencyUpdateWorker = KoinJavaComponent.get(CurrencyUpdateWorker.class);
currencyUpdateWorker.start();
}

//show wallet locked if it is
if (!ActivityUTILS.isAppSafe(app))
if (AuthManager.getInstance().isWalletDisabled(app))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import com.brainwallet.data.repository.SettingRepository
import com.brainwallet.tools.sqlite.CurrencyDataSource
import com.brainwallet.ui.BrainwalletViewModel
import com.brainwallet.util.CurrencyDataGetter
import com.google.firebase.crashlytics.FirebaseCrashlytics
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
Expand All @@ -34,15 +32,6 @@ class LTCPickerBentoViewModel(
)

init {
viewModelScope.launch {
while (true) {
try { fetchAndUpdateRates() } catch (e: Exception) {
Timber.e(e, "fetchRates failed")
FirebaseCrashlytics.getInstance().recordException(e)
}
delay(5000L)
}
}
viewModelScope.launch {
settingRepository.settings.collect { setting ->
_state.update {
Expand All @@ -64,45 +53,45 @@ class LTCPickerBentoViewModel(
}
}
}
}
private suspend fun fetchAndUpdateRates(
currencyCode: String = settingRepository.currentSettings.value.currency.code
) {
val rates = ltcRepository.fetchRates()
val selectedFiat = rates.find { it.code == currencyCode }
val iso = currencyDataGetter.getIsoSymbol()

var formattedCurrency: String? = null
val currency = currencyDataGetter.getCurrencyByIso(iso)
if (currency != null) {
val roundedPriceAmount: BigDecimal =
BigDecimal(currency.rate.toDouble()).multiply(BigDecimal(100))
.divide(BigDecimal(100), 2, BWConstants.ROUNDING_MODE)
formattedCurrency =
currencyDataGetter.getFormattedCurrencyString(
iso,
roundedPriceAmount
)
} else {
Timber.w("The currency related to %s is NULL", iso)
}
_state.update {
it.copy(
selectedCurrency = selectedFiat ?: return@update it,
formattedFiat = formattedCurrency ?: "",
formattedTimeStamp = formatter.format(java.util.Date()),
ltcStats = ltcRepository.ltcStats.value
)
viewModelScope.launch {
ltcRepository.rates.collect { rates ->
runCatching {
Timber.d("timber|| rates in fetching $rates")
val currencyCode = _state.value.selectedCurrency.code
val selectedFiat = rates.find { it.code == currencyCode }
val iso = currencyDataGetter.getIsoSymbol()
val currency = currencyDataGetter.getCurrencyByIso(iso)

val formattedCurrency = currency?.let {
val rounded = BigDecimal(it.rate.toDouble())
.multiply(BigDecimal(100))
.divide(BigDecimal(100), 2, BWConstants.ROUNDING_MODE)
currencyDataGetter.getFormattedCurrencyString(iso, rounded)
}

if (selectedFiat != null) {
_state.update {
it.copy(
selectedCurrency = selectedFiat,
formattedFiat = formattedCurrency ?: "",
formattedTimeStamp = formatter.format(java.util.Date()),
ltcStats = ltcRepository.ltcStats.value
)
}
}
}.onFailure { Timber.e(it, "timber|| rates collector crashed") }
}
}
}

override fun onEvent(event: LTCPickerBentoEvent) {
when (event) {
is LTCPickerBentoEvent.OnGlobalCurrencyChange -> {
val newCurrency = currencyDataSource.getCurrencyByIso(event.globalCurrency.code)
if (newCurrency != null) {
viewModelScope.launch {
settingRepository.save(settingRepository.currentSettings.value.copy(currency = newCurrency))
fetchAndUpdateRates(newCurrency.code)
}
} else {
Timber.w("Currency not found for code: ${event.globalCurrency.code}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ fun MainScreen(
)

Route.BitrefillWeb -> WebModalScreen(
modifier = Modifier
.fillMaxSize(),
onNavigate = onNavigate,
url = BWConstants.BITREFILL_URL
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.brainwallet.ui.screens.main

import android.graphics.Bitmap
import android.view.ViewGroup
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.background
Expand All @@ -11,7 +13,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.brainwallet.navigation.OnNavigate
Expand All @@ -32,21 +33,43 @@ fun WebModalScreen(
LaunchedEffect(Unit) {
AnalyticsManager.logCustomEvent(eventString)
}
val context = LocalContext.current

Card(
modifier = modifier
.fillMaxSize()
.background(brush = bentoDarkSurfaceGradient),
shape = RoundedCornerShape(18.dp),
) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
WebView(context).apply {
webViewClient = WebViewClient()
loadUrl(url)
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)
}
}
}
},
modifier = Modifier.fillMaxSize()
update = {
it.loadUrl(url)
}
)
}
}
33 changes: 0 additions & 33 deletions app/src/main/java/com/brainwallet/worker/CurrencyUpdateWorker.kt

This file was deleted.

2 changes: 1 addition & 1 deletion app/src/main/jni/core
Submodule core updated from 28d7d3 to 31a712
Loading
Loading