Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
a746d3d
Merge pull request #53 from gruntsoftware/release/v4.4.1
kcw-grunt Mar 30, 2025
ba8ea45
Revert "Updated the APIManager"
kcw-grunt Mar 31, 2025
638ce3a
Reverted the Kotlin APIManager.
kcw-grunt Mar 31, 2025
5344a96
Add version and code to welcome screen
kcw-grunt Mar 31, 2025
ebc3bb9
reset padding
kcw-grunt Mar 31, 2025
03c68b8
Merge pull request #56 from gruntsoftware/feature/add-version-issue-108
kcw-grunt Apr 1, 2025
c770f01
Revert "Updated the APIManager"
kcw-grunt Mar 31, 2025
f8c1bd5
Reverted the Kotlin APIManager.
kcw-grunt Mar 31, 2025
ff58b57
fix: fix crash when FragmentSignal dismissed
andhikayuana Apr 4, 2025
d64ea93
fix: fix sync after wipe
andhikayuana Apr 7, 2025
277f387
Merge branch 'hotfix/api-manager-fix' of https://github.com/brainwall…
kcw-grunt Apr 7, 2025
9a8a20f
fix: fix wrong lifecycle to trigger callback at FragmentSignal
andhikayuana Apr 7, 2025
832fa36
Update issue templates
kcw-grunt Apr 8, 2025
b294cd6
updated core changes
kcw-grunt Apr 8, 2025
4ed8af3
Merge pull request #57 from gruntsoftware/hotfix/api-manager-fix
kcw-grunt Apr 8, 2025
089995a
Rename .java to .kt
andhikayuana Apr 11, 2025
7e85987
chore: refactor BRApiManager & APIClient
andhikayuana Apr 11, 2025
0aa41e7
chore: remove unused part at APIClient
andhikayuana Apr 14, 2025
0cc29cb
feat: wip new peer discovery
andhikayuana Apr 14, 2025
54d2d9e
feat: implement selected peer ip address from cache (fetched from API)
andhikayuana Apr 14, 2025
c6923b1
feat: implement selected peer ip address from cache (fetched from API)
andhikayuana Apr 14, 2025
ef4e6d2
feat: filter out peers with NODE_NETWORK, NODE_BLOOM
andhikayuana Apr 15, 2025
2336939
fix: race condition when clear shared prefs values after wipeAll
andhikayuana Apr 16, 2025
51a4d9a
Merge pull request #62 from gruntsoftware/hotfix/prefs-race-condition
kcw-grunt Apr 16, 2025
62afb9d
Merge pull request #61 from gruntsoftware/feat/new-peer-discovery
kcw-grunt Apr 16, 2025
391e319
Updating the core library
kcw-grunt Apr 16, 2025
836b6f0
Chore/revert pre peer discovery (Android) (#69)
andhikayuana Apr 25, 2025
3caa1a7
feat: remove unused activity (ImportActivity) at AndroidManifest.xml …
andhikayuana Apr 29, 2025
a324444
fix: fix crash IllegalStateException: cannot make a new request becau…
andhikayuana May 2, 2025
1f9c5d0
code bump
kcw-grunt May 2, 2025
7ca17d3
Feat/move tx fee (#74)
andhikayuana May 5, 2025
e7fb2b7
fix: fix dismiss allow state loss (#76)
andhikayuana May 7, 2025
3d8ef98
fix: fix typo at strings.xml (#75)
andhikayuana May 7, 2025
25be1a8
feat: new UI for receive and topup flow (moonpay integration) (#72)
andhikayuana May 12, 2025
18eda46
version and code bump
kcw-grunt May 12, 2025
dbb6a5f
Added support url (#81)
kcw-grunt May 19, 2025
c82a5e3
version and code bump
kcw-grunt May 19, 2025
2981ec6
Revert from eda0f532 & cherry pick (#86)
andhikayuana May 25, 2025
c161fed
build bump
kcw-grunt May 25, 2025
63d7494
chore: open bread activity first then open moonpay widget (#88)
andhikayuana May 26, 2025
f09eb28
Adjustment for circleci (#89)
andhikayuana May 29, 2025
47c69cd
fix: android: Footer version label is obfuscated (#92)
andhikayuana May 29, 2025
a9c4a63
fix: You saved it right screen reset button covers words (#93)
andhikayuana May 29, 2025
d8f08ad
tiny resizing (#94)
kcw-grunt May 29, 2025
ef93585
code and version bump
kcw-grunt May 29, 2025
174d612
change break (#97)
kcw-grunt May 30, 2025
a4521d7
build code number
andhikayuana May 31, 2025
6fec1e2
fix: [#137] fix: Reset fiat options in Buy / Receive modal (#99)
andhikayuana Jun 2, 2025
c8fdf8d
Chore/update device data (#100)
kcw-grunt Jun 2, 2025
3f646df
Add agent string obfuscation (#103)
kcw-grunt Jun 14, 2025
642f9e6
updated metadata (#105)
kcw-grunt Jun 24, 2025
50f44de
chore: remove screen lock detection (#106)
andhikayuana Jun 24, 2025
ea15423
🧰 Fx/seed words UI polish (#108)
kcw-grunt Jun 25, 2025
5b6dff3
❇️ Feat/add polish punjabi farsi (#109)
kcw-grunt Jun 27, 2025
4ff50b8
fix: fix YourSeedProveItState.isWordUsedCorrectly (#111)
andhikayuana Jun 29, 2025
2fd094f
Upgrade targetSdk 36 (#113)
andhikayuana Aug 5, 2025
4efd95f
feat(#195): adopt koin annotation for dependency injection (#120)
JosephSanjaya Aug 18, 2025
5900ed4
Create PULL_REQUEST_TEMPLATE.md
kcw-grunt Aug 19, 2025
3b1f628
bump for test (#121)
kcw-grunt Aug 19, 2025
f11d5a8
feat(#174): initiate games module (#119)
JosephSanjaya Aug 20, 2025
77ed7df
Force pushed the version and code bump and catch up with Prod.
kcw-grunt Aug 20, 2025
ef353e3
πŸš€[Release v4.7.2] Merge into Develop (#127)
kcw-grunt Aug 25, 2025
e25e9e1
Fix(#227): Crash when launching MoonPay Widget (#126)
JosephSanjaya Aug 25, 2025
e0aebb5
feat(#138): Improve Unlock Screen UI and add dark mode toggle (#122)
JosephSanjaya Aug 25, 2025
7d8dd14
Redesign welcome screen (#123)
josikie Aug 25, 2025
18df293
fix(#226): android test failure on RecoverWalletScreenGrabsTest (#130)
JosephSanjaya Aug 26, 2025
9b191b7
fix(#223): fix issue on test environment SLF4J + agent warnings in te…
JosephSanjaya Aug 26, 2025
c9b1ef0
feat(#225): Send sync duration in Firebase Analytics as a custom even…
JosephSanjaya Aug 30, 2025
58f0cd8
feat(#234): Implement language-specific Firebase messaging topics (#132)
JosephSanjaya Aug 30, 2025
4bb06cf
bump code
kcw-grunt Aug 30, 2025
9f4908b
chore(#234): normalize Indonesian language code to "id" (#133)
JosephSanjaya Aug 30, 2025
4a27ae0
Feat: Detekt and Test Plugins, (Including Create Detekt Baseline) (#136)
JosephSanjaya Sep 22, 2025
3285d8e
Chore/renamed gp module (#140)
kcw-grunt Sep 29, 2025
94459d0
create private gp submodule
kcw-grunt Sep 23, 2025
13c39a0
Update settings.gradle.kts
kcw-grunt Sep 23, 2025
c0683ad
chore: Migrate build logic to version catalog and update submodules
JosephSanjaya Sep 24, 2025
2fcb1b2
feat(deps): add kotlin-immutable dependency
JosephSanjaya Oct 5, 2025
631b4f6
refactor(app): Relocate core module imports
JosephSanjaya Oct 8, 2025
0b46614
Merge pull request #141 from gruntsoftware/js/feat/iap
JosephSanjaya Oct 9, 2025
279fa23
build bump
kcw-grunt Oct 9, 2025
5ea5fe9
Merge branch 'main' into release/v4.8.0
kcw-grunt Oct 9, 2025
779f47f
removed cruft
kcw-grunt Oct 9, 2025
05813ad
chore(submodules): remove bugged games repository
JosephSanjaya Oct 10, 2025
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
7 changes: 5 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ commands:
EOL
ls && cat local.properties
- run:
name: "Initialize submodule"
command: "git submodule init && git submodule update --init --recursive"
name: Rewrite .gitmodules with token
command: |
sed -i "s#https://github.com/#https://${GH_TOKEN}@github.com/#g" .gitmodules
git submodule sync --recursive
git submodule update --init --recursive
- android/restore_gradle_cache

# Define a job to be invoked later in a workflow.
Expand Down
10 changes: 6 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
[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
[submodule "modules/private-general-purpose"]
path = modules/private-general-purpose
url = https://github.com/gruntsoftware/android-private-general-purpose.git
[submodule "gruntsoftware-build-logic"]
path = gruntsoftware-build-logic
url = https://github.com/gruntsoftware/android-build-logic.git
104 changes: 35 additions & 69 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import org.gradle.kotlin.dsl.grunt

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.jetbrains.kotlin.compose)
alias(grunt.plugins.android.application)
alias(grunt.plugins.jetbrains.kotlin.android)
alias(grunt.plugins.jetbrains.kotlin.compose)
alias(libs.plugins.jetbrains.kotlin.kapt)
alias(libs.plugins.jetbrains.kotlin.serialization)
alias(grunt.plugins.jetbrains.kotlin.serialization)
alias(libs.plugins.google.services)
alias(libs.plugins.firebase.crashlytics)
alias(libs.plugins.ksp)
alias(grunt.plugins.ksp)
alias(grunt.plugins.buildlogic.test)
alias(grunt.plugins.buildlogic.detekt)
}

val localProperties = gradleLocalProperties(rootDir, providers)
Expand All @@ -21,8 +24,8 @@ android {
applicationId = "ltd.grunt.brainwallet"
minSdk = 29
targetSdk = 36
versionCode = 202506296
versionName = "v4.7.2"
versionCode = 202506298
versionName = "v4.8.0"

multiDexEnabled = true
base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})")
Expand Down Expand Up @@ -161,13 +164,17 @@ android {
viewBinding = true
compose = true
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.valueOf("VERSION_${grunt.versions.jvm.target.get()}")
targetCompatibility = JavaVersion.valueOf("VERSION_${grunt.versions.jvm.target.get()}")
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
kotlin {
jvmToolchain(grunt.versions.jvm.target.get().toInt())
compilerOptions {
jvmTarget.set(
org.jetbrains.kotlin.gradle.dsl.JvmTarget.fromTarget(grunt.versions.jvm.target.get())
)
}
}

packaging {
Expand All @@ -179,24 +186,13 @@ android {
//TODO: rename output apk/bundle
}

val ktlint by configurations.creating

dependencies {
ktlint(libs.pinterest.ktlint) {
attributes {
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
}
}

val gamesModule = findProject(":modules:games:content")
if (gamesModule != null) {
implementation(gamesModule)
} else {
logger.lifecycle("⚠️ Submodule ':modules:games:content' not found β€” skipping dependency")
}

implementation(project(":games"))
implementation(project(":iap"))
implementation(project(":core"))
implementation("androidx.webkit:webkit:1.9.0")
implementation(libs.androidx.core)
implementation(grunt.androidx.core.ktx)
implementation(grunt.app.startup)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.legacy.support)
implementation(libs.androidx.recyclerview)
Expand All @@ -209,8 +205,10 @@ dependencies {
implementation(libs.bundles.androidx.lifecycle)
implementation(libs.androidx.work)
implementation(libs.androidx.browser)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.androidx.compose)
implementation(platform(grunt.androidx.compose.bom))
implementation(grunt.bundles.androidx.compose)
implementation(grunt.kotlin.immutable)
implementation(grunt.material)
implementation(libs.google.material)
implementation(libs.google.zxing)
implementation(platform(libs.firebase.bom))
Expand All @@ -222,11 +220,11 @@ dependencies {
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.coroutines.android)
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(grunt.koin.bom))
implementation(grunt.bundles.koin)
implementation(platform(grunt.koin.annotation.bom))
implementation(grunt.koin.annotation)
ksp(grunt.koin.annotation.compiler)

implementation(platform(libs.squareup.okhttp.bom))
implementation(libs.bundles.squareup.okhttp)
Expand All @@ -248,45 +246,13 @@ dependencies {
testImplementation(libs.slf4j.android)
testImplementation(libs.kotlinx.coroutines.tests)

androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.bundles.androidx.compose.ui.test)
androidTestImplementation(platform(grunt.androidx.compose.bom))
androidTestImplementation(grunt.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) {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = "Check Kotlin code style"
classpath = ktlint
mainClass.set("com.pinterest.ktlint.Main")
// see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information
args(
"**/src/**/*.kt",
"**.kts",
"!**/build/**",
)
}

tasks.check {
dependsOn(ktlintCheck)
}

tasks.register<JavaExec>("ktlintFormat") {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = "Check Kotlin code style and format"
classpath = ktlint
mainClass.set("com.pinterest.ktlint.Main")
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
// see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information
args(
"-F",
"**/src/**/*.kt",
"**.kts",
"!**/build/**",
)
}

tasks.withType<Test> {
jvmArgs("-XX:+EnableDynamicAgentLoading")
}
2 changes: 2 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
-dontwarn org.slf4j.impl.StaticMDCBinder
-dontwarn org.slf4j.impl.StaticMarkerBinder
-dontwarn java.lang.reflect.AnnotatedType
-dontwarn com.google.api.client.http.**
-dontwarn org.joda.time.**

-keepclasseswithmembernames class * {
native <methods>;
Expand Down
16 changes: 5 additions & 11 deletions app/src/androidTest/kotlin/flow/RecoverWalletScreenGrabsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,9 @@ class RecoverWalletScreenGrabsTest {
CleanStatusBar.disable()
}


@OptIn(ExperimentalTestApi::class)
@Test
fun onRecoverFlowSuccess() {

composeTestRule.activityRule.scenario.onActivity {
Screengrab.setDefaultScreenshotStrategy(FalconScreenshotStrategy(it))
}
Expand All @@ -102,7 +100,7 @@ class RecoverWalletScreenGrabsTest {

Screengrab.screenshot("2_input_words_screen")

//seed words input
// seed words input
val editTextTags = (0..11).map { index -> "textFieldSeedWord$index" }

val paperKey = BuildConfig.SCREENGRAB_PAPERKEY
Expand Down Expand Up @@ -148,7 +146,7 @@ class RecoverWalletScreenGrabsTest {

Screengrab.screenshot("6_main_screen")

//setting drawer
// setting drawer
onView(withId(R.id.menuBut)).perform(click())

Screengrab.screenshot("7_setting_drawer_open")
Expand Down Expand Up @@ -216,8 +214,7 @@ class RecoverWalletScreenGrabsTest {
uiDevice.waitForIdle()
Thread.sleep(1000)


//tx send ui
// tx send ui
onView(withId(R.id.nav_send)).perform(click())

onView(withId(R.id.amount_edit)).perform(click())
Expand All @@ -226,16 +223,14 @@ class RecoverWalletScreenGrabsTest {

onView(withId(R.id.close_button)).perform(click())


//tx buy/receive ui
// tx buy/receive ui
onView(withId(R.id.nav_receive)).perform(click())

Screengrab.screenshot("15_transaction_buy_receive")

composeTestRule.onNodeWithTag("buttonClose").performClick()

uiDevice.waitForIdle()

}

private fun waitUntilReady() {
Expand All @@ -262,5 +257,4 @@ class RecoverWalletScreenGrabsTest {
}
}
}

}
}
9 changes: 8 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@
tools:replace="android:fullBackupContent,android:allowBackup">

<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true" />

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data android:name="com.brainwallet.initializer.AppInitializer"
android:value="androidx.startup" />
</provider>
<!-- Main Compose Activity -->
<activity
android:name=".ui.BrainwalletActivity"
Expand Down
25 changes: 1 addition & 24 deletions app/src/main/java/com/brainwallet/BrainwalletApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import android.app.Application
import android.content.Context
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
Expand All @@ -17,29 +14,19 @@ 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()
private val messagingTopicHandler: MessagingTopicUseCase by inject()

override fun onCreate() {
super.onCreate()

initializeModule()

/** DEV: Top placement requirement. **/
val enableCrashlytics = !Utils.isEmulatorOrDebug(this)
notificationHandler.setupNotificationChannels(this)
Expand Down Expand Up @@ -75,16 +62,6 @@ open class BrainwalletApp : Application() {
appsFlyerLib.start(this)
}

protected open fun initializeModule() {
startKoin {
androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.ERROR)
androidContext(this@BrainwalletApp)
modules(AppModule.dataModule, AppModule.module)
}
thread { remoteConfigSource.initialize() }
thread { messagingTopicHandler.initialize() }
}

// override fun attachBaseContext(base: Context) {
// init(base)
// super.attachBaseContext(instance.setLocale(base))
Expand Down Expand Up @@ -136,7 +113,7 @@ open class BrainwalletApp : Application() {
return context == null || activityCounter.get() <= 0
}

//call onStop on evert activity so
// call onStop on evert activity so
@JvmStatic
fun onStop(app: BRActivity?) {
if (isBackgroundChecker != null) isBackgroundChecker!!.cancel()
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/brainwallet/data/model/AppSetting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ data class AppSetting(
-1f,
"$"
)
)
)
2 changes: 1 addition & 1 deletion app/src/main/java/com/brainwallet/data/model/Country.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.brainwallet.data.model

data class Country(val name: String, val code: String)
data class Country(val name: String, val code: String)
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import java.io.Serializable
@kotlinx.serialization.Serializable
data class CurrencyEntity(
@JvmField
var code: String ="",
var code: String = "",
@JvmField
var name: String = "",
@JvmField
@SerialName("n")
var rate: Float = 0F,
@JvmField
var symbol: String = ""
) : Serializable
) : Serializable
3 changes: 1 addition & 2 deletions app/src/main/java/com/brainwallet/data/model/Fee.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ data class Fee(
}
}


data class FeeOption(
@FeeType
val type: String,
Expand Down Expand Up @@ -90,5 +89,5 @@ fun FeeOption.getFiatFormatted(currencyEntity: CurrencyEntity): String {

fun List<FeeOption>.getSelectedIndex(selectedFeeType: String): Int {
return indexOfFirst { it.type == selectedFeeType }.takeIf { it >= 0 }
?: 2 //2 -> index of top, since we have [low,medium,top]
?: 2 // 2 -> index of top, since we have [low,medium,top]
}
Loading