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
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 12 additions & 6 deletions app/src/main/java/com/brainwallet/BrainwalletApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,41 @@ 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()

initializeModule()

/** DEV: Top placement requirement. **/
val enableCrashlytics = !Utils.isEmulatorOrDebug(this)
setupNotificationChannels(this)
notificationHandler.setupNotificationChannels(this)

AnalyticsManager.init(this)
AnalyticsManager.logCustomEvent(BRConstants._20191105_AL)
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
}
83 changes: 0 additions & 83 deletions app/src/main/java/com/brainwallet/data/repository/LtcRepository.kt
Original file line number Diff line number Diff line change
@@ -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<CurrencyEntity>
Expand All @@ -26,79 +16,6 @@ interface LtcRepository {

suspend fun fetchMoonpaySignedUrl(params: Map<String, String>): 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<CurrencyEntity> {
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<String, String>): GetMoonpayBuyQuoteResponse =
remoteApiSource.getBuyQuote(params)

override suspend fun fetchMoonpaySignedUrl(params: Map<String, String>): 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"
Expand Down
Original file line number Diff line number Diff line change
@@ -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<CurrencyEntity> {
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<String, String>): GetMoonpayBuyQuoteResponse =
remoteApiSource.getBuyQuote(params)

override suspend fun fetchMoonpaySignedUrl(params: Map<String, String>): 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()
}

}
Loading