Skip to content

Commit

Permalink
Increment to version 4.0.24
Browse files Browse the repository at this point in the history
  • Loading branch information
angelix committed Feb 6, 2024
1 parent e6d56f5 commit 1ca3fe1
Show file tree
Hide file tree
Showing 21 changed files with 110 additions and 81 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [4.0.24] - 2024-01-31

### Changed
- Export Greenlight logs
- Add "Receive any Liquid/AMP asset" to the assets list on Receive and Create New Account screens

### Changed
- 2FA SMS activation comply with US requirements
- Allow setting custom fees when recovering funds from Lightning
- Refactor ViewModels to support Kotlin Multiplatform
- Rewrite some UI screens into Jetpack Compose
- Update Jade Oracle whitelisted urls
- Bump Breez to version 0.2.15
- Bump GDK to version 0.70.0

### Fixed
- Fix F-Droid build
- Fix message signing UI
- Various bug fixes

## [4.0.23] - 2024-01-08

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,10 @@ class GdkSession constructor(
changeSettings(network, Settings.normalizeFromProminent(networkSettings = getSettings(network) ?: it, prominentSettings = it, pgpFromProminent = true))
}

if (network.isMultisig) {
getTwoFactorConfig(network = network, useCache = false)
updateWatchOnlyUsername(network = network)
}

// hard refresh accounts for the new network
val networkAccounts = getAccounts(network, refresh = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ class SignMessageViewModel(greenWallet: GreenWallet, account: Account, val addre
address = address,
message = message.value
),
hardwareWalletResolver = DeviceResolver.createIfNeeded(
session.gdkHwWallet,
this
)
hardwareWalletResolver = DeviceResolver.createIfNeeded(session.gdkHwWallet)
).signature
}, onSuccess = {
_signature.value = it
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.blockstream.common.models.onboarding

import com.arkivanov.essenty.statekeeper.StateKeeper
import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
import com.blockstream.common.data.Redact
import com.blockstream.common.data.SetupArgs
import com.blockstream.common.events.Event
Expand All @@ -11,13 +13,15 @@ import com.blockstream.common.models.GreenViewModel
import com.blockstream.common.navigation.NavigateDestinations
import com.blockstream.common.sideeffects.SideEffect
import com.blockstream.common.sideeffects.SideEffects
import com.blockstream.common.utils.Loggable
import com.rickclephas.kmm.viewmodel.MutableStateFlow
import com.rickclephas.kmm.viewmodel.coroutineScope
import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.serialization.Serializable
import org.koin.core.component.inject
import kotlin.math.ceil
import kotlin.math.max
Expand Down Expand Up @@ -68,7 +72,7 @@ abstract class EnterRecoveryPhraseViewModelAbstract(val setupArgs: SetupArgs) :
abstract val bip39WordList: List<String>
}

class EnterRecoveryPhraseViewModel(setupArgs: SetupArgs) :
class EnterRecoveryPhraseViewModel(setupArgs: SetupArgs, stateKeeper: StateKeeper = StateKeeperDispatcher()) :
EnterRecoveryPhraseViewModelAbstract(setupArgs) {
val wally: Wally by inject()

Expand Down Expand Up @@ -111,6 +115,14 @@ class EnterRecoveryPhraseViewModel(setupArgs: SetupArgs) :
init {
bootstrap()

stateKeeper.register(STATE, State.serializer()) {
State(mnemonic = toMnemonic())
}

stateKeeper.consume(STATE, State.serializer())?.mnemonic.takeIf { it.isNotBlank() }?.also {
setRecoveryPhrase(it)
}

combine(recoveryPhrase,recoveryPhraseSize, activeWord) { _, _, _ ->
checkRecoveryPhrase()
}.launchIn(viewModelScope.coroutineScope)
Expand All @@ -127,17 +139,8 @@ class EnterRecoveryPhraseViewModel(setupArgs: SetupArgs) :
}
} else if (event is LocalEvents.MnemonicEncryptionPassword) {
proceed(setupArgs.copy(mnemonic = toMnemonic(), password = event.password))

} else if (event is LocalEvents.SetRecoveryPhrase) {
println("RECOVERY: -> '${event.recoveryPhrase}'")
// Basic check to prevent huge inputs
recoveryPhrase.value = event.recoveryPhrase
.trim()
.replace("\n", " ")
.replace("\\s+", "")
.takeIf { it.isNotBlank() }
?.split(" ")?.takeIf { it.size <= 32 }?.toMutableList() ?: mutableListOf()
activeWord.value = -1
setRecoveryPhrase(event.recoveryPhrase)
} else if (event is LocalEvents.KeyAction) {
keyAction(event.key)
} else if (event is LocalEvents.SetActiveWord) {
Expand All @@ -147,6 +150,17 @@ class EnterRecoveryPhraseViewModel(setupArgs: SetupArgs) :
}
}

private fun setRecoveryPhrase(phrase: String){
// Basic check to prevent huge inputs
recoveryPhrase.value = phrase
.trim()
.replace("\n", " ")
.replace("\\s+", "")
.takeIf { it.isNotBlank() }
?.split(" ")?.takeIf { it.size <= 32 }?.toMutableList() ?: mutableListOf()
activeWord.value = -1
}

