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 android-build-logic
16 changes: 10 additions & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ android {
applicationId = "ltd.grunt.brainwallet"
minSdk = 29
targetSdk = 35
versionCode = 202506340
versionName = "v4.10.2"
versionCode = 202506341
versionName = "v4.10.3"
multiDexEnabled = true
base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -213,7 +213,6 @@ dependencies {
implementation(libs.androidx.espresso.core)
implementation(libs.androidx.runtime)
implementation(libs.androidx.foundation)
implementation(libs.androidx.animation)
implementation(libs.play.services.games)
ksp(grunt.koin.annotation.compiler)
implementation(platform(libs.squareup.okhttp.bom))
Expand All @@ -229,17 +228,20 @@ dependencies {
implementation(libs.razir.progressbutton)
implementation(libs.appsflyer)
implementation(libs.android.installreferrer)
implementation("androidx.compose.animation:animation:1.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7")
implementation("io.coil-kt:coil-compose:2.0.0-rc01")
implementation(libs.androidx.material3)
testImplementation(libs.junit)
testImplementation(libs.mockk)
testImplementation(libs.turbine)
testImplementation(libs.slf4j.android)
testImplementation(libs.kotlinx.coroutines.tests)
implementation("androidx.compose.animation:animation:1.10.6")
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7")
implementation("io.coil-kt:coil-compose:2.0.0-rc01")
implementation("androidx.emoji2:emoji2-emojipicker:1.6.0")
testImplementation("io.mockk:mockk:1.13.5")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
testImplementation("app.cash.turbine:turbine:1.0.0")
implementation("androidx.core:core-splashscreen:1.0.1")
androidTestImplementation(platform(grunt.androidx.compose.bom))
androidTestImplementation("androidx.test:core-ktx:1.5.0")
androidTestImplementation(grunt.bundles.androidx.compose.ui.test)
Expand All @@ -260,6 +262,8 @@ dependencies {
implementation("com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64")
implementation("ltd.grunt.brainwallet.gdx:core:1.14.1")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")


}

tasks.withType<Test> {
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<activity
android:name=".ui.BrainwalletActivity"
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -94,6 +95,7 @@
<activity
android:name=".presenter.activities.BreadActivity"
android:exported="true"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustPan">
<intent-filter>
Expand Down Expand Up @@ -122,41 +124,49 @@
android:name=".presenter.activities.settings.SyncBlockchainActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.settings.NotificationActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.intro.WriteDownActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.camera.ScanQRActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.DisabledActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.settings.NodesActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.camera.CameraActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>
<activity
android:name=".presenter.activities.settings.TestActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
/>

<service
Expand Down
55 changes: 55 additions & 0 deletions app/src/main/java/com/brainwallet/appreview/InAppReviewService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.brainwallet.appreview

import android.app.Activity
import android.app.Application
import com.brainwallet.constants.BWConstants
import com.brainwallet.tools.manager.AnalyticsManager
import com.brainwallet.tools.manager.BRSharedPrefs
import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.gms.tasks.Task
import com.google.android.play.core.review.ReviewInfo
import com.google.android.play.core.review.ReviewManagerFactory
import timber.log.Timber
import java.lang.Void

class InAppReviewService(
private val app: Application,
private val activityProvider: () -> Activity?,

) {
public fun showInAppReviewDialogIfNeeded() {
val activity = activityProvider() ?: return
if (!BRSharedPrefs.isInAppReviewDone(app) &&
BRSharedPrefs.getSendTransactionCount(app) > 2
) {
val manager = ReviewManagerFactory.create(app)
val request = manager.requestReviewFlow()
request.addOnCompleteListener(
OnCompleteListener { task: Task<ReviewInfo>? ->
AnalyticsManager.logCustomEvent(BWConstants._20241006_DRR)
if (task!!.isSuccessful()) {
val reviewInfo = task.getResult()
val flow = manager.launchReviewFlow(activity, reviewInfo)
flow.addOnCompleteListener(
OnCompleteListener { task1: Task<Void?>? ->
// The flow has finished. The API does not indicate whether the user
// reviewed or not, or even whether the review dialog was shown. Thus, no
// matter the result, we continue our app flow.
Timber.i(
"timber: In-app LaunchReviewFlow completed successful (%s)",
task1!!.isSuccessful()
)
if (task1.isSuccessful()) {
BRSharedPrefs.inAppReviewDone(app)
AnalyticsManager.logCustomEvent(BWConstants._20241006_UCR)
}
}
)
} else {
Timber.e(task.getException(), "In-app request review flow failed")
}
}
)
}
}
}
6 changes: 6 additions & 0 deletions app/src/main/java/com/brainwallet/constants/BWConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ object BWConstants {
const val PUT_PHRASE_NEW_WALLET_REQUEST_CODE: Int = 114
const val PUT_PHRASE_RECOVERY_WALLET_REQUEST_CODE: Int = 115
const val PROVE_PHRASE_REQUEST: Int = 119
const val SHOW_EMOJIS_REQUEST_CODE: Int = 120

const val PUT_EMOJIS_REQUEST_CODE: Int = 121

const val CLEAR_EMOJIS_REQUEST_CODE: Int = 122

/**
* Request codes for taking pictures
Expand All @@ -71,6 +76,7 @@ object BWConstants {
const val CURRENT_UNIT: String = "currencyUnit"
const val POSITION: String = "position"
const val PHRASE_WRITTEN: String = "phraseWritten"
const val EMOJIS_CHOSEN: String = "emojisChosen"
const val ALLOW_SPEND: String = "allowSpend"
const val USER_ID: String = "userId"
const val GEO_PERMISSIONS_REQUESTED: String = "geoPermissionsRequested"
Expand Down
30 changes: 28 additions & 2 deletions app/src/main/java/com/brainwallet/navigation/MainNavigationHost.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.brainwallet.navigation

import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.runtime.Composable
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
Expand All @@ -8,20 +10,23 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import com.brainwallet.constants.BWConstants
import com.brainwallet.ui.bentosections.buyreceivebento.receive.ReceiveDialog
import com.brainwallet.ui.screens.buyreceive.BuyReceiveScreen
import com.brainwallet.ui.screens.gamehub.GameHubScreen
import com.brainwallet.ui.screens.home.MainScreen
import com.brainwallet.ui.bentosections.buyreceivebento.receive.ReceiveDialog
import com.brainwallet.ui.screens.main.WebModalScreen
import com.brainwallet.ui.screens.restore.RestoreScreen
import com.brainwallet.ui.screens.emojis.EmojiPagerScreen
import com.brainwallet.ui.screens.emojis.YourEmojisScreen
import com.brainwallet.ui.screens.ready.ReadyScreen
import com.brainwallet.ui.screens.restore.RestoreScreen
import com.brainwallet.ui.screens.send.SendScreen
import com.brainwallet.ui.screens.setpasscode.SetPasscodeScreen
import com.brainwallet.ui.screens.topup.TopUpScreen
import com.brainwallet.ui.screens.unlock.UnLockScreen
import com.brainwallet.ui.screens.welcome.WelcomeScreen
import com.brainwallet.ui.screens.yourseedproveit.YourSeedProveItScreen
import com.brainwallet.ui.screens.yourseedwords.YourSeedWordsScreen
import kotlinx.collections.immutable.toImmutableList

/**
* Main Navigation Host for compose
Expand Down Expand Up @@ -102,6 +107,15 @@ fun NavGraphBuilder.mainNavGraph(
seedWords = route.seedWords,
)
}

composable<Route.YourEmojis> { navBackStackEntry ->
val route: Route.YourEmojis = navBackStackEntry.toRoute()
YourEmojisScreen(
onNavigate = onNavigate,
emojis = route.emojis.toImmutableList(),
)
}

composable<Route.YourSeedProveIt> { navBackStackEntry ->
val route: Route.YourSeedProveIt = navBackStackEntry.toRoute()
YourSeedProveItScreen(
Expand Down Expand Up @@ -154,4 +168,16 @@ fun NavGraphBuilder.mainNavGraph(
url = route.url
)
}

composable<Route.EmojiPickerPager>(
enterTransition = {
slideInHorizontally(
initialOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(350)
)
},
) { navBackStackEntry ->
val route: Route.EmojiPickerPager = navBackStackEntry.toRoute()
EmojiPagerScreen(onNavigate = onNavigate)
}
}
16 changes: 12 additions & 4 deletions app/src/main/java/com/brainwallet/navigation/Route.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.brainwallet.navigation

import androidx.compose.runtime.Immutable
import kotlinx.serialization.Serializable
import java.io.Serializable as JavaSerializable

Expand Down Expand Up @@ -37,6 +38,10 @@ sealed class Route : JavaSerializable {
@Serializable
data class YourSeedProveIt(val seedWords: List<String>) : Route()

@Serializable
@Immutable
data class YourEmojis(val emojis: List<String>) : Route()

@Serializable
object Main : Route()

Expand Down Expand Up @@ -68,10 +73,13 @@ sealed class Route : JavaSerializable {
data class BitrefillWeb(val url: String) : Route()

@Serializable
data class SocialsWeb(
val url: String,
val gameImageURIString: String
) : Route()
object EmojiPickerPager : Route()

@Serializable
object HowToSetEmojis : Route()

@Serializable
object PickEmojis : Route()

@Serializable
object LinktreeWeb : Route()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ 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 org.koin.core.annotation.Single
Expand All @@ -39,6 +36,59 @@ class NotificationHandler(
}
) {

// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// setupNotificationPermission()
// }
// private val requestNotificationPermissionLauncher: ActivityResultLauncher<String?> =
// registerForActivityResult<String?, Boolean?>(
// ActivityResultContracts.RequestPermission(),
// ActivityResultCallback { isGranted: Boolean? ->
// if (isGranted) {
// Toast.makeText(
// BreadActivity.app,
// R.string.permission_notification_granted,
// Toast.LENGTH_SHORT
// ).show()
// }
// })
//
// private val requestNotificationPermissionLauncher =
// registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
// if (isGranted) {
// Toast.makeText(
// this,
// R.string.permission_notification_granted,
// Toast.LENGTH_SHORT,
// ).show()
//
// Timber.d("Notification permission granted")
// } else {
// Timber.d("Notification permission denied")
// // Optionally show a message explaining reduced functionality
// }
// }
// @RequiresApi(Build.VERSION_CODES.TIRAMISU)
// // private fun setupNotificationPermission() {
// // if (hasPermission(this, Manifest.permission.POST_NOTIFICATIONS)) return
// //
// // if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
// // showNotificationRationaleDialog()
// // } else {
// // requestPermission(requestNotificationPermissionLauncher, Manifest.permission.POST_NOTIFICATIONS)
// // }
// // }

// @RequiresApi(Build.VERSION_CODES.TIRAMISU)
// private fun showNotificationRationaleDialog() {
// // AlertDialog.Builder(this)
// // .setTitle(R.string.permission_info)
// // .setMessage(R.string.please_grant_notification_permission)
// // .setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
// // .setPositiveButton(R.string.ok) { _, _ ->
// // requestPermission(requestNotificationPermissionLauncher, Manifest.permission.POST_NOTIFICATIONS)
// // }
// // .show()
// }
fun handleMessageReceived(context: Context, remoteMessage: RemoteMessage): Boolean {
if (remoteMessage.data.containsKey(KEY_DATA_BRAINWALLET).not()) {
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,7 @@ public static BreadActivity getApp() {
return app;
}

private final ActivityResultLauncher<String> requestNotificationPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
Toast.makeText(app, R.string.permission_notification_granted, Toast.LENGTH_SHORT).show();
}
});


@Override
protected void onCreate(Bundle savedInstanceState) {
Expand Down
Loading
Loading