private fun proceed(setupArgs: SetupArgs) {
setupArgs.let { args ->
if (args.isAddAccount()) {
Expand Down Expand Up @@ -295,6 +309,15 @@ class EnterRecoveryPhraseViewModel(setupArgs: SetupArgs) :
private fun toMnemonic(): String {
return recoveryPhrase.value.joinToString(" ")
}

@Serializable
private class State(
val mnemonic: String
)

companion object: Loggable() {
const val STATE = "STATE"
}
}

class EnterRecoveryPhraseViewModelPreview(setupArgs: SetupArgs) :
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.blockstream.common.models.recovery

import com.arkivanov.essenty.parcelable.Parcelable
import com.arkivanov.essenty.parcelable.Parcelize
import com.arkivanov.essenty.statekeeper.StateKeeper
import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
import com.arkivanov.essenty.statekeeper.consume
import com.blockstream.common.data.SetupArgs
import com.blockstream.common.events.Event
import com.blockstream.common.events.Events
Expand All @@ -20,6 +17,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.serialization.Serializable
import org.koin.core.component.inject

abstract class RecoveryIntroViewModelAbstract(val setupArgs: SetupArgs) :
Expand All @@ -37,7 +35,7 @@ class RecoveryIntroViewModel constructor(setupArgs: SetupArgs, stateKeeper: Stat
RecoveryIntroViewModelAbstract(setupArgs = setupArgs) {
private val gdk: Gdk by inject()

private val state: State = stateKeeper.consume(STATE) ?: State(
private val state: State = stateKeeper.consume(STATE, State.serializer()) ?: State(
mnemonic = gdk.generateMnemonic12(), mnemonicSize = 12
)

Expand All @@ -54,7 +52,7 @@ class RecoveryIntroViewModel constructor(setupArgs: SetupArgs, stateKeeper: Stat
}

init {
stateKeeper.register(STATE) {
stateKeeper.register(STATE, State.serializer()) {
State(mnemonic = mnemonic.value, mnemonicSize = mnemonicSize.value)
}

Expand Down Expand Up @@ -112,10 +110,10 @@ class RecoveryIntroViewModel constructor(setupArgs: SetupArgs, stateKeeper: Stat
}
}

@Parcelize
@Serializable
private class State(
val mnemonic: String, val mnemonicSize: Int
) : Parcelable
)

companion object {
const val STATE = "STATE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,20 +208,20 @@ fun AboutScreen(

GreenColumn(padding = 0) {

// GreenCard(
// modifier = Modifier
// .align(Alignment.CenterHorizontally)
// .clickable {
// viewModel.postEvent(AboutViewModel.LocalEvents.ClickFeedback)
// },
// ) {
// Text(
// stringResource(id = R.string.id_give_us_your_feedback),
// modifier = Modifier.align(Alignment.Center),
// color = MaterialTheme.colorScheme.primary,
// style = labelLarge,
// )
// }
GreenCard(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.clickable {
viewModel.postEvent(AboutViewModel.LocalEvents.ClickFeedback)
},
) {
Text(
stringResource(id = R.string.id_give_us_your_feedback),
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.primary,
style = labelLarge,
)
}

GreenCard(
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.getScreenModel
import com.arkivanov.essenty.parcelable.Parcelable
import com.arkivanov.essenty.parcelable.Parcelize
import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
import com.blockstream.common.data.SetupArgs
import com.blockstream.common.events.Events
import com.blockstream.common.extensions.isNotBlank
Expand Down Expand Up @@ -89,7 +90,8 @@ data class EnterRecoveryPhraseScreen(val setupArgs: SetupArgs) : Screen, Parcela
@Composable
override fun Content() {
val viewModel = getScreenModel<EnterRecoveryPhraseViewModel>() {
parametersOf(setupArgs)
// TODO FIX STATE RESTORATION
parametersOf(setupArgs, StateKeeperDispatcher())
}

AppBar {
Expand All @@ -112,9 +114,6 @@ data class EnterRecoveryPhraseScreen(val setupArgs: SetupArgs) : Screen, Parcela
fun EnterRecoveryPhraseScreen(
viewModel: EnterRecoveryPhraseViewModelAbstract
) {
val context = LocalContext.current


HandleSideEffect(viewModel = viewModel)

GreenColumn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ data class RecoveryIntroScreen(val setupArgs: SetupArgs) : Screen, Parcelable {
@Composable
override fun Content() {
val viewModel = getScreenModel<RecoveryIntroViewModel>() {
// TODO FIX STATE RESTORATION
parametersOf(setupArgs, StateKeeperDispatcher())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,21 @@ fun WalletRenameBottomSheet(
// Holds the latest TextFieldValue that BasicTextField was recomposed with. We couldn't simply
// pass `TextFieldValue(text = value)` to the CoreTextField because we need to preserve the
// composition.
// val textFieldValue = textFieldValueState.copy(text = name)
val textFieldValue = textFieldValueState.copy(text = name)

// SideEffect {
// if (textFieldValue.selection != textFieldValueState.selection ||
// textFieldValue.composition != textFieldValueState.composition
// ) {
// textFieldValueState = textFieldValue
// }
// }
SideEffect {
if (textFieldValue.selection != textFieldValueState.selection ||
textFieldValue.composition != textFieldValueState.composition
) {
textFieldValueState = textFieldValue
}
}

TextField(
value = textFieldValueState,
onValueChange = viewModel.name.onTextFieldValueChange {
textFieldValueState = it
},
},
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
Expand Down
3 changes: 1 addition & 2 deletions compose/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1433,8 +1433,7 @@
<string name="id_some_accounts_can_not_be_logged_in_due_to_network">Some accounts can not be logged in due to network issues. Please try again later.</string>
<string name="id_the_lightning_service_is_currently_unavailable_for">The Lightning service is currently unavailable for maintenance, but it will be back soon.</string>
<string name="id_the_lightning_service_is_currently_unavailable_we">The Lightning service is currently unavailable. We apologize for the disruption, we are working to bring the service back online.</string>
<string name="id_by_continuing_you_agree_to_blockstream_s">By continuing you agree to Blockstream\'s ToS and Privacy Policy</string>
<string name="id_tos">ToS</string>
<string name="id_by_continuing_you_agree_to_blockstream_s">By continuing you agree to Blockstream\'s Terms Of Service and Privacy Policy</string>
<string name="id_message_frequency_varies_according_to_the_number">Message frequency varies according to the number of 2FA SMS requests you make.</string>
<string name="id_for_help_visit_help_blockstream_com">For help visit help.blockstream.com\nTo unsubscribe turn off SMS 2FA from the app.\nStandard messages and data rates may apply.</string>
<string name="id_help_blockstream_com">help.blockstream.com</string>
Expand Down
4 changes: 2 additions & 2 deletions green/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ android {
defaultConfig {
minSdk = libs.versions.androidMinSdk.get().toInt()
targetSdk = libs.versions.androidTargetSdk.get().toInt()
versionCode = 423
versionName = "4.0.23"
versionCode = 424
versionName = "4.0.24"

setProperty("archivesBaseName", "BlockstreamGreen-v$versionName")
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class UrlWarningDialogFragment : AbstractDialogFragment<UrlWarningDialogBinding>

isCancelable = false

binding.connectionAttemptHost = getString(R.string.id_connection_attempt_to_s, urls.firstOrNull()?.hostname())
binding.connectionAttemptHost = getString(R.string.id_connection_attempt_to_s, urls.map { it.hostname() }.joinToString(", "))

binding.buttonClose.setOnClickListener {
handle(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.arkivanov.essenty.statekeeper.stateKeeper
import com.blockstream.common.data.ScanResult
import com.blockstream.common.events.Events
import com.blockstream.common.gdk.getBip39WordList
Expand Down Expand Up @@ -59,7 +60,7 @@ class EnterRecoveryPhraseFragment : AppFragment<EnterRecoveryPhraseFragmentBindi
get() = args.setupArgs.network?.getNetworkIcon()

val viewModel: EnterRecoveryPhraseViewModel by viewModel {
parametersOf(args.setupArgs)
parametersOf(args.setupArgs, stateKeeper())
}

override fun getGreenViewModel(): GreenViewModel = viewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class TwoFactorSetupFragment : AbstractWalletFragment<TwofactorSetupFragmentBind
text = R.string.id_by_continuing_you_agree_to_blockstream_s,
color = R.color.color_on_surface_emphasis_medium,
links = listOf(
R.string.id_tos to object : ClickableSpan() {
R.string.id_terms_of_service to object : ClickableSpan() {
override fun onClick(widget: View) {
viewModel.postEvent(TwoFactorSetupViewModel.LocalEvents.ClickTermsOfService())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ open class WalletSettingsViewModel constructor(
database.deleteLoginCredentials(wallet.id, CredentialType.PASSWORD_PINDATA)
}, onSuccess = {
postSideEffect(SideEffects.Snackbar("id_you_have_successfully_changed"))
postSideEffect(SideEffects.Success())
postSideEffect(SideEffects.NavigateBack())
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ object AppReviewHelper {
MaterialAlertDialogBuilder(fragment.requireContext())
.setTitle(R.string.id_give_us_your_feedback)
.setView(dialogBinding.root)
.setCancelable(false)
.setPositiveButton(R.string.id_send) { _, _ ->
if (dialogBinding.toggleRate.checkedButtonId > 0 || !dialogBinding.feedbackText.text.isNullOrBlank()) {
fragment.countly.recordFeedback(
Expand Down
2 changes: 1 addition & 1 deletion green/src/main/res/layout/list_item_asset_accounts.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@

<include
android:id="@+id/createNewAccount"
isVisible="@{isSelected}"
isVisible="@{isSelected &amp;&amp; !isWatchOnly}"
layout="@layout/select_account_layout" />

</LinearLayout>
Expand Down
Loading

0 comments on commit 1ca3fe1

Please sign in to comment.