diff --git a/.gitignore b/.gitignore
index ba2aeb0cf..cb5d30587 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,5 +79,7 @@ CMakeFiles/
CMakeCache.txt
jniLibs/
-libwallet/
+libwallet/wallet.h
+libwallet/arm64-v8a/libminotari_wallet_ffi.a
+libwallet/x86_64/libminotari_wallet_ffi.a
!app/src/main/jniLibs/
diff --git a/app/build.gradle b/app/build.gradle
index c284001e6..9e31865e8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -13,8 +13,8 @@ android {
defaultConfig {
applicationId "com.tari.android.wallet"
minSdkVersion 26
- targetSdkVersion 33
- compileSdk 33
+ targetSdkVersion 34
+ compileSdk 34
versionCode buildNumber
versionName versionNumber + "-libwallet-" + libwalletVersion
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -22,8 +22,9 @@ android {
ndk {
abiFilters = []
- abiFilters.addAll(supportedABIs)
+ abiFilters.addAll(["arm64-v8a", "x86_64"])
}
+
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_static"
@@ -63,9 +64,9 @@ android {
// PRIVATE BUILD: comment (add two slashes at the start of each line) all the `sentry`
// block for private release builds support
sentry { // https://docs.sentry.io/platforms/android/#gradle-configuration
- autoUpload.set(true)
- uploadNativeSymbols.set(true)
- includeNativeSources.set(true)
+ autoUpload.set(false)
+ uploadNativeSymbols.set(false)
+ includeNativeSources.set(false)
}
}
}
@@ -84,11 +85,7 @@ android {
applicationVariants.configureEach { variant ->
variant.mergedFlavor.manifestPlaceholders.dropboxApiKey = loadDropboxProps().getProperty("dropbox_key")
- if (variant.buildType.name == "debug") {
- variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = ""
- } else {
- variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = loadSecretProps().getProperty("sentry.public_dsn")
- }
+ variant.mergedFlavor.manifestPlaceholders.sentryPublicDSN = loadSecretProps().getProperty("sentry.public_dsn")
}
externalNativeBuild {
@@ -201,24 +198,24 @@ Properties loadProps(fileName) {
return properties
}
-//preBuild.dependsOn("downloadLibwallet")
+preBuild.dependsOn("downloadLibwallet")
dependencies {
// kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// coroutines
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
- implementation "androidx.fragment:fragment-ktx:1.5.7"
+ implementation "androidx.fragment:fragment-ktx:1.6.2"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// kotlin extensions
- implementation "androidx.core:core-ktx:1.10.1"
+ implementation "androidx.core:core-ktx:1.12.0"
// android
implementation "androidx.appcompat:appcompat:1.6.1"
// support lib
@@ -227,30 +224,30 @@ dependencies {
// android jetpack
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
// recycler view
- implementation "androidx.recyclerview:recyclerview:1.3.1-rc01"
+ implementation "androidx.recyclerview:recyclerview:1.3.2"
// the new view pager
implementation "androidx.viewpager2:viewpager2:1.0.0"
// for tab layout
- implementation "com.google.android.material:material:1.9.0"
+ implementation "com.google.android.material:material:1.10.0"
// lottie
- implementation 'com.airbnb.android:lottie:6.0.0'
+ implementation 'com.airbnb.android:lottie:6.1.0'
// Glide - image processing & caching library
- implementation 'com.github.bumptech.glide:glide:4.15.1'
- kapt 'com.github.bumptech.glide:compiler:4.15.1'
+ implementation 'com.github.bumptech.glide:glide:4.16.0'
+ kapt 'com.github.bumptech.glide:compiler:4.16.0'
// biometric
implementation "androidx.biometric:biometric:1.1.0"
// joda
- implementation 'net.danlew:android.joda:2.12.1'
+ implementation 'net.danlew:android.joda:2.12.5'
// parceler
implementation "org.parceler:parceler-api:1.1.13"
kapt "org.parceler:parceler:1.1.13"
// dagger - DI
- implementation 'com.google.dagger:dagger:2.45'
- kapt 'com.google.dagger:dagger-compiler:2.45'
+ implementation 'com.google.dagger:dagger:2.48.1'
+ kapt 'com.google.dagger:dagger-compiler:2.48.1'
// rx
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
@@ -267,7 +264,7 @@ dependencies {
implementation "com.github.adorsys:secure-storage-android:0.0.2"
// Tor control
- implementation "info.guardianproject:tor-android:0.4.7.8"
+ implementation "info.guardianproject:tor-android:0.4.7.14"
implementation "info.guardianproject:jtorctl:0.4.5.7"
// used to read log files
@@ -280,14 +277,14 @@ dependencies {
// Retrofit2 - Popular (2020) REST API wrapper with Java interface
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
- implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.10"
+ implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11"
// Google services & Google drive
implementation platform('com.google.firebase:firebase-bom:31.2.3')
implementation 'com.google.firebase:firebase-crashlytics'
- implementation 'com.google.android.gms:play-services-auth:20.4.1'
- implementation 'com.google.http-client:google-http-client-gson:1.43.1'
+ implementation 'com.google.android.gms:play-services-auth:20.7.0'
+ implementation 'com.google.http-client:google-http-client-gson:1.43.3'
implementation('com.google.api-client:google-api-client-android:2.2.0') {
exclude group: "org.apache.httpcomponents"
}
@@ -295,12 +292,12 @@ dependencies {
exclude group: "org.apache.httpcomponents"
}
// sentry - crash analytics
- implementation 'io.sentry:sentry-android:6.16.0'
-
- implementation "com.dropbox.core:dropbox-core-sdk:5.4.4"
+ implementation 'io.sentry:sentry-android:6.33.1'
- implementation "com.github.yat-labs:yat-lib-android:0.1.42"
+ implementation "com.dropbox.core:dropbox-core-sdk:5.4.6"
+// implementation "com.github.yat-labs:yat-lib-android:0.1.42"
+ implementation project(":yatlib")
// custom libraries region
// flex layout
@@ -309,7 +306,7 @@ dependencies {
implementation "io.github.everythingme:overscroll-decor-android:1.1.1"
// giphy, don"t update to 2.2.0 because of not compatible yet
- implementation 'com.giphy.sdk:ui:2.3.1'
+ implementation 'com.giphy.sdk:ui:2.3.13'
// spring animation
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
implementation "com.github.MasayukiSuda:EasingInterpolator:v1.3.2"
@@ -317,14 +314,14 @@ dependencies {
// seismic - device shake detector
implementation "com.squareup:seismic:1.0.3"
- implementation "net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:2.2.0"
+ implementation "net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:2.3.0"
- implementation 'com.itextpdf:itext7-core:7.2.5'
+ implementation 'com.itextpdf:itext7-core:8.0.2'
- implementation("org.apache.maven:maven-artifact:3.0.3")
+ implementation("org.apache.maven:maven-artifact:3.9.5")
// debugImplementation because LeakCanary should only run in debug builds.
- debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
+ debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
implementation 'com.github.vestrel00:contacts-android:0.2.4'
@@ -332,8 +329,8 @@ dependencies {
// test
testImplementation "junit:junit:4.13.2"
- testImplementation 'io.mockk:mockk:1.13.4'
- androidTestImplementation 'io.mockk:mockk-android:1.13.4'
+ testImplementation 'io.mockk:mockk:1.13.8'
+ androidTestImplementation 'io.mockk:mockk-android:1.13.8'
androidTestImplementation "androidx.test:core:1.5.0"
androidTestImplementation "androidx.test.ext:junit:1.1.5"
androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 10bd9827e..6b02068cf 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -32,4 +32,17 @@
-keep enum com.tari.android.wallet.ui.fragment.settings.themeSelector.TariTheme { *; }
--keep enum com.tari.android.wallet.data.sharedPrefs.securityStages.WalletSecurityStage { *; }
\ No newline at end of file
+-keep enum com.tari.android.wallet.data.sharedPrefs.securityStages.WalletSecurityStage { *; }
+
+-keep enum com.tari.android.wallet.application.Network { *; }
+
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.SearchGIFResponse { *; }
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.SearchGIFsResponse { *; }
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.Data { *; }
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.Meta { *; }
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.Images { *; }
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.ImageVariant { *; }
+-keep class com.tari.android.wallet.ui.common.gyphy.api.dto.Original { *; }
+
+-keep class **Fragment** { *; }
+-keep class **ViewModel** { *; }
diff --git a/app/regular/release/app-regular-release.aab b/app/regular/release/app-regular-release.aab
deleted file mode 100644
index d9c71d382..000000000
Binary files a/app/regular/release/app-regular-release.aab and /dev/null differ
diff --git a/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt b/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt
index 8fae11b70..635df526d 100644
--- a/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt
+++ b/app/src/androidTest/java/com/tari/android/wallet/FFIWalletTests.kt
@@ -43,7 +43,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepositoryImpl
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.data.sharedPrefs.securityStages.SecurityStagesRepository
+import com.tari.android.wallet.data.sharedPrefs.sentry.SentryPrefRepository
import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository
import com.tari.android.wallet.data.sharedPrefs.tor.TorSharedRepository
import com.tari.android.wallet.di.ApplicationModule
@@ -77,9 +79,10 @@ class FFIWalletTests {
private val tariSettingsRepository = TariSettingsSharedRepository(prefs, networkRepository)
private val securityStagesRepository = SecurityStagesRepository(prefs, networkRepository)
private val contactSharedPrefRepository = ContactSharedPrefRepository(networkRepository, prefs)
+ private val sentryPrefRepository: SentryPrefRepository = SentryPrefRepository(prefs, networkRepository)
private val torSharedRepository = TorSharedRepository(prefs, networkRepository)
+ private val securityPrefRepository = SecurityPrefRepository(context, prefs, networkRepository)
private val sharedPrefsRepository = SharedPrefsRepository(
- context,
prefs,
networkRepository,
backupSettingsRepository,
@@ -88,7 +91,9 @@ class FFIWalletTests {
torSharedRepository,
tariSettingsRepository,
securityStagesRepository,
- contactSharedPrefRepository
+ contactSharedPrefRepository,
+ sentryPrefRepository,
+ securityPrefRepository,
)
private val walletDirPath = context.filesDir.absolutePath
@@ -118,7 +123,7 @@ class FFIWalletTests {
)
val logFile = File(walletDirPath, "test_log.log")
// create wallet instance
- wallet = FFIWallet(sharedPrefsRepository, SeedPhraseRepository(), networkRepository, commsConfig, logFile.absolutePath)
+ wallet = FFIWallet(sharedPrefsRepository, securityPrefRepository, SeedPhraseRepository(), networkRepository, commsConfig, logFile.absolutePath)
// create listener
listener = TestAddRecipientAddNodeListener()
wallet.listener = listener
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0169de819..b0b91b874 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -30,9 +30,12 @@
+
+
+
@@ -55,7 +58,8 @@
android:name=".service.service.WalletService"
android:description="@string/wallet_service_desc"
android:enabled="true"
- android:exported="false">
+ android:exported="false"
+ android:foregroundServiceType="dataSync">
@@ -81,6 +85,7 @@
android:name=".ui.fragment.splash.SplashActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
+ android:screenOrientation="portrait"
android:theme="@style/AppTheme.Splash"
android:windowSoftInputMode="stateAlwaysHidden">
@@ -93,18 +98,21 @@
@@ -137,11 +145,16 @@
android:host="y.at"
android:scheme="tari" />
+
+
+
@@ -156,13 +169,15 @@
android:name="com.google.android.gms.auth.api.signin.internal.SignInHubActivity"
android:excludeFromRecents="true"
android:exported="false"
+ android:screenOrientation="portrait"
android:theme="@style/GoogleSignInActivity"
tools:replace="android:theme" />
+ android:launchMode="singleTask"
+ android:screenOrientation="portrait">
@@ -175,26 +190,32 @@
diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt
index 335ff6370..8a3bd0088 100644
--- a/app/src/main/cpp/CMakeLists.txt
+++ b/app/src/main/cpp/CMakeLists.txt
@@ -49,7 +49,7 @@ add_library(
set_target_properties(
wallet
PROPERTIES
- IMPORTED_LOCATION ${libs_DIR}/${ANDROID_ABI}/libtari_wallet_ffi.a
+ IMPORTED_LOCATION ${libs_DIR}/${ANDROID_ABI}/libminotari_wallet_ffi.a
IMPORTED_LINK_INTERFACE_LIBRARIES "ssl;sqlite3"
)
diff --git a/app/src/main/java/com/tari/android/wallet/application/MigrationManager.kt b/app/src/main/java/com/tari/android/wallet/application/MigrationManager.kt
index 7b5d7c6ab..2d1da2e82 100644
--- a/app/src/main/java/com/tari/android/wallet/application/MigrationManager.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/MigrationManager.kt
@@ -11,7 +11,7 @@ import javax.inject.Singleton
@Singleton
class MigrationManager @Inject constructor(private val manager: WalletManager) {
- private val minValidVersion = DefaultArtifactVersion("0.50.0-hotfix.1")
+ private val minValidVersion = DefaultArtifactVersion("v0.52.0")
private val simpleViewModel = SimpleViewModel()
fun validateVersion(onValid: () -> Unit, onError: () -> Unit) {
diff --git a/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt b/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt
index e21afe021..780108bd6 100644
--- a/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/TariWalletApplication.kt
@@ -38,7 +38,9 @@ import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import com.orhanobut.logger.Logger
+import com.tari.android.wallet.BuildConfig
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.di.DiContainer
import com.tari.android.wallet.event.Event
import com.tari.android.wallet.event.EventBus
@@ -48,6 +50,7 @@ import com.tari.android.wallet.notification.NotificationHelper
import com.tari.android.wallet.service.service.WalletServiceLauncher
import com.tari.android.wallet.ui.common.gyphy.GiphyAdapter
import com.tari.android.wallet.yat.YatAdapter
+import io.sentry.android.core.SentryAndroid
import java.lang.ref.WeakReference
import javax.inject.Inject
@@ -70,6 +73,9 @@ class TariWalletApplication : Application() {
@Inject
lateinit var sharedPrefsRepository: SharedPrefsRepository
+ @Inject
+ lateinit var securityPrefRepository: SecurityPrefRepository
+
@Inject
lateinit var walletServiceLauncher: WalletServiceLauncher
@@ -93,15 +99,27 @@ class TariWalletApplication : Application() {
val currentActivity: Activity?
get() = activityLifecycleCallbacks.currentActivity
+ @Suppress("KotlinConstantConditions")
override fun onCreate() {
super.onCreate()
INSTANCE = WeakReference(this)
+ SentryAndroid.init(this) {
+ it.isDebug = BuildConfig.BUILD_TYPE == "debug"
+ val buildType = when (BuildConfig.BUILD_TYPE) {
+ "debug" -> "DEVELOPMENT"
+ "release" -> "PRODUCTION"
+ else -> "PRODUCTION"
+ }
+ it.environment = buildType + "_" + BuildConfig.FLAVOR
+ }
+
registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
DiContainer.initContainer(this)
initApplication()
+
ProcessLifecycleOwner.get().lifecycle.addObserver(AppObserver())
logger.i("Application inited")
}
@@ -112,7 +130,7 @@ class TariWalletApplication : Application() {
notificationHelper.createNotificationChannels()
// user should authenticate every time the app starts up
- sharedPrefsRepository.isAuthenticated = false
+ securityPrefRepository.isAuthenticated = false
registerReceiver(connectionStateReceiver, connectionStateReceiver.intentFilter)
@@ -149,6 +167,7 @@ class TariWalletApplication : Application() {
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
+ securityPrefRepository.isAuthenticated = false
logger.i("App was destroyed")
walletServiceLauncher.stopOnAppBackgrounded()
}
diff --git a/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt b/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt
index 5b80bb515..1a71f6fef 100644
--- a/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/WalletManager.kt
@@ -40,6 +40,7 @@ import com.tari.android.wallet.data.WalletConfig
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository
import com.tari.android.wallet.event.EventBus
import com.tari.android.wallet.ffi.*
@@ -64,7 +65,8 @@ class WalletManager(
private val baseNodeSharedRepository: BaseNodeSharedRepository,
private val seedPhraseRepository: SeedPhraseRepository,
private val networkRepository: NetworkRepository,
- private var tariSettingsSharedRepository: TariSettingsSharedRepository,
+ private val tariSettingsSharedRepository: TariSettingsSharedRepository,
+ private val securityPrefRepository: SecurityPrefRepository,
private val baseNodes: BaseNodes,
private val torConfig: TorConfig
) {
@@ -202,6 +204,7 @@ class WalletManager(
val isNewInstallation = !WalletUtil.walletExists(walletConfig)
val wallet = FFIWallet(
sharedPrefsWrapper,
+ securityPrefRepository,
seedPhraseRepository,
networkRepository,
getCommsConfig(),
diff --git a/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt b/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt
index 29553cd43..f935931a1 100644
--- a/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/baseNodes/BaseNodes.kt
@@ -1,6 +1,8 @@
package com.tari.android.wallet.application.baseNodes
import android.content.Context
+import com.google.gson.Gson
+import com.orhanobut.logger.Logger
import com.tari.android.wallet.R
import com.tari.android.wallet.application.Network
import com.tari.android.wallet.application.WalletState
@@ -43,6 +45,9 @@ class BaseNodes(
}.addTo(compositeDisposable)
}
+ val onionRegex = "(.+::[A-Za-z0-9 ]{64}::/onion3/[A-Za-z0-9]+:[\\d]+)"
+ val ipV4Regex = "(.+::[A-Za-z0-9 ]{64}::/ip4/[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}/tcp/[0-9]{2,6})"
+
/**
* Returns the list of base nodes in the resource file base_nodes.txt as pairs of
* ({name}, {public_key_hex}, {public_address}).
@@ -52,8 +57,22 @@ class BaseNodes(
context.resources.openRawResource(getBaseNodeResource(networkRepository.currentNetwork!!.network)),
"UTF-8"
)
- Regex("(.+::[A-Za-z0-9 ]{64}::/onion3/[A-Za-z0-9]+:[\\d]+)").findAll(fileContent).map { matchResult ->
+ Logger.t(this::class.simpleName).e("baseNodeList: $fileContent")
+ val list = mutableListOf()
+ val onionBaseNodes = findAndAddBaseNode(fileContent, onionRegex).toList()
+ val ipV4BaseNodes = findAndAddBaseNode(fileContent, ipV4Regex).toList()
+ list.addAll(onionBaseNodes)
+ list.addAll(ipV4BaseNodes)
+ list.sortedBy { it.name }
+ }
+
+ private fun findAndAddBaseNode(fileContent: String, regex: String): Sequence {
+ return Regex(regex).findAll(fileContent).map { matchResult ->
val tripleString = matchResult.value.split("::")
+ if (tripleString.size ==2) {
+ 1
+ }
+ Logger.t(this::class.simpleName).e("baseNodeList0: $tripleString, baseNodeList1: ${tripleString[1]}, baseNodeList2: ${tripleString[2]}")
BaseNodeDto(tripleString[0], tripleString[1], tripleString[2])
}
}
@@ -78,19 +97,28 @@ class BaseNodes(
}
fun startSync() {
- //essential for wallet creation flow
- val baseNode = baseNodeSharedRepository.currentBaseNode ?: return
- serviceConnection.currentState.service ?: return
- if (EventBus.walletState.publishSubject.value != WalletState.Running) return
+ try {
+ Logger.t(this::class.simpleName).e("startSync")
+ //essential for wallet creation flow
+ val baseNode = baseNodeSharedRepository.currentBaseNode ?: return
+ serviceConnection.currentState.service ?: return
+ if (EventBus.walletState.publishSubject.value != WalletState.Running) return
- val baseNodeKeyFFI = FFIPublicKey(HexString(baseNode.publicKeyHex))
- FFIWallet.instance?.addBaseNodePeer(baseNodeKeyFFI, baseNode.address)
- baseNodeKeyFFI.destroy()
- walletService.getWithError { error, wallet -> wallet.startBaseNodeSync(error) }
+ Logger.t(this::class.simpleName).e("startSync:publicKeyHex: ${baseNode.publicKeyHex}")
+ Logger.t(this::class.simpleName).e("startSync:address: ${baseNode.address}")
+ Logger.t(this::class.simpleName).e("startSync:address: ${Gson().toJson(baseNodeSharedRepository.userBaseNodes)}")
+ val baseNodeKeyFFI = FFIPublicKey(HexString(baseNode.publicKeyHex))
+ FFIWallet.instance?.addBaseNodePeer(baseNodeKeyFFI, baseNode.address)
+ baseNodeKeyFFI.destroy()
+ walletService.getWithError { error, wallet -> wallet.startBaseNodeSync(error) }
+ } catch (e: Throwable) {
+ Logger.t(this::class.simpleName).e("startSync")
+ setNextBaseNode()
+ startSync()
+ }
}
-
@Suppress("UNUSED_EXPRESSION")
- private fun getBaseNodeResource(network: Network): Int = when(network) {
+ private fun getBaseNodeResource(network: Network): Int = when (network) {
else -> R.raw.stagenet_base_nodes
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeepLink.kt b/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeepLink.kt
index 437cb4527..cfb87dca7 100644
--- a/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeepLink.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeepLink.kt
@@ -32,7 +32,9 @@
*/
package com.tari.android.wallet.application.deeplinks
+import com.tari.android.wallet.data.sharedPrefs.tor.TorBridgeConfiguration
import com.tari.android.wallet.model.MicroTari
+import com.tari.android.wallet.model.TariWalletAddress
import java.math.BigInteger
/**
@@ -49,8 +51,7 @@ sealed class DeepLink {
// tari://esmeralda/contacts?list[0][alias]=Name&list[0][hex]=hex&list[1][alias]=Name&list[1][hex]=hex
class Contacts(val contacts: List) : DeepLink() {
- constructor(params: Map) : this(
- params.filterKeys { it.startsWith("list[") }
+ constructor(params: Map) : this(params.filterKeys { it.startsWith("list[") }
.map { FormatExtractor(it.key, it.value) }
.groupBy { it.index }
.map {
@@ -58,7 +59,7 @@ sealed class DeepLink {
val hex = it.value.firstOrNull { it.name == hexKey }?.value.orEmpty()
DeeplinkContact(alias, hex)
}
- )
+ .filter { TariWalletAddress.validate(it.hex) })
override fun getParams(): Map = hashMapOf().apply {
contacts.forEachIndexed { index, contact ->
@@ -160,6 +161,10 @@ sealed class DeepLink {
}
}
+ class TorBridges(val torConfigurations: List): DeepLink() {
+
+ }
+
companion object {
fun getByCommand(command: String, params: Map): DeepLink? = when (command) {
diff --git a/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkFormatter.kt b/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkFormatter.kt
index 27dac3688..4084e5666 100644
--- a/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkFormatter.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkFormatter.kt
@@ -2,6 +2,8 @@ package com.tari.android.wallet.application.deeplinks
import android.net.Uri
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.tor.TorBridgeConfiguration
+import com.tari.android.wallet.model.TariWalletAddress
import java.net.URLDecoder
import javax.inject.Inject
import javax.inject.Singleton
@@ -9,6 +11,11 @@ import javax.inject.Singleton
@Singleton
class DeeplinkFormatter @Inject constructor(private val networkRepository: NetworkRepository) {
fun parse(deepLink: String): DeepLink? {
+ val torBridges = getTorDeeplink(deepLink)
+ if (torBridges.isNotEmpty()) {
+ return DeepLink.TorBridges(torBridges)
+ }
+
val uri = Uri.parse(URLDecoder.decode(deepLink, "UTF-8"))
if (!uri.authority.equals(networkRepository.currentNetwork!!.network.uriComponent)) {
@@ -24,10 +31,26 @@ class DeeplinkFormatter @Inject constructor(private val networkRepository: Netwo
}.toMap()
paramentrs = values.toMutableMap()
}
- return DeepLink.getByCommand(command, paramentrs)
+
+ val parsedDeeplink = DeepLink.getByCommand(command, paramentrs)
+
+ if (parsedDeeplink is DeepLink.Send) {
+ if (!TariWalletAddress.validate(parsedDeeplink.walletAddressHex)) return null
+ }
+ if (parsedDeeplink is DeepLink.UserProfile) {
+ if (!TariWalletAddress.validate(parsedDeeplink.tariAddressHex)) return null
+ }
+
+ return parsedDeeplink
}
fun toDeeplink(deepLink: DeepLink): String {
+ if (deepLink is DeepLink.TorBridges) {
+ return deepLink.torConfigurations.joinToString("\n") {
+ "${it.ip}:${it.port} ${it.fingerprint}"
+ }
+ }
+
val fullPart = Uri.Builder()
.scheme(scheme)
.authority(networkRepository.currentNetwork!!.network.uriComponent)
@@ -40,7 +63,21 @@ class DeeplinkFormatter @Inject constructor(private val networkRepository: Netwo
return fullPart.build().toString()
}
+ private fun getTorDeeplink(input: String): List {
+ return regex.findAll(input).mapNotNull { match ->
+ try {
+ val ipAddressAndPort = match.groupValues[1].split(":")
+ val sha1Hash = match.groupValues[2]
+ TorBridgeConfiguration("", ipAddressAndPort[0], ipAddressAndPort[1], sha1Hash)
+ } catch (e: Exception) {
+ null
+ }
+ }.toList()
+ }
+
companion object {
const val scheme = "tari"
+
+ val regex = Regex("""(\d+\.\d+\.\d+\.\d+:\d+) ([0-9A-Fa-f]+)""")
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkViewModel.kt b/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkViewModel.kt
index 93b566633..c538de353 100644
--- a/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/deeplinks/DeeplinkViewModel.kt
@@ -4,6 +4,7 @@ import com.tari.android.wallet.R
import com.tari.android.wallet.application.baseNodes.BaseNodes
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeDto
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository
+import com.tari.android.wallet.data.sharedPrefs.tor.TorSharedRepository
import com.tari.android.wallet.ffi.FFITariWalletAddress
import com.tari.android.wallet.ffi.HexString
import com.tari.android.wallet.model.TariWalletAddress
@@ -35,24 +36,28 @@ class DeeplinkViewModel : CommonViewModel() {
@Inject
lateinit var deeplinkHandler: DeeplinkHandler
+ @Inject
+ lateinit var torSharedRepository: TorSharedRepository
+
init {
component.inject(this)
}
- fun tryToHandle(qrData: String) {
- deeplinkHandler.handle(qrData)?.let { execute(it) }
+ fun tryToHandle(qrData: String, isQrData: Boolean = true) {
+ deeplinkHandler.handle(qrData)?.let { execute(it, isQrData) }
}
- fun execute(deeplink: DeepLink) {
+ fun execute(deeplink: DeepLink, isQrData: Boolean = true) {
when (deeplink) {
- is DeepLink.AddBaseNode -> addBaseNode(deeplink)
- is DeepLink.Contacts -> addContacts(deeplink)
- is DeepLink.Send -> sendAction(deeplink)
- is DeepLink.UserProfile -> addUserProfile(deeplink)
+ is DeepLink.AddBaseNode -> addBaseNode(deeplink, isQrData)
+ is DeepLink.Contacts -> addContacts(deeplink, isQrData)
+ is DeepLink.Send -> sendAction(deeplink, isQrData)
+ is DeepLink.UserProfile -> addUserProfile(deeplink, isQrData)
+ is DeepLink.TorBridges -> addTorBridges(deeplink, isQrData)
}
}
- fun addBaseNode(deeplink: DeepLink.AddBaseNode) {
+ fun addBaseNode(deeplink: DeepLink.AddBaseNode, isQrData: Boolean = true) {
val baseNode = getData(deeplink)
val args = ConfirmDialogArgs(
resourceManager.getString(R.string.home_custom_base_node_title),
@@ -61,13 +66,13 @@ class DeeplinkViewModel : CommonViewModel() {
resourceManager.getString(R.string.common_lets_do_it),
onConfirm = {
dismissDialog.postValue(Unit)
- addBaseNodeAction(baseNode)
+ addBaseNodeAction(baseNode, isQrData)
}
).getModular(baseNode, resourceManager)
modularDialog.postValue(args)
}
- fun addUserProfile(deeplink: DeepLink.UserProfile) {
+ fun addUserProfile(deeplink: DeepLink.UserProfile, isQrData: Boolean) {
val contact = DeepLink.Contacts(
listOf(
DeepLink.Contacts.DeeplinkContact(
@@ -76,10 +81,10 @@ class DeeplinkViewModel : CommonViewModel() {
)
)
)
- addContacts(contact)
+ addContacts(contact, isQrData)
}
- fun addContacts(contacts: DeepLink.Contacts) {
+ fun addContacts(contacts: DeepLink.Contacts, isQrData: Boolean = true) {
val contactDtos = getData(contacts)
if (contactDtos.isEmpty()) return
val names = contactDtos.joinToString(", ") { it.contact.getAlias().trim() }
@@ -88,7 +93,7 @@ class DeeplinkViewModel : CommonViewModel() {
HeadModule(resourceManager.getString(R.string.contact_deeplink_title)),
BodyModule(resourceManager.getString(R.string.contact_deeplink_message, contactDtos.size.toString()) + ". " + names),
ButtonModule(resourceManager.getString(R.string.common_confirm), ButtonStyle.Normal) {
- addContactsAction(contactDtos)
+ addContactsAction(contactDtos, isQrData)
dismissDialog.postValue(Unit)
},
ButtonModule(resourceManager.getString(R.string.common_cancel), ButtonStyle.Close)
@@ -97,12 +102,19 @@ class DeeplinkViewModel : CommonViewModel() {
modularDialog.postValue(args)
}
- fun executeRawDeeplink(deeplink: DeepLink) {
+ fun addTorBridges(deeplink: DeepLink.TorBridges, isQrData: Boolean) {
+ deeplink.torConfigurations.forEach {
+ torSharedRepository.addTorBridgeConfiguration(it)
+ }
+ }
+
+ fun executeRawDeeplink(deeplink: DeepLink, isQrData: Boolean = true) {
when (deeplink) {
is DeepLink.AddBaseNode -> addBaseNode(deeplink)
- is DeepLink.Contacts -> addContactsAction(getData(deeplink))
- is DeepLink.Send -> sendAction(deeplink)
- is DeepLink.UserProfile -> addContactsAction(getData(deeplink)?.let { listOf(it) } ?: listOf())
+ is DeepLink.Contacts -> addContactsAction(getData(deeplink), isQrData)
+ is DeepLink.Send -> sendAction(deeplink, isQrData)
+ is DeepLink.UserProfile -> addContactsAction(getData(deeplink)?.let { listOf(it) } ?: listOf(), isQrData)
+ is DeepLink.TorBridges -> addTorBridges(deeplink, isQrData)
}
}
@@ -128,16 +140,18 @@ class DeeplinkViewModel : CommonViewModel() {
ContactDto(FFIContactDto(tariWalletAddress, userProfile.alias))
}.getOrNull()
- private fun addContactsAction(contacts: List) {
- _backPressed.postValue(Unit)
+ private fun addContactsAction(contacts: List, isQrData: Boolean) {
+ if (isQrData) {
+ backPressed.postValue(Unit)
+ }
contacts.forEach { contactRepository.addContact(it) }
}
- private fun sendAction(deeplink: DeepLink.Send) {
+ private fun sendAction(deeplink: DeepLink.Send, isQrData: Boolean) {
navigation.postValue(Navigation.TxListNavigation.ToSendWithDeeplink(deeplink))
}
- private fun addBaseNodeAction(baseNodeDto: BaseNodeDto) {
+ private fun addBaseNodeAction(baseNodeDto: BaseNodeDto, isQrData: Boolean) {
baseNodeRepository.addUserBaseNode(baseNodeDto)
baseNodes.setBaseNode(baseNodeDto)
}
diff --git a/app/src/main/java/com/tari/android/wallet/application/securityStage/StagedWalletSecurityManager.kt b/app/src/main/java/com/tari/android/wallet/application/securityStage/StagedWalletSecurityManager.kt
index bff78ec79..32597528a 100644
--- a/app/src/main/java/com/tari/android/wallet/application/securityStage/StagedWalletSecurityManager.kt
+++ b/app/src/main/java/com/tari/android/wallet/application/securityStage/StagedWalletSecurityManager.kt
@@ -3,7 +3,6 @@ package com.tari.android.wallet.application.securityStage
import android.text.SpannableString
import android.text.Spanned
import com.tari.android.wallet.R
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.securityStages.DisabledTimestampsDto
import com.tari.android.wallet.data.sharedPrefs.securityStages.SecurityStagesRepository
import com.tari.android.wallet.data.sharedPrefs.securityStages.WalletSecurityStage
@@ -35,9 +34,6 @@ class StagedWalletSecurityManager : CommonViewModel() {
@Inject
lateinit var backupPrefsRepository: BackupSettingsRepository
- @Inject
- lateinit var sharedPrefsRepository: SharedPrefsRepository
-
init {
component.inject(this)
diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt
index a802b35d7..85e04ed22 100644
--- a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt
+++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/SharedPrefsRepository.kt
@@ -32,16 +32,16 @@
*/
package com.tari.android.wallet.data.sharedPrefs
-import android.content.Context
import android.content.SharedPreferences
import com.tari.android.wallet.data.repository.CommonRepository
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository
import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefBooleanDelegate
import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefStringDelegate
-import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefStringSecuredDelegate
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
import com.tari.android.wallet.data.sharedPrefs.network.formatKey
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.data.sharedPrefs.securityStages.SecurityStagesRepository
+import com.tari.android.wallet.data.sharedPrefs.sentry.SentryPrefRepository
import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository
import com.tari.android.wallet.data.sharedPrefs.tor.TorSharedRepository
import com.tari.android.wallet.ui.fragment.contact_book.data.localStorage.ContactSharedPrefRepository
@@ -60,7 +60,6 @@ import kotlin.random.Random
@Singleton
class SharedPrefsRepository @Inject constructor(
- context: Context,
sharedPrefs: SharedPreferences,
networkRepository: NetworkRepository,
private val backupSettingsRepository: BackupSettingsRepository,
@@ -69,12 +68,13 @@ class SharedPrefsRepository @Inject constructor(
private val torSharedRepository: TorSharedRepository,
private val tariSettingsSharedRepository: TariSettingsSharedRepository,
private val securityStagesRepository: SecurityStagesRepository,
- private val contactSharedPrefRepository: ContactSharedPrefRepository
+ private val contactSharedPrefRepository: ContactSharedPrefRepository,
+ private val sentryPrefRepository: SentryPrefRepository,
+ private val securityPrefRepository: SecurityPrefRepository
) : CommonRepository(networkRepository) {
private object Key {
const val publicKeyHexString = "tari_wallet_public_key_hex_string"
- const val isAuthenticated = "tari_wallet_is_authenticated"
const val emojiId = "tari_wallet_emoji_id_"
const val name = "tari_wallet_name_"
const val surname = "tari_wallet_surname_"
@@ -84,22 +84,17 @@ class SharedPrefsRepository @Inject constructor(
const val onboardingAuthSetupStarted = "tari_wallet_onboarding_auth_setup_started"
const val onboardingCompleted = "tari_wallet_onboarding_completed"
const val onboardingDisplayedAtHome = "tari_wallet_onboarding_displayed_at_home"
- const val walletDatabasePassphrase = "tari_wallet_database_passphrase"
const val isDataCleared = "tari_is_data_cleared"
}
var publicKeyHexString: String? by SharedPrefStringDelegate(sharedPrefs, this, formatKey(Key.publicKeyHexString))
- var isAuthenticated: Boolean by SharedPrefBooleanDelegate(sharedPrefs, this, formatKey(Key.isAuthenticated))
-
var emojiId: String? by SharedPrefStringDelegate(sharedPrefs, this, formatKey(Key.emojiId))
var name: String? by SharedPrefStringDelegate(sharedPrefs, this, formatKey(Key.name))
var surname: String? by SharedPrefStringDelegate(sharedPrefs, this, formatKey(Key.surname))
- var databasePassphrase: String? by SharedPrefStringSecuredDelegate(context, sharedPrefs, this, formatKey(Key.walletDatabasePassphrase))
-
var onboardingStarted: Boolean by SharedPrefBooleanDelegate(sharedPrefs, this, formatKey(Key.onboardingStarted))
var onboardingCompleted: Boolean by SharedPrefBooleanDelegate(sharedPrefs, this, formatKey(Key.onboardingCompleted))
@@ -111,7 +106,7 @@ class SharedPrefsRepository @Inject constructor(
var actionMenuSide: Boolean by SharedPrefBooleanDelegate(sharedPrefs, this, formatKey(Key.actionMenuSide))
val onboardingAuthWasInterrupted: Boolean
- get() = onboardingAuthSetupStarted && !onboardingAuthSetupCompleted
+ get() = onboardingAuthSetupStarted && (!onboardingAuthSetupCompleted || securityPrefRepository.pinCode == null)
val onboardingWasInterrupted: Boolean
get() = onboardingStarted && !onboardingCompleted
@@ -128,15 +123,16 @@ class SharedPrefsRepository @Inject constructor(
tariSettingsSharedRepository.clear()
securityStagesRepository.clear()
contactSharedPrefRepository.clear()
+ sentryPrefRepository.clear()
+ securityPrefRepository.clear()
publicKeyHexString = null
- isAuthenticated = false
emojiId = null
- databasePassphrase = null
onboardingStarted = false
onboardingCompleted = false
onboardingAuthSetupStarted = false
onboardingAuthSetupCompleted = false
onboardingDisplayedAtHome = false
+
}
fun generateDatabasePassphrase(): String {
diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/security/LoginAttemptDto.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/security/LoginAttemptDto.kt
new file mode 100644
index 000000000..6cdd127c9
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/security/LoginAttemptDto.kt
@@ -0,0 +1,7 @@
+package com.tari.android.wallet.data.sharedPrefs.security
+
+class LoginAttemptDto(val timeInMills: Long, val isSuccessful: Boolean)
+
+class LoginAttemptList : ArrayList()
+
+fun LoginAttemptList?.orEmpty() : LoginAttemptList = this ?: LoginAttemptList()
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/security/SecurityPrefRepository.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/security/SecurityPrefRepository.kt
new file mode 100644
index 000000000..1b3ccbc6a
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/security/SecurityPrefRepository.kt
@@ -0,0 +1,66 @@
+package com.tari.android.wallet.data.sharedPrefs.security
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.tari.android.wallet.data.repository.CommonRepository
+import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefBooleanDelegate
+import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefBooleanNullableDelegate
+import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefGsonDelegate
+import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefStringSecuredDelegate
+import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.network.formatKey
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SecurityPrefRepository @Inject constructor(
+ context: Context,
+ sharedPrefs: SharedPreferences,
+ networkRepository: NetworkRepository,
+) : CommonRepository(networkRepository) {
+
+ companion object Key {
+ const val isAuthenticatedKey = "tari_wallet_is_authenticated"
+ const val isFeatureAuthenticatedKey = "tari_wallet_is_feature_authenticated"
+ const val pinCodeKey = "tari_is_pincode"
+ const val biometricsKey = "tari_is_biometrics"
+ const val walletDatabasePassphraseKey = "tari_wallet_database_passphrase"
+ const val loginAttemptsKey = "tari_login_attempts"
+ }
+
+ var isAuthenticated: Boolean by SharedPrefBooleanDelegate(sharedPrefs, this, formatKey(isAuthenticatedKey))
+
+ var isFeatureAuthenticated: Boolean by SharedPrefBooleanDelegate(sharedPrefs, this, formatKey(isFeatureAuthenticatedKey))
+
+ var pinCode: String? by SharedPrefStringSecuredDelegate(context, sharedPrefs, this, formatKey(pinCodeKey), null)
+
+ var biometricsAuth: Boolean? by SharedPrefBooleanNullableDelegate(sharedPrefs, this, formatKey(biometricsKey))
+
+ var databasePassphrase: String? by SharedPrefStringSecuredDelegate(context, sharedPrefs, this, formatKey(walletDatabasePassphraseKey))
+
+ var attempts: LoginAttemptList? by SharedPrefGsonDelegate(
+ sharedPrefs,
+ this,
+ formatKey(loginAttemptsKey),
+ LoginAttemptList::class.java,
+ LoginAttemptList()
+ )
+
+ fun saveAttempt(attempt: LoginAttemptDto) {
+ this.attempts = attempts.orEmpty().apply {
+ add(attempt)
+ }
+ if (attempt.isSuccessful) {
+ attempts = null
+ }
+ }
+
+ fun clear() {
+ databasePassphrase = null
+ isAuthenticated = false
+ isFeatureAuthenticated = false
+ pinCode = null
+ biometricsAuth = null
+ attempts = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/sentry/SentryPrefRepository.kt b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/sentry/SentryPrefRepository.kt
new file mode 100644
index 000000000..b48a44a26
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/data/sharedPrefs/sentry/SentryPrefRepository.kt
@@ -0,0 +1,28 @@
+package com.tari.android.wallet.data.sharedPrefs.sentry
+
+import android.content.SharedPreferences
+import com.tari.android.wallet.data.repository.CommonRepository
+import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefBooleanNullableDelegate
+import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.network.formatKey
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SentryPrefRepository @Inject constructor(sharedPrefs: SharedPreferences, networkRepository: NetworkRepository) :
+ CommonRepository(networkRepository) {
+
+ private object Key {
+ const val disabledTimestamps = "tari_sentry_disabled"
+ }
+
+ var isEnabled: Boolean? by SharedPrefBooleanNullableDelegate(
+ sharedPrefs,
+ this,
+ formatKey(Key.disabledTimestamps),
+ )
+
+ fun clear() {
+ isEnabled = null
+ }
+}
diff --git a/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt b/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt
index b14feabf6..d893f09d9 100644
--- a/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt
+++ b/app/src/main/java/com/tari/android/wallet/di/ApplicationComponent.kt
@@ -42,6 +42,9 @@ import com.tari.android.wallet.ui.component.clipboardController.WalletAddressVie
import com.tari.android.wallet.ui.component.networkStateIndicator.ConnectionIndicatorViewModel
import com.tari.android.wallet.ui.fragment.auth.AuthActivity
import com.tari.android.wallet.ui.fragment.auth.AuthViewModel
+import com.tari.android.wallet.ui.fragment.biometrics.ChangeBiometricsViewModel
+import com.tari.android.wallet.ui.fragment.chat_list.ChatListViewModel
+import com.tari.android.wallet.ui.fragment.chat_list.chat.ChatViewModel
import com.tari.android.wallet.ui.fragment.contact_book.contactSelection.ContactSelectionViewModel
import com.tari.android.wallet.ui.fragment.contact_book.contacts.ContactsViewModel
import com.tari.android.wallet.ui.fragment.contact_book.details.ContactDetailsViewModel
@@ -57,6 +60,7 @@ import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowAct
import com.tari.android.wallet.ui.fragment.onboarding.createWallet.CreateWalletViewModel
import com.tari.android.wallet.ui.fragment.onboarding.inroduction.IntroductionViewModel
import com.tari.android.wallet.ui.fragment.onboarding.localAuth.LocalAuthViewModel
+import com.tari.android.wallet.ui.fragment.pinCode.EnterPinCodeViewModel
import com.tari.android.wallet.ui.fragment.profile.WalletInfoViewModel
import com.tari.android.wallet.ui.fragment.qr.QRScannerActivity
import com.tari.android.wallet.ui.fragment.qr.QRScannerViewModel
@@ -87,6 +91,7 @@ import com.tari.android.wallet.ui.fragment.settings.baseNodeConfig.addBaseNode.A
import com.tari.android.wallet.ui.fragment.settings.baseNodeConfig.changeBaseNode.ChangeBaseNodeViewModel
import com.tari.android.wallet.ui.fragment.settings.bluetoothSettings.BluetoothSettingsViewModel
import com.tari.android.wallet.ui.fragment.settings.bugReporting.BugsReportingViewModel
+import com.tari.android.wallet.ui.fragment.settings.dataCollection.DataCollectionViewModel
import com.tari.android.wallet.ui.fragment.settings.deleteWallet.DeleteWalletViewModel
import com.tari.android.wallet.ui.fragment.settings.logs.LogFilesManager
import com.tari.android.wallet.ui.fragment.settings.logs.logFiles.LogFilesViewModel
@@ -197,6 +202,11 @@ interface ApplicationComponent {
fun inject(viewModel: QRScannerViewModel)
fun inject(viewModel: TransferFragment)
fun inject(viewModel: ContactBookActionMenuViewModel)
+ fun inject(viewModel: ChatListViewModel)
+ fun inject(viewModel: ChatViewModel)
+ fun inject(viewModel: DataCollectionViewModel)
+ fun inject(viewModel: EnterPinCodeViewModel)
+ fun inject(viewModel: ChangeBiometricsViewModel)
fun getClipboardManager(): ClipboardManager
}
diff --git a/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt b/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt
index a83647464..492766ddc 100644
--- a/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt
+++ b/app/src/main/java/com/tari/android/wallet/di/WalletModule.kt
@@ -39,9 +39,8 @@ import com.tari.android.wallet.data.WalletConfig
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeSharedRepository
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository
-import com.tari.android.wallet.infrastructure.logging.BugReportingService
-import com.tari.android.wallet.network.NetworkConnectionStateReceiver
import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository
import com.tari.android.wallet.tor.TorConfig
import com.tari.android.wallet.tor.TorProxyManager
@@ -63,6 +62,7 @@ class WalletModule {
baseNodeSharedRepository: BaseNodeSharedRepository,
seedPhraseRepository: SeedPhraseRepository,
networkRepository: NetworkRepository,
+ securityPrefRepository: SecurityPrefRepository,
tariSettingsSharedRepository: TariSettingsSharedRepository,
baseNodes: BaseNodes
): WalletManager = WalletManager(
@@ -73,6 +73,7 @@ class WalletModule {
seedPhraseRepository,
networkRepository,
tariSettingsSharedRepository,
+ securityPrefRepository,
baseNodes,
torConfig
)
diff --git a/app/src/main/java/com/tari/android/wallet/event/Event.kt b/app/src/main/java/com/tari/android/wallet/event/Event.kt
index d7f1b5ecc..663a0967c 100644
--- a/app/src/main/java/com/tari/android/wallet/event/Event.kt
+++ b/app/src/main/java/com/tari/android/wallet/event/Event.kt
@@ -32,7 +32,12 @@
*/
package com.tari.android.wallet.event
-import com.tari.android.wallet.model.*
+import com.tari.android.wallet.model.CancelledTx
+import com.tari.android.wallet.model.CompletedTx
+import com.tari.android.wallet.model.PendingInboundTx
+import com.tari.android.wallet.model.PendingOutboundTx
+import com.tari.android.wallet.model.TransactionSendStatus
+import com.tari.android.wallet.model.TxId
import com.tari.android.wallet.ui.fragment.send.finalize.TxFailureReason
/**
diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt
index 801808084..12eb11c16 100644
--- a/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt
+++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIPublicKey.kt
@@ -54,11 +54,7 @@ class FFIPublicKey() : FFIBase() {
}
constructor(hex: HexString) : this() {
- if (hex.toString().length == 64) {
- runWithError { jniFromHex(hex.hex, it) }
- } else {
- throw FFIException(message = "HexString is not a valid PublicKey")
- }
+ runWithError { jniFromHex(hex.hex, it) }
}
constructor(privateKey: FFIPrivateKey) : this() {
diff --git a/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt b/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt
index fcbf933db..6466643e9 100644
--- a/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt
+++ b/app/src/main/java/com/tari/android/wallet/ffi/FFIWallet.kt
@@ -34,6 +34,7 @@ package com.tari.android.wallet.ffi
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.model.*
import com.tari.android.wallet.model.recovery.WalletRestorationResult
import com.tari.android.wallet.service.seedPhrase.SeedPhraseRepository
@@ -50,6 +51,7 @@ import java.util.concurrent.atomic.AtomicReference
class FFIWallet(
val sharedPrefsRepository: SharedPrefsRepository,
+ val securityPrefRepository: SecurityPrefRepository,
val seedPhraseRepository: SeedPhraseRepository,
val networkRepository: NetworkRepository,
val commsConfig: FFICommsConfig,
@@ -224,10 +226,10 @@ class FFIWallet(
val error = FFIError()
logger.i("Pre jniCreate")
- var passphrase = sharedPrefsRepository.databasePassphrase
+ var passphrase = securityPrefRepository.databasePassphrase
if (passphrase.isNullOrEmpty()) {
passphrase = sharedPrefsRepository.generateDatabasePassphrase()
- sharedPrefsRepository.databasePassphrase = passphrase
+ securityPrefRepository.databasePassphrase = passphrase
}
try {
diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt
index cb6c6da98..5935e15ba 100644
--- a/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt
+++ b/app/src/main/java/com/tari/android/wallet/infrastructure/backup/BackupFileProcessor.kt
@@ -35,7 +35,7 @@ package com.tari.android.wallet.infrastructure.backup
import com.google.gson.Gson
import com.orhanobut.logger.Logger
import com.tari.android.wallet.data.WalletConfig
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.extension.encrypt
import com.tari.android.wallet.ffi.FFIError
import com.tari.android.wallet.ffi.FFIWallet
@@ -54,7 +54,7 @@ import javax.inject.Singleton
@Singleton
class BackupFileProcessor @Inject constructor(
private val backupSettingsRepository: BackupSettingsRepository,
- private val sharedPrefsRepository: SharedPrefsRepository,
+ private val securityPrefRepository: SecurityPrefRepository,
private val walletConfig: WalletConfig,
private val namingPolicy: BackupNamingPolicy,
) {
@@ -88,7 +88,7 @@ class BackupFileProcessor @Inject constructor(
logger.i("Partial files was generated")
return Triple(outputFile, backupDate, mimeType)
} else {
- val passphrase = sharedPrefsRepository.databasePassphrase!!
+ val passphrase = securityPrefRepository.databasePassphrase!!
val passphraseFile = File(walletConfig.getWalletTempDirPath(), namingPolicy.getPassphraseFileName())
passphraseFile.bufferedWriter().use { it.append(passphrase) }
@@ -133,7 +133,7 @@ class BackupFileProcessor @Inject constructor(
val passphraseFile = File(walletConfig.getWalletFilesDirPath(), namingPolicy.getPassphraseFileName())
val passphrase = passphraseFile.readText()
- sharedPrefsRepository.databasePassphrase = passphrase
+ securityPrefRepository.databasePassphrase = passphrase
unencryptedCompressedFile.delete()
diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/bluetooth/TariBluetoothServer.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/bluetooth/TariBluetoothServer.kt
index 3d1f89061..a8cc28c27 100644
--- a/app/src/main/java/com/tari/android/wallet/infrastructure/bluetooth/TariBluetoothServer.kt
+++ b/app/src/main/java/com/tari/android/wallet/infrastructure/bluetooth/TariBluetoothServer.kt
@@ -9,7 +9,6 @@ import android.bluetooth.le.AdvertiseSettings
import android.os.ParcelUuid
import com.tari.android.wallet.application.deeplinks.DeepLink
import com.tari.android.wallet.application.deeplinks.DeeplinkHandler
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.bluetooth.BluetoothServerState
import com.tari.android.wallet.data.sharedPrefs.bluetooth.ShareSettingsRepository
import com.tari.android.wallet.extension.addTo
@@ -32,9 +31,7 @@ import javax.inject.Singleton
class TariBluetoothServer @Inject constructor(
private val shareSettingsRepository: ShareSettingsRepository,
val deeplinkHandler: DeeplinkHandler,
- val sharedPrefsRepository: SharedPrefsRepository
-) :
- TariBluetoothAdapter() {
+) : TariBluetoothAdapter() {
private var bluetoothGattServer: BluetoothGattServer? = null
@@ -151,7 +148,7 @@ class TariBluetoothServer @Inject constructor(
val data = deeplinkHandler.getDeeplink(
DeepLink.UserProfile(
sharedPrefsRepository.publicKeyHexString.orEmpty(),
- ContactDto.normalizeAlias(sharedPrefsRepository.name.orEmpty(), myWalletAddress),
+ ContactDto.normalizeAlias((sharedPrefsRepository.name.orEmpty() + " " + sharedPrefsRepository.surname).trim(), myWalletAddress),
)
)
logger.i("contactlessPayment: read: whole data: $data")
diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt
index 0d0a04e04..f9ac61efa 100644
--- a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt
+++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/LoggerAdapter.kt
@@ -4,17 +4,18 @@ import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import com.tari.android.wallet.BuildConfig
import com.tari.android.wallet.data.WalletConfig
+import com.tari.android.wallet.data.sharedPrefs.sentry.SentryPrefRepository
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class LoggerAdapter @Inject constructor(val walletConfig: WalletConfig) {
+class LoggerAdapter @Inject constructor(val walletConfig: WalletConfig, private val sentryPrefRepository: SentryPrefRepository) {
fun init() {
Logger.addLogAdapter(AndroidLogAdapter())
Logger.addLogAdapter(FFIFileAdapter())
@Suppress("KotlinConstantConditions")
if (BuildConfig.FLAVOR != "privacy") {
- Logger.addLogAdapter(SentryLogAdapter(walletConfig))
+ Logger.addLogAdapter(SentryLogAdapter(walletConfig, sentryPrefRepository))
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt
index eb6d7adc0..5aae4d368 100644
--- a/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt
+++ b/app/src/main/java/com/tari/android/wallet/infrastructure/logging/SentryLogAdapter.kt
@@ -3,20 +3,30 @@ package com.tari.android.wallet.infrastructure.logging
import com.orhanobut.logger.LogAdapter
import com.orhanobut.logger.Logger
import com.tari.android.wallet.data.WalletConfig
+import com.tari.android.wallet.data.sharedPrefs.sentry.SentryPrefRepository
import com.tari.android.wallet.util.WalletUtil
-import io.sentry.*
+import com.welie.blessed.BluetoothPeripheralManager
+import io.sentry.Attachment
+import io.sentry.Breadcrumb
+import io.sentry.Hint
+import io.sentry.Sentry
+import io.sentry.SentryEvent
+import io.sentry.SentryLevel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
-class SentryLogAdapter(val walletConfig: WalletConfig) : LogAdapter {
+class SentryLogAdapter(val walletConfig: WalletConfig,
+ private val sentryPrefRepository: SentryPrefRepository) : LogAdapter {
private var localScope = CoroutineScope(Job())
- override fun isLoggable(priority: Int, tag: String?): Boolean = true
+ override fun isLoggable(priority: Int, tag: String?): Boolean = sentryPrefRepository.isEnabled == true
override fun log(priority: Int, tag: String?, message: String) {
+ if (tag == BluetoothPeripheralManager::class.java.simpleName) return
+
if (priority == Logger.ERROR) {
localScope.launch(Dispatchers.IO) {
try {
diff --git a/app/src/main/java/com/tari/android/wallet/infrastructure/nfc/TariNFCAdapter.kt b/app/src/main/java/com/tari/android/wallet/infrastructure/nfc/TariNFCAdapter.kt
deleted file mode 100644
index c2742e9dd..000000000
--- a/app/src/main/java/com/tari/android/wallet/infrastructure/nfc/TariNFCAdapter.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.tari.android.wallet.infrastructure.nfc
-
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_MUTABLE
-import android.content.Intent
-import android.content.IntentFilter
-import android.nfc.NdefMessage
-import android.nfc.NdefRecord
-import android.nfc.NfcAdapter
-import android.os.Build
-import androidx.appcompat.app.AppCompatActivity
-import com.tari.android.wallet.application.deeplinks.DeepLink
-import com.tari.android.wallet.application.deeplinks.DeeplinkHandler
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
-import com.tari.android.wallet.ui.common.CommonViewModel
-import com.tari.android.wallet.ui.fragment.home.HomeActivity
-import java.nio.charset.Charset
-import java.util.Locale
-import javax.inject.Inject
-import javax.inject.Singleton
-
-
-@Singleton
-class TariNFCAdapter @Inject constructor(
- val deeplinkHandler: DeeplinkHandler,
- val sharedPrefsRepository: SharedPrefsRepository
-) : CommonViewModel() {
-
- val MIME_TEXT_PLAIN = "text/plain"
-
- var context: AppCompatActivity? = null
-
- var onSuccessSharing: () -> Unit = {}
- var onFailedSharing: (String) -> Unit = {}
-
- var onReceived: (List) -> Unit = {}
-
- fun onNewIntent(intent: Intent) {
- if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
- intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
- val messages: List = rawMessages.map { it as NdefMessage }
- val first = messages.firstOrNull() ?: return
- val actualMessage = first.records.firstOrNull()?.payload ?: return
- val payload = String(actualMessage, Charsets.UTF_16)
- doHandling(payload)
- }
- }
- }
-
- private fun doHandling(string: String) {
- val handled = runCatching { deeplinkHandler.handle(string) }.getOrNull()
-
- if (handled != null && handled is DeepLink.Contacts) {
- onReceived.invoke(handled.contacts)
- }
- }
-
- fun stopSharing() {
- val nfcAdapter = NfcAdapter.getDefaultAdapter(context!!)
- nfcAdapter.setNdefPushMessageCallback(null, context)
- nfcAdapter.setOnNdefPushCompleteCallback(null, context)
- }
-
- fun startSharing(data: String) {
- val adapter = NfcAdapter.getDefaultAdapter(context!!) ?: return
- if (adapter.isEnabled.not()) {
- showNFCSettings()
- return
- }
- createTag(data)
- }
-
- private fun createTag(data: String) {
- val outBytes: ByteArray = data.toByteArray(Charsets.UTF_16)
- val outRecord = NdefRecord.createMime(MIME_TEXT_PLAIN, outBytes)
-
- val nfcAdapter = NfcAdapter.getDefaultAdapter(context!!)
- nfcAdapter.enableForegroundNdefPush(context, NdefMessage(outRecord))
- nfcAdapter.setOnNdefPushCompleteCallback({ onSuccessSharing() }, context)
- nfcAdapter.setNdefPushMessageCallback({ NdefMessage(outRecord) }, context)
- }
-
- fun enableForegroundDispatch(activity: AppCompatActivity) {
- val adapter = NfcAdapter.getDefaultAdapter(activity) ?: return
-
- val intent = Intent(activity.applicationContext, HomeActivity::class.java)
- intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
- val pendingIntent = PendingIntent.getActivity(activity.applicationContext, 0, intent, FLAG_MUTABLE)
- val filters = arrayOfNulls(1)
- val techList = arrayOf>()
- filters[0] = IntentFilter()
- filters[0]!!.addAction(NfcAdapter.ACTION_NDEF_DISCOVERED)
- filters[0]!!.addCategory(Intent.CATEGORY_DEFAULT)
- try {
- filters[0]!!.addDataType(MIME_TEXT_PLAIN)
- } catch (ex: IntentFilter.MalformedMimeTypeException) {
- throw RuntimeException("Check your MIME type")
- }
- adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList)
- }
-
- fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord {
- val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII"))
- val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16")
- val textBytes = payload.toByteArray(utfEncoding)
- val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7
- val status = (utfBit + langBytes.size).toChar()
- val data = ByteArray(1 + langBytes.size + textBytes.size)
- data[0] = status.code.toByte()
- System.arraycopy(langBytes, 0, data, 1, langBytes.size)
- System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size)
- return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data)
- }
-
- fun disableForegroundDispatch(activity: AppCompatActivity?) {
- val adapter = NfcAdapter.getDefaultAdapter(activity) ?: return
- adapter.disableForegroundDispatch(activity)
- }
-
- fun isNFCAvailable(): Boolean {
- val adapter = NfcAdapter.getDefaultAdapter(context!!)
- return adapter != null && adapter.isEnabled
- }
-
- fun isNFCSupported(): Boolean {
- val adapter = NfcAdapter.getDefaultAdapter(context!!)
- val sdk = Build.VERSION.SDK_INT
- return adapter != null && sdk < Build.VERSION_CODES.Q
- }
-
- fun showNFCSettings() {
- val intent = Intent(android.provider.Settings.ACTION_NFC_SETTINGS)
- context?.startActivity(intent)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/model/TariWalletAddress.kt b/app/src/main/java/com/tari/android/wallet/model/TariWalletAddress.kt
index c34d0b9dc..482122eef 100644
--- a/app/src/main/java/com/tari/android/wallet/model/TariWalletAddress.kt
+++ b/app/src/main/java/com/tari/android/wallet/model/TariWalletAddress.kt
@@ -48,8 +48,8 @@ class TariWalletAddress() : Parcelable, Serializable {
constructor(hexString: String, emojiId: String) : this() {
// crunch fix for not crashing on action related to wallet address
- if (hexString == "0000000000000000000000000000000000000000000000000000000000000026") {
- this.hexString = "000000000000000000000000000000000000000000000000000000000000000026"
+ if (hexString == zeroHex) {
+ this.hexString = zero66Hex
this.emojiId =
"\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF00\uD83C\uDF57"
} else {
@@ -58,6 +58,8 @@ class TariWalletAddress() : Parcelable, Serializable {
}
}
+ fun isZeros(): Boolean = hexString == zeroHex || hexString == zero66Hex || hexString.all { it == '0' }
+
override fun equals(other: Any?): Boolean = (other is TariWalletAddress) && hexString == other.hexString
override fun hashCode(): Int = hexString.hashCode()
@@ -72,6 +74,9 @@ class TariWalletAddress() : Parcelable, Serializable {
companion object CREATOR : Parcelable.Creator {
+ const val zeroHex = "0000000000000000000000000000000000000000000000000000000000000026"
+ const val zero66Hex = "000000000000000000000000000000000000000000000000000000000000000026"
+
override fun createFromParcel(parcel: Parcel): TariWalletAddress {
return TariWalletAddress(parcel)
}
@@ -80,6 +85,7 @@ class TariWalletAddress() : Parcelable, Serializable {
return Array(size) { TariWalletAddress() }
}
+ fun validate(addressHex: String): Boolean = addressHex.length > 64
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
@@ -97,5 +103,4 @@ class TariWalletAddress() : Parcelable, Serializable {
}
// endregion
-
}
diff --git a/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt b/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt
index ecc096ec9..435498209 100644
--- a/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt
+++ b/app/src/main/java/com/tari/android/wallet/service/service/TariWalletServiceStubImpl.kt
@@ -149,6 +149,8 @@ class TariWalletServiceStubImpl(
override fun cancelPendingTx(id: TxId, error: WalletError): Boolean = runMapping(error) { wallet.cancelPendingTx(id.value) } ?: false
override fun addBaseNodePeer(baseNodePublicKey: String, baseNodeAddress: String, error: WalletError): Boolean = runMapping(error) {
+ Logger.t(this::class.simpleName).e("walletServiceStub:addBaseNodePeer:publicKeyHex: ${baseNodePublicKey}")
+ Logger.t(this::class.simpleName).e("walletServiceStub:addBaseNodePeer:address: ${baseNodeAddress}")
val result = FFIPublicKey(HexString(baseNodePublicKey)).runWithDestroy { wallet.addBaseNodePeer(it, baseNodeAddress) }
if (result) {
walletServiceListener.baseNodeValidationStatusMap.clear()
diff --git a/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt b/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt
index 482b910e9..c6167f48a 100644
--- a/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt
+++ b/app/src/main/java/com/tari/android/wallet/tor/TorProxyControl.kt
@@ -72,6 +72,7 @@ class TorProxyControl(private val torConfig: TorConfig) {
private fun checkTorStatus() {
try {
val bootstrapStatus = isTorRunning(controlConnection)
+ logger.i(bootstrapStatus.toString())
if (bootstrapStatus != null) {
if (bootstrapStatus.progress == 100 && bootstrapStatus.summary == "Done") {
updateState(TorProxyState.Running(bootstrapStatus))
@@ -87,6 +88,7 @@ class TorProxyControl(private val torConfig: TorConfig) {
updateState(TorProxyState.Failed(Throwable("Tor not running")))
}
} catch (throwable: Throwable) {
+ logger.i("tor state during fall: ${EventBus.torProxyState.publishSubject.value}")
logger.e(throwable, "Tor proxy has failed")
updateState(TorProxyState.Failed(throwable))
}
@@ -99,6 +101,8 @@ class TorProxyControl(private val torConfig: TorConfig) {
}
private fun updateState(newState: TorProxyState) {
+ logger.i("tor update old state: ${EventBus.torProxyState.publishSubject.value}")
+ logger.i("tor update new state: $newState")
if (newState != EventBus.torProxyState.publishSubject.value) {
EventBus.torProxyState.post(newState)
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt
index c6df1e339..6be51da48 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/common/CommonActivity.kt
@@ -1,5 +1,6 @@
package com.tari.android.wallet.ui.common
+import android.app.Activity
import android.content.Intent
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.content.res.Configuration.UI_MODE_NIGHT_YES
@@ -121,6 +122,14 @@ abstract class CommonActivity : App
super.onStart()
}
+ fun launch(destination: Class) {
+ val intent = Intent(this, destination)
+ intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
+ this.intent.data?.let(intent::setData)
+ startActivity(intent)
+ finish()
+ }
+
override fun onResume() {
super.onResume()
@@ -144,7 +153,7 @@ abstract class CommonActivity : App
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dialogManager.context = this
- overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left)
+
subscribeToCommon(connectionStateViewModel)
}
@@ -152,11 +161,6 @@ abstract class CommonActivity : App
containerId = id
}
- override fun onBackPressed() {
- super.onBackPressed()
- overridePendingTransition(R.anim.enter_from_left, R.anim.exit_to_right)
- }
-
fun addFragment(fragment: Fragment, bundle: Bundle? = null, isRoot: Boolean = false, withAnimation: Boolean = true) {
bundle?.let { fragment.arguments = it }
if (supportFragmentManager.isDestroyed) return
@@ -172,7 +176,11 @@ abstract class CommonActivity : App
}
fun popUpTo(tag: String) {
- while (supportFragmentManager.fragments.last().tag != tag && supportFragmentManager.backStackEntryCount > 0) {
+ viewModel.logger.e("popUpTo $tag")
+ viewModel.logger.e("popUpTo:last ${supportFragmentManager.fragments.last().tag}")
+ viewModel.logger.e("popUpTo:all ${supportFragmentManager.fragments.map { it.tag }.joinToString(", ")}")
+ viewModel.logger.e("popUpTo:all ${supportFragmentManager.fragments.map { it::class.java }.joinToString(", ")}")
+ while (supportFragmentManager.fragments.last()::class.java.simpleName != tag && supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStackImmediate()
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt
index af1334e6a..04c547af9 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/common/CommonViewModel.kt
@@ -7,7 +7,9 @@ import com.orhanobut.logger.Logger
import com.orhanobut.logger.Printer
import com.tari.android.wallet.R
import com.tari.android.wallet.application.WalletState
+import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository
import com.tari.android.wallet.di.ApplicationComponent
import com.tari.android.wallet.di.DiContainer
@@ -68,13 +70,20 @@ open class CommonViewModel : ViewModel() {
@Inject
lateinit var tariNavigator: TariNavigator
+ @Inject
+ lateinit var sharedPrefsRepository: SharedPrefsRepository
+
+ @Inject
+ lateinit var securityPrefRepository: SecurityPrefRepository
+
+ private var authorizedAction: (() -> Unit)? = null
+
val logger: Printer
get() = Logger.t(this::class.simpleName).t(LoggerTags.UI.name)
val currentTheme = SingleLiveEvent()
- protected val _backPressed = SingleLiveEvent()
- val backPressed: LiveData = _backPressed
+ val backPressed = SingleLiveEvent()
protected val _openLink = SingleLiveEvent()
val openLink: LiveData = _openLink
@@ -108,6 +117,10 @@ open class CommonViewModel : ViewModel() {
logger.t(LoggerTags.Navigation.name).i(this::class.simpleName + " was started")
+ securityPrefRepository.updateNotifier.subscribe {
+ checkAuthorization()
+ }.addTo(compositeDisposable)
+
EventBus.walletState.publishSubject.filter { it is WalletState.Failed }
.subscribe({
val exception = (it as WalletState.Failed).exception
@@ -152,5 +165,19 @@ open class CommonViewModel : ViewModel() {
modularDialog.postValue(modularArgs)
}
+ fun runWithAuthorization(action: () -> Unit) {
+ authorizedAction = action
+ navigation.postValue(Navigation.FeatureAuth())
+ }
+
+ fun checkAuthorization() {
+ if (authorizedAction != null && securityPrefRepository.isFeatureAuthenticated) {
+ securityPrefRepository.isFeatureAuthenticated = false
+ backPressed.value = Unit
+ authorizedAction?.invoke()
+ authorizedAction = null
+ }
+ }
+
fun doOnBackground(action: suspend CoroutineScope.() -> Unit): Job = viewModelScope.launch { action() }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt
index 2df6fca08..f191149cb 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/presentation/GlideGIFListener.kt
@@ -11,7 +11,7 @@ class GlideGIFListener(private val consumer: GIFStateConsumer) : RequestListener
override fun onLoadFailed(
e: GlideException?,
model: Any?,
- target: Target?,
+ target: Target,
isFirstResource: Boolean
): Boolean {
consumer.onErrorState()
@@ -19,10 +19,10 @@ class GlideGIFListener(private val consumer: GIFStateConsumer) : RequestListener
}
override fun onResourceReady(
- resource: GifDrawable?,
- model: Any?,
+ resource: GifDrawable,
+ model: Any,
target: Target?,
- dataSource: DataSource?,
+ dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
consumer.onResourceReady()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GIFItem.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GIFItem.kt
index 8daf6d20d..93b62899b 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GIFItem.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GIFItem.kt
@@ -55,4 +55,6 @@ data class GIFItem(val id: String, val embedUri: Uri, val uri: Uri) : Parcelable
override fun newArray(size: Int): Array = arrayOfNulls(size)
}
+
+ override fun toString(): String = "GIFItem(id='$id', embedUri=$embedUri, uri=$uri)"
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GiphyRESTRetrofitRepository.kt b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GiphyRESTRetrofitRepository.kt
index abc45e443..3786d2323 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GiphyRESTRetrofitRepository.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/common/gyphy/repository/GiphyRESTRetrofitRepository.kt
@@ -26,13 +26,16 @@ class GiphyRESTRetrofitRepository(private val gateway: GiphyRESTGateway) : GIFRe
}
override fun getById(id: String): GIFItem {
- val response: Response = gateway.getGIFByID(id).execute()
+ val request = gateway.getGIFByID(id)
+ val response: Response = request.execute()
val body = response.body()
return if (response.isSuccessful && body != null && body.meta.status in 200..299)
body.data.let { GIFItem(it.id, Uri.parse(it.embedUrl), Uri.parse(it.images.fixedWidth.url)) }
else {
val exception = GIFSearchException(body?.meta?.message ?: response.message() ?: response.errorBody()?.string())
- logger.e(exception, "Get all was failed")
+ logger.e(exception.message.orEmpty())
+ logger.e(exception.stackTraceToString())
+ logger.e(exception, "Get by id was failed")
throw exception
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/component/clipboardController/WalletAddressViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/component/clipboardController/WalletAddressViewModel.kt
index cb9a79173..c9e7c4285 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/component/clipboardController/WalletAddressViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/component/clipboardController/WalletAddressViewModel.kt
@@ -43,7 +43,7 @@ class WalletAddressViewModel : CommonViewModel() {
runCatching {
checkForValidEmojiId(walletService, clipboardString)
- discoveredWalletAddressFromClipboard.value = discoveredWalletAddress
+ discoveredWalletAddressFromClipboard.postValue(discoveredWalletAddress)
}
}
}
@@ -51,7 +51,7 @@ class WalletAddressViewModel : CommonViewModel() {
fun checkFromQuery(walletService: TariWalletService, query: String) {
doOnConnectedToWallet {
checkForValidEmojiId(walletService, query)
- discoveredWalletAddressFromQuery.value = discoveredWalletAddress
+ discoveredWalletAddressFromQuery.postValue(discoveredWalletAddress)
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt
index 11e3b949a..ce38714f7 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthActivity.kt
@@ -32,115 +32,94 @@
*/
package com.tari.android.wallet.ui.fragment.auth
-import android.animation.AnimatorSet
-import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.content.Intent
import android.os.Bundle
-import android.view.View
+import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
-import androidx.core.animation.addListener
-import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
-import com.daasuu.ei.Ease
-import com.daasuu.ei.EasingInterpolator
+import com.tari.android.wallet.R
import com.tari.android.wallet.R.string.auth_biometric_prompt
import com.tari.android.wallet.R.string.auth_device_lock_code_prompt
-import com.tari.android.wallet.R.string.auth_failed_desc
-import com.tari.android.wallet.R.string.auth_failed_title
import com.tari.android.wallet.R.string.auth_not_available_or_canceled_desc
import com.tari.android.wallet.R.string.auth_not_available_or_canceled_title
import com.tari.android.wallet.R.string.auth_title
import com.tari.android.wallet.R.string.exit
import com.tari.android.wallet.R.string.proceed
+import com.tari.android.wallet.data.sharedPrefs.security.LoginAttemptDto
import com.tari.android.wallet.databinding.ActivityAuthBinding
import com.tari.android.wallet.extension.observe
import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationException
import com.tari.android.wallet.ui.common.CommonActivity
-import com.tari.android.wallet.ui.extension.addAnimatorListener
-import com.tari.android.wallet.ui.extension.invisible
import com.tari.android.wallet.ui.extension.setColor
import com.tari.android.wallet.ui.extension.string
import com.tari.android.wallet.ui.extension.visible
import com.tari.android.wallet.ui.fragment.home.HomeActivity
+import com.tari.android.wallet.ui.fragment.pinCode.EnterPinCodeFragment
+import com.tari.android.wallet.ui.fragment.pinCode.PinCodeScreenBehavior
import com.tari.android.wallet.ui.fragment.settings.allSettings.TariVersionModel
-import com.tari.android.wallet.util.Build.MOCKED
-import com.tari.android.wallet.util.Constants
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-/**
- * Initial activity class - authenticates the user.
- *
- * @author The Tari Development Team
- */
class AuthActivity : CommonActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- ui = ActivityAuthBinding.inflate(layoutInflater).apply { setContentView(root) }
val viewModel: AuthViewModel by viewModels()
bindViewModel(viewModel)
+ onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() = Unit
+ })
+
+ ui = ActivityAuthBinding.inflate(layoutInflater).apply { setContentView(root) }
+
setupUi()
observe(viewModel.goAuth) {
- // call the animations
- showTariText()
viewModel.walletServiceLauncher.start()
}
+
+ doAuth()
+ }
+
+ private fun setupPinCodeFragment() {
+ val pinCode = viewModel.securityPrefRepository.pinCode
+ if (pinCode != null) {
+ val pinCodeFragment = EnterPinCodeFragment.newInstance(PinCodeScreenBehavior.Auth, pinCode)
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fragment_container, pinCodeFragment)
+ .commit()
+ }
}
private fun setupUi() {
- ui.progressBar.setColor(viewModel.paletteManager.getWhite(this))
- ui.progressBar.invisible()
ui.networkInfoTextView.text = TariVersionModel(viewModel.networkRepository).versionInfo
}
- override fun onBackPressed() = Unit
-
- /**
- * Hides the gem and displays Tari logo.
- */
- private fun showTariText() {
- // hide features to be shown after animation
- ui.authAnimLottieAnimationView.alpha = 0f
- ui.networkInfoTextView.alpha = 0f
- ui.smallGemImageView.alpha = 0f
+ private fun doAuth() {
+ showBiometricAuth()
- // define animations
- val hideGemAnim = ValueAnimator.ofFloat(1f, 0f).apply {
- addUpdateListener { valueAnimator: ValueAnimator ->
- val alpha = valueAnimator.animatedValue as Float
- ui.bigGemImageView.alpha = alpha
- }
- }
- val showTariTextAnim = ValueAnimator.ofFloat(0f, 1f).apply {
- addUpdateListener { valueAnimator: ValueAnimator ->
- val alpha = valueAnimator.animatedValue as Float
- ui.authAnimLottieAnimationView.alpha = alpha
- ui.networkInfoTextView.alpha = alpha
- ui.smallGemImageView.alpha = alpha
+ // check whether there's at least screen lock
+ if (viewModel.authService.isDeviceSecured) {
+ lifecycleScope.launch {
+ try {
+ setupPinCodeFragment()
+ } catch (e: BiometricAuthenticationException) {
+ viewModel.logger.e(e, "Authentication has failed")
+ }
}
- }
- AnimatorSet().apply {
- startDelay = Constants.UI.shortDurationMs
- play(showTariTextAnim).after(hideGemAnim)
- duration = Constants.UI.shortDurationMs
- interpolator = EasingInterpolator(Ease.QUART_IN)
- addListener(onEnd = { doAuth() })
- start()
+ } else {
+ displayAuthNotAvailableDialog()
}
}
- private fun doAuth() {
- // check whether there's at least screen lock
+ fun showBiometricAuth() {
if (viewModel.authService.isDeviceSecured) {
lifecycleScope.launch {
try {
- if (!MOCKED) {
+ if (viewModel.securityPrefRepository.biometricsAuth == true) {
// prompt system authentication dialog
viewModel.authService.authenticate(
this@AuthActivity,
@@ -149,33 +128,17 @@ class AuthActivity : CommonActivity() {
if (viewModel.authService.isBiometricAuthAvailable) string(auth_biometric_prompt)
else string(auth_device_lock_code_prompt)
)
+ proceedLogin()
}
- authSuccessful()
} catch (e: BiometricAuthenticationException) {
- authHasFailed()
+ viewModel.logger.e(e, "Authentication has failed")
}
}
} else {
- // local authentication not available
displayAuthNotAvailableDialog()
}
}
- /**
- * Auth was successful.
- */
- private fun authSuccessful() {
- viewModel.sharedPrefsWrapper.isAuthenticated = true
- playTariWalletAnim()
- }
-
- /**
- * Auth has failed.
- */
- private fun authHasFailed() {
- displayAuthFailedDialog()
- }
-
/**
* Auth not available on device, i.e. lock screen is disabled
*/
@@ -186,8 +149,8 @@ class AuthActivity : CommonActivity() {
.setPositiveButton(getString(proceed)) { dialog, _ ->
dialog.cancel()
// user has chosen to proceed without authentication
- viewModel.sharedPrefsWrapper.isAuthenticated = true
- playTariWalletAnim()
+ viewModel.securityPrefRepository.isAuthenticated = true
+ proceedLogin()
}
// negative button text and action
.setNegativeButton(getString(exit)) { _, _ -> finish() }
@@ -196,58 +159,17 @@ class AuthActivity : CommonActivity() {
dialog.show()
}
- private fun displayAuthFailedDialog() {
- val state = lifecycle.currentState
- if (state == Lifecycle.State.RESUMED || state == Lifecycle.State.STARTED) {
- AlertDialog.Builder(this)
- .setMessage(getString(auth_failed_desc))
- .setCancelable(false)
- .setNegativeButton(getString(exit)) { _, _ -> finish() }
- .run(AlertDialog.Builder::create)
- .apply { setTitle(string(auth_failed_title)) }
- .show()
- }
- }
-
- /**
- * Plays Tari Wallet text anim.
- */
- private fun playTariWalletAnim() {
- ui.authAnimLottieAnimationView.addAnimatorListener(onEnd = {
- ui.progressBar.alpha = 0f
- ui.progressBar.visible()
- ObjectAnimator.ofFloat(ui.progressBar, View.ALPHA, 0f, 1f).apply {
- duration = Constants.UI.mediumDurationMs
- start()
- }
-
- proceedLogin()
- })
- ui.authAnimLottieAnimationView.playAnimation()
-
- ValueAnimator.ofFloat(1f, 0f).apply {
- duration = Constants.UI.mediumDurationMs
- addUpdateListener { valueAnimator: ValueAnimator ->
- val alpha = valueAnimator.animatedValue as Float
- ui.smallGemImageView.alpha = alpha
- ui.networkInfoTextView.alpha = alpha
- }
- startDelay = Constants.UI.CreateWallet.introductionBottomViewsFadeOutDelay
- start()
- }
- }
-
private fun proceedLogin() {
+ viewModel.securityPrefRepository.saveAttempt(LoginAttemptDto(System.currentTimeMillis(), true))
lifecycleScope.launch(Dispatchers.Main) {
+ ui.loader.visible()
+ ui.progressBar.setColor(viewModel.paletteManager.getPurpleBrand(this@AuthActivity))
continueToHomeActivity()
}
}
- private fun continueToHomeActivity() {
- ObjectAnimator.ofFloat(ui.progressBar, View.ALPHA, 1f, 0f).apply {
- duration = Constants.UI.shortDurationMs
- start()
- }
+ fun continueToHomeActivity() {
+ viewModel.securityPrefRepository.isAuthenticated = true
// go to home activity
Intent(this, HomeActivity::class.java).apply {
@@ -257,5 +179,4 @@ class AuthActivity : CommonActivity() {
}
finish()
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt
index a9467a6e3..b697381c0 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/AuthViewModel.kt
@@ -3,7 +3,6 @@ package com.tari.android.wallet.ui.fragment.auth
import androidx.lifecycle.viewModelScope
import com.tari.android.wallet.R
import com.tari.android.wallet.application.MigrationManager
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationService
import com.tari.android.wallet.service.service.WalletServiceLauncher
import com.tari.android.wallet.ui.common.CommonViewModel
@@ -21,9 +20,6 @@ import javax.inject.Inject
class AuthViewModel : CommonViewModel() {
- @Inject
- lateinit var sharedPrefsWrapper: SharedPrefsRepository
-
@Inject
lateinit var authService: BiometricAuthenticationService
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/FeatureAuthFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/FeatureAuthFragment.kt
new file mode 100644
index 000000000..560291199
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/auth/FeatureAuthFragment.kt
@@ -0,0 +1,166 @@
+/**
+ * Copyright 2020 The Tari Project
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.tari.android.wallet.ui.fragment.auth
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import com.tari.android.wallet.R
+import com.tari.android.wallet.R.string.auth_biometric_prompt
+import com.tari.android.wallet.R.string.auth_device_lock_code_prompt
+import com.tari.android.wallet.R.string.auth_not_available_or_canceled_desc
+import com.tari.android.wallet.R.string.auth_not_available_or_canceled_title
+import com.tari.android.wallet.R.string.auth_title
+import com.tari.android.wallet.R.string.exit
+import com.tari.android.wallet.R.string.proceed
+import com.tari.android.wallet.data.sharedPrefs.security.LoginAttemptDto
+import com.tari.android.wallet.databinding.FragmentFeatureAuthBinding
+import com.tari.android.wallet.extension.observe
+import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationException
+import com.tari.android.wallet.ui.common.CommonFragment
+import com.tari.android.wallet.ui.extension.setColor
+import com.tari.android.wallet.ui.extension.string
+import com.tari.android.wallet.ui.extension.visible
+import com.tari.android.wallet.ui.fragment.pinCode.EnterPinCodeFragment
+import com.tari.android.wallet.ui.fragment.pinCode.PinCodeScreenBehavior
+import com.tari.android.wallet.ui.fragment.settings.allSettings.TariVersionModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class FeatureAuthFragment : CommonFragment() {
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ FragmentFeatureAuthBinding.inflate(inflater, container, false).also { ui = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val viewModel: AuthViewModel by viewModels()
+ bindViewModel(viewModel)
+
+ setupUi()
+
+ observe(viewModel.goAuth) {
+ viewModel.walletServiceLauncher.start()
+ }
+
+ doAuth()
+ }
+
+ private fun setupPinCodeFragment() {
+ val pinCode = viewModel.securityPrefRepository.pinCode
+ if (pinCode != null) {
+ val pinCodeFragment = EnterPinCodeFragment.newInstance(PinCodeScreenBehavior.FeatureAuth, pinCode)
+ childFragmentManager.beginTransaction()
+ .replace(R.id.fragment_container, pinCodeFragment)
+ .commit()
+ }
+ }
+
+ private fun setupUi() {
+ ui.networkInfoTextView.text = TariVersionModel(viewModel.networkRepository).versionInfo
+ }
+
+ private fun doAuth() {
+ // check whether there's at least screen lock
+ if (viewModel.authService.isDeviceSecured) {
+ try {
+ setupPinCodeFragment()
+ } catch (e: BiometricAuthenticationException) {
+ viewModel.logger.e(e, "Authentication has failed")
+ }
+ } else {
+ displayAuthNotAvailableDialog()
+ }
+
+ showBiometricAuth()
+ }
+
+ fun showBiometricAuth() {
+ if (viewModel.authService.isDeviceSecured) {
+ lifecycleScope.launch {
+ try {
+ if (viewModel.securityPrefRepository.biometricsAuth == true) {
+ // prompt system authentication dialog
+ viewModel.authService.authenticate(
+ this@FeatureAuthFragment,
+ title = string(auth_title),
+ subtitle =
+ if (viewModel.authService.isBiometricAuthAvailable) string(auth_biometric_prompt)
+ else string(auth_device_lock_code_prompt)
+ )
+ authSuccessfully()
+ }
+ } catch (e: BiometricAuthenticationException) {
+ viewModel.logger.e(e, "Authentication has failed")
+ }
+ }
+ } else {
+ displayAuthNotAvailableDialog()
+ }
+ }
+
+ /**
+ * Auth not available on device, i.e. lock screen is disabled
+ */
+ private fun displayAuthNotAvailableDialog() {
+ val dialog = AlertDialog.Builder(requireContext())
+ .setMessage(getString(auth_not_available_or_canceled_desc))
+ .setCancelable(false)
+ .setPositiveButton(getString(proceed)) { dialog, _ ->
+ dialog.cancel()
+ // user has chosen to proceed without authentication
+ viewModel.securityPrefRepository.isAuthenticated = true
+ authSuccessfully()
+ }
+ // negative button text and action
+ .setNegativeButton(getString(exit)) { _, _ -> viewModel.backPressed.postValue(Unit) }
+ .create()
+ dialog.setTitle(getString(auth_not_available_or_canceled_title))
+ dialog.show()
+ }
+
+ fun authSuccessfully() {
+ viewModel.securityPrefRepository.saveAttempt(LoginAttemptDto(System.currentTimeMillis(), true))
+ lifecycleScope.launch(Dispatchers.Main) {
+ ui.loader.visible()
+ ui.progressBar.setColor(viewModel.paletteManager.getPurpleBrand(requireContext()))
+
+ viewModel.securityPrefRepository.isFeatureAuthenticated = true
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/biometrics/ChangeBiometricsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/biometrics/ChangeBiometricsFragment.kt
new file mode 100644
index 000000000..e39fa7441
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/biometrics/ChangeBiometricsFragment.kt
@@ -0,0 +1,76 @@
+package com.tari.android.wallet.ui.fragment.biometrics
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import com.tari.android.wallet.R.string.auth_biometric_prompt
+import com.tari.android.wallet.R.string.auth_device_lock_code_prompt
+import com.tari.android.wallet.R.string.auth_title
+import com.tari.android.wallet.databinding.FragmentChangeBiometricsBinding
+import com.tari.android.wallet.extension.observe
+import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationException
+import com.tari.android.wallet.ui.common.CommonFragment
+import com.tari.android.wallet.ui.extension.string
+import com.tari.android.wallet.util.TariBuild.MOCKED
+import kotlinx.coroutines.launch
+
+class ChangeBiometricsFragment : CommonFragment() {
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ FragmentChangeBiometricsBinding.inflate(inflater, container, false).also { ui = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initUI()
+ }
+
+ private fun initUI() {
+ val viewModel: ChangeBiometricsViewModel by viewModels()
+ bindViewModel(viewModel)
+
+ ui.loadingSwitchView.setOnCheckedChangeListener {
+ doAuth(it)
+ }
+
+ observe(viewModel.state) { ui.loadingSwitchView.setState(it) }
+ }
+
+ private fun doAuth(isTurningOn: Boolean = false) {
+ // check whether there's at least screen lock
+ if (viewModel.authService.isDeviceSecured) {
+ viewModel.startAuth(isTurningOn)
+ lifecycleScope.launch {
+ try {
+ if (!MOCKED) {
+ // prompt system authentication dialog
+ viewModel.authService.authenticate(
+ this@ChangeBiometricsFragment,
+ title = string(auth_title),
+ subtitle =
+ if (viewModel.authService.isBiometricAuthAvailable) string(auth_biometric_prompt)
+ else string(auth_device_lock_code_prompt)
+ )
+ }
+ authSuccess(isTurningOn)
+ } catch (e: BiometricAuthenticationException) {
+ authFailed(isTurningOn)
+ }
+ }
+ } else {
+ authFailed(isTurningOn)
+ }
+ }
+
+ private fun authSuccess(isChecked: Boolean) {
+ viewModel.authSuccessfully(isChecked)
+ viewModel.stopAuth(isChecked)
+ }
+
+ private fun authFailed(isChecked: Boolean) {
+ viewModel.stopAuth(!isChecked)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/biometrics/ChangeBiometricsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/biometrics/ChangeBiometricsViewModel.kt
new file mode 100644
index 000000000..21af67720
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/biometrics/ChangeBiometricsViewModel.kt
@@ -0,0 +1,32 @@
+package com.tari.android.wallet.ui.fragment.biometrics
+
+import androidx.lifecycle.MutableLiveData
+import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationService
+import com.tari.android.wallet.ui.common.CommonViewModel
+import com.tari.android.wallet.ui.component.loadingSwitch.TariLoadingSwitchState
+import javax.inject.Inject
+
+class ChangeBiometricsViewModel : CommonViewModel() {
+
+ @Inject
+ lateinit var authService: BiometricAuthenticationService
+
+ val state: MutableLiveData = MutableLiveData()
+
+ init {
+ component.inject(this)
+ state.value = TariLoadingSwitchState(isChecked = securityPrefRepository.biometricsAuth == true, false)
+ }
+
+ fun startAuth(isChecked: Boolean) {
+ state.value = TariLoadingSwitchState(isChecked = isChecked, isLoading = true)
+ }
+
+ fun authSuccessfully(newState: Boolean) {
+ securityPrefRepository.biometricsAuth = newState
+ }
+
+ fun stopAuth(isChecked: Boolean) {
+ state.value = TariLoadingSwitchState(isChecked = isChecked, isLoading = false)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/ChatListFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/ChatListFragment.kt
new file mode 100644
index 000000000..eceda6deb
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/ChatListFragment.kt
@@ -0,0 +1,63 @@
+package com.tari.android.wallet.ui.fragment.chat_list
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.tari.android.wallet.R
+import com.tari.android.wallet.databinding.FragmentChatListBinding
+import com.tari.android.wallet.extension.observe
+import com.tari.android.wallet.ui.common.CommonFragment
+import com.tari.android.wallet.ui.common.recyclerView.AdapterFactory
+import com.tari.android.wallet.ui.common.recyclerView.CommonAdapter
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
+import com.tari.android.wallet.ui.component.tari.toolbar.TariToolbarActionArg
+import com.tari.android.wallet.ui.extension.setVisible
+import com.tari.android.wallet.ui.fragment.chat_list.adapter.ChatItemViewHolder
+import com.tari.android.wallet.ui.fragment.chat_list.adapter.ChatItemViewHolderItem
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
+
+class ChatListFragment : CommonFragment() {
+
+ val adapter: CommonAdapter by lazy { AdapterFactory.generate(ChatItemViewHolder.getBuilder()) }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ FragmentChatListBinding.inflate(inflater, container, false).also { ui = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val viewModel: ChatListViewModel by viewModels()
+ bindViewModel(viewModel)
+
+ initUI()
+
+ subscribeUI()
+ }
+
+ private fun initUI() = with(ui) {
+ list.layoutManager = LinearLayoutManager(requireContext())
+ list.adapter = adapter
+
+ adapter.setClickListener(CommonAdapter.ItemClickListener {
+ if (it is ChatItemViewHolderItem) {
+ viewModel.navigation.postValue(Navigation.ChatNavigation.ToChat(it.walletAddress, false))
+ }
+ })
+
+ val right = TariToolbarActionArg(R.drawable.vector_chat_add) {
+ viewModel.navigation.postValue(Navigation.ChatNavigation.ToAddChat)
+ }
+ toolbar.setRightArgs(right)
+ }
+
+ private fun subscribeUI() = with(viewModel) {
+ observe(list) {
+ adapter.submitList(it)
+ ui.list.setVisible(it.isNotEmpty())
+ ui.emptyState.setVisible(it.isEmpty())
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/ChatListViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/ChatListViewModel.kt
new file mode 100644
index 000000000..38079a990
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/ChatListViewModel.kt
@@ -0,0 +1,50 @@
+package com.tari.android.wallet.ui.fragment.chat_list
+
+import androidx.lifecycle.MediatorLiveData
+import com.tari.android.wallet.ui.common.CommonViewModel
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
+import com.tari.android.wallet.ui.fragment.chat_list.adapter.ChatItemViewHolderItem
+import com.tari.android.wallet.ui.fragment.chat_list.data.ChatsRepository
+import com.tari.android.wallet.ui.fragment.contact_book.data.ContactsRepository
+import com.tari.android.wallet.util.extractEmojis
+import javax.inject.Inject
+
+class ChatListViewModel : CommonViewModel() {
+
+ init {
+ component.inject(this)
+ }
+
+ @Inject
+ lateinit var chatsRepository: ChatsRepository
+
+ @Inject
+ lateinit var contactsRepository: ContactsRepository
+
+ val list = MediatorLiveData>()
+
+ init {
+ component.inject(this)
+
+ list.addSource(chatsRepository.list) {
+ list.postValue(it.map {
+ val firstEmoji = it.walletAddress.emojiId.extractEmojis().first()
+ val contact = contactsRepository.ffiBridge.getContactByAddress(it.walletAddress)
+ val lastMessage = it.messages.sortedBy { it.date }.lastOrNull()
+ val unreadCount = it.messages.count { it.isRead.not() }
+ ChatItemViewHolderItem(
+ it.walletAddress,
+ it.uuid,
+ firstEmoji,
+ contact.getPhoneDto()?.avatar.orEmpty(),
+ contact.contact.getAlias(),
+ it.walletAddress.emojiId,
+ lastMessage?.message.orEmpty(),
+ lastMessage?.date.orEmpty(),
+ unreadCount,
+ true
+ )
+ }.toMutableList())
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/adapter/ChatItemViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/adapter/ChatItemViewHolder.kt
new file mode 100644
index 000000000..0dcbc47f9
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/adapter/ChatItemViewHolder.kt
@@ -0,0 +1,53 @@
+package com.tari.android.wallet.ui.fragment.chat_list.adapter
+
+import com.bumptech.glide.Glide
+import com.tari.android.wallet.databinding.ItemChatItemBinding
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolder
+import com.tari.android.wallet.ui.common.recyclerView.ViewHolderBuilder
+import com.tari.android.wallet.ui.component.fullEmojiId.EmojiIdSummaryViewController
+import com.tari.android.wallet.ui.extension.gone
+import com.tari.android.wallet.ui.extension.setVisible
+import com.tari.android.wallet.ui.extension.visible
+
+class ChatItemViewHolder(view: ItemChatItemBinding) : CommonViewHolder(view) {
+
+ private val emojiIdSummaryController = EmojiIdSummaryViewController(ui.participantEmojiIdView)
+
+ override fun bind(item: ChatItemViewHolderItem) {
+ super.bind(item)
+
+ with(ui) {
+ onlineStatus.setVisible(item.isOnline)
+ unreadCountContainer.setVisible(item.unreadCount > 0)
+ unreadCount.text = item.unreadCount.toString()
+ date.text = item.dateMessage
+ message.text = item.subtitle
+ alias.text = item.alias
+
+ if (item.avatar.isNotEmpty()) {
+ firstEmojiTextView.gone()
+ avatar.visible()
+ Glide.with(avatar).load(item.avatar).into(avatar)
+ } else {
+ firstEmojiTextView.visible()
+ avatar.gone()
+ firstEmojiTextView.text = item.firstEmoji
+ }
+
+ if (item.alias.isEmpty()) {
+ participantEmojiIdView.root.visible()
+ alias.gone()
+ emojiIdSummaryController.display(item.emojiId)
+ } else {
+ participantEmojiIdView.root.gone()
+ alias.text = item.alias
+ alias.visible()
+ }
+ }
+ }
+
+ companion object {
+ fun getBuilder(): ViewHolderBuilder =
+ ViewHolderBuilder(ItemChatItemBinding::inflate, ChatItemViewHolderItem::class.java) { ChatItemViewHolder(it as ItemChatItemBinding) }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/adapter/ChatItemViewHolderItem.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/adapter/ChatItemViewHolderItem.kt
new file mode 100644
index 000000000..78b4f5d8d
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/adapter/ChatItemViewHolderItem.kt
@@ -0,0 +1,20 @@
+package com.tari.android.wallet.ui.fragment.chat_list.adapter
+
+import com.tari.android.wallet.model.TariWalletAddress
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
+
+data class ChatItemViewHolderItem(
+ val walletAddress: TariWalletAddress,
+ val uuid: String,
+ val firstEmoji: String,
+ val avatar: String,
+ val alias: String,
+ val emojiId: String,
+ val subtitle: String,
+ val dateMessage: String,
+ val unreadCount: Int,
+ val isOnline: Boolean,
+) :
+ CommonViewHolderItem() {
+ override val viewHolderUUID: String = ""
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/addChat/AddChatFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/addChat/AddChatFragment.kt
new file mode 100644
index 000000000..368f08e96
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/addChat/AddChatFragment.kt
@@ -0,0 +1,34 @@
+package com.tari.android.wallet.ui.fragment.chat_list.addChat
+
+import android.os.Bundle
+import android.view.View
+import com.tari.android.wallet.R
+import com.tari.android.wallet.ui.extension.gone
+import com.tari.android.wallet.ui.extension.string
+import com.tari.android.wallet.ui.fragment.chat_list.data.ChatItemDto
+import com.tari.android.wallet.ui.fragment.contact_book.contactSelection.ContactSelectionFragment
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
+import java.util.UUID
+
+class AddChatFragment : ContactSelectionFragment() {
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ ui.toolbar.ui.toolbarTitle.text = string(R.string.chat_add_chat)
+ ui.addFirstNameInput.gone()
+
+ viewModel.additionalFilter = { it.contact.getFFIDto() != null }
+ }
+
+ override fun goToNext() {
+ super.goToNext()
+
+ val user = viewModel.getUserDto()
+
+ val chatDto = ChatItemDto(UUID.randomUUID().toString(), listOf(), user.getFFIDto()!!.walletAddress)
+ viewModel.chatsRepository.addChat(chatDto)
+
+ viewModel.navigation.postValue(Navigation.ChatNavigation.ToChat(user.getFFIDto()?.walletAddress!!, true))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/ChatFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/ChatFragment.kt
new file mode 100644
index 000000000..728642d99
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/ChatFragment.kt
@@ -0,0 +1,76 @@
+package com.tari.android.wallet.ui.fragment.chat_list.chat
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.tari.android.wallet.databinding.FragmentChatBinding
+import com.tari.android.wallet.extension.observe
+import com.tari.android.wallet.model.TariWalletAddress
+import com.tari.android.wallet.ui.common.CommonFragment
+import com.tari.android.wallet.ui.common.recyclerView.AdapterFactory
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
+import com.tari.android.wallet.ui.extension.parcelable
+import com.tari.android.wallet.ui.extension.setVisible
+import com.tari.android.wallet.ui.fragment.chat_list.chat.cells.MessageCellViewHolder
+import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.ContactDto
+
+class ChatFragment : CommonFragment() {
+
+ private val adapter = AdapterFactory.generate(MessageCellViewHolder.getBuilder())
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ FragmentChatBinding.inflate(inflater, container, false).also { ui = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val viewModel: ChatViewModel by viewModels()
+ bindViewModel(viewModel)
+
+ val walletAddress = arguments?.parcelable(WALLET_ADDRESS)!!
+ viewModel.startWith(walletAddress)
+
+ initUI()
+ observeUI()
+ }
+
+ private fun initUI() {
+ ui.list.adapter = adapter
+ ui.list.layoutManager = LinearLayoutManager(requireContext())
+
+ ui.sendTariButton.setOnClickListener {
+ viewModel.sendMessage(ui.messageInput.ui.editText.text.toString())
+ ui.messageInput.setText("")
+ }
+
+ ui.attachButton.setOnClickListener { viewModel.showOptions() }
+ }
+
+ private fun observeUI() = with(viewModel) {
+ observe(contact) { showContact(it) }
+
+ observe(messages) {
+ adapter.update(it)
+ ui.emptyState.setVisible(it.isEmpty())
+ ui.list.setVisible(it.isNotEmpty())
+ }
+ }
+
+ private fun showContact(contact: ContactDto) {
+ ui.toolbar.setText(contact.contact.getAlias())
+ }
+
+ companion object {
+ const val WALLET_ADDRESS = "Wallet address key"
+
+ fun newInstance(walletAddress: TariWalletAddress) = ChatFragment().apply {
+ arguments = Bundle().apply {
+ putParcelable(WALLET_ADDRESS, walletAddress)
+ }
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/ChatViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/ChatViewModel.kt
new file mode 100644
index 000000000..3442d8701
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/ChatViewModel.kt
@@ -0,0 +1,85 @@
+package com.tari.android.wallet.ui.fragment.chat_list.chat
+
+import androidx.lifecycle.MutableLiveData
+import com.tari.android.wallet.R
+import com.tari.android.wallet.model.TariWalletAddress
+import com.tari.android.wallet.ui.common.CommonViewModel
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
+import com.tari.android.wallet.ui.dialog.modular.DialogArgs
+import com.tari.android.wallet.ui.dialog.modular.ModularDialogArgs
+import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonModule
+import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonStyle
+import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule
+import com.tari.android.wallet.ui.fragment.chat_list.chat.cells.MessagePresentationDto
+import com.tari.android.wallet.ui.fragment.chat_list.data.ChatMessageItemDto
+import com.tari.android.wallet.ui.fragment.chat_list.data.ChatsRepository
+import com.tari.android.wallet.ui.fragment.contact_book.data.ContactsRepository
+import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.ContactDto
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
+import java.util.UUID
+import javax.inject.Inject
+
+class ChatViewModel : CommonViewModel() {
+
+ @Inject
+ lateinit var contactsRepository: ContactsRepository
+
+ @Inject
+ lateinit var chatRepository: ChatsRepository
+
+ val userAddress = MutableLiveData()
+
+ val contact = MutableLiveData()
+
+ val messages = MutableLiveData>()
+
+ init {
+ component.inject(this)
+ }
+
+
+ fun startWith(walletAddress: TariWalletAddress) {
+ userAddress.postValue(walletAddress)
+
+ val contact = contactsRepository.ffiBridge.getContactByAddress(walletAddress)
+ this.contact.postValue(contact)
+
+ val chat = chatRepository.getByWalletAddress(walletAddress)
+
+ val list = mutableListOf()
+
+ val messagesPresentation = chat?.messages.orEmpty().map { getMessage(it) }
+ list.addAll(messagesPresentation)
+
+ this.messages.postValue(list)
+ }
+
+ private fun getMessage(dto: ChatMessageItemDto): MessagePresentationDto = MessagePresentationDto(dto.message, dto.isMine)
+
+ fun sendMessage(message: String) {
+ //todo send to backend
+ val list = messages.value.orEmpty().toMutableList()
+ val dto = ChatMessageItemDto(UUID.randomUUID().toString(), message, "date", true, false)
+ chatRepository.addMessage(userAddress.value!!, dto)
+ list.add(getMessage(dto))
+ messages.postValue(list)
+ }
+
+ fun showOptions() {
+ val args = ModularDialogArgs(
+ DialogArgs(), listOf(
+ HeadModule(resourceManager.getString(R.string.chat_options_title)),
+ ButtonModule(resourceManager.getString(R.string.send_tari), ButtonStyle.Normal) {
+ dismissDialog.postValue(Unit)
+ navigation.postValue(Navigation.ContactBookNavigation.ToSendTari(contact.value!!))
+ },
+ ButtonModule(resourceManager.getString(R.string.request_tari), ButtonStyle.Normal) {
+ dismissDialog.postValue(Unit)
+ navigation.postValue(Navigation.AllSettingsNavigation.ToRequestTari)
+ },
+ ButtonModule(resourceManager.getString(R.string.common_cancel), ButtonStyle.Close)
+ )
+ )
+ modularDialog.postValue(args)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/cells/MessageCellViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/cells/MessageCellViewHolder.kt
new file mode 100644
index 000000000..dc82358b0
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/cells/MessageCellViewHolder.kt
@@ -0,0 +1,20 @@
+package com.tari.android.wallet.ui.fragment.chat_list.chat.cells
+
+import com.tari.android.wallet.databinding.ItemChatItemBinding
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolder
+import com.tari.android.wallet.ui.common.recyclerView.ViewHolderBuilder
+
+class MessageCellViewHolder(ui: ItemChatItemBinding) : CommonViewHolder(ui) {
+
+ override fun bind(item: MessagePresentationDto) {
+ super.bind(item)
+
+ //todo
+ }
+
+ companion object {
+ fun getBuilder(): ViewHolderBuilder = ViewHolderBuilder(ItemChatItemBinding::inflate, MessagePresentationDto::class.java) {
+ MessageCellViewHolder(it as ItemChatItemBinding)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/cells/MessagePresentationDto.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/cells/MessagePresentationDto.kt
new file mode 100644
index 000000000..458617819
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/chat/cells/MessagePresentationDto.kt
@@ -0,0 +1,7 @@
+package com.tari.android.wallet.ui.fragment.chat_list.chat.cells
+
+import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
+
+data class MessagePresentationDto(val message: String, val isMine: Boolean) : CommonViewHolderItem() {
+ override val viewHolderUUID: String = "MessageCellViewHolder + $message + $isMine"
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatItemDto.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatItemDto.kt
new file mode 100644
index 000000000..fc3262988
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatItemDto.kt
@@ -0,0 +1,6 @@
+package com.tari.android.wallet.ui.fragment.chat_list.data
+
+import com.tari.android.wallet.model.TariWalletAddress
+import java.io.Serializable
+
+class ChatItemDto(val uuid: String, val messages: List, val walletAddress: TariWalletAddress) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatList.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatList.kt
new file mode 100644
index 000000000..a574eb44f
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatList.kt
@@ -0,0 +1,11 @@
+package com.tari.android.wallet.ui.fragment.chat_list.data
+
+import java.io.Serializable
+
+class ChatList() : ArrayList(), Serializable {
+ constructor(list: List) : this() {
+ this.addAll(list)
+ }
+}
+
+fun ChatList?.orEmpty(): ChatList = this ?: ChatList()
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatMessageItemDto.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatMessageItemDto.kt
new file mode 100644
index 000000000..10177c84f
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatMessageItemDto.kt
@@ -0,0 +1,3 @@
+package com.tari.android.wallet.ui.fragment.chat_list.data
+
+class ChatMessageItemDto(val uuid: String, val message: String, val date: String, val isMine: Boolean, val isRead: Boolean)
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatsPrefRepository.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatsPrefRepository.kt
new file mode 100644
index 000000000..eb3928bd3
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatsPrefRepository.kt
@@ -0,0 +1,52 @@
+package com.tari.android.wallet.ui.fragment.chat_list.data
+
+import android.content.SharedPreferences
+import com.tari.android.wallet.data.repository.CommonRepository
+import com.tari.android.wallet.data.sharedPrefs.delegates.SharedPrefGsonDelegate
+import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.network.formatKey
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ChatsPrefRepository @Inject constructor(
+ networkRepository: NetworkRepository,
+ val sharedPrefs: SharedPreferences
+) : CommonRepository(networkRepository) {
+
+ private var savedChats: ChatList? by SharedPrefGsonDelegate(sharedPrefs, this, formatKey(KEY_SAVED_CHATS), ChatList::class.java, ChatList())
+
+ fun getSavedChats(): List = savedChats.orEmpty().map { it }
+
+ @Synchronized
+ fun saveChats(list: List) {
+ savedChats = ChatList(list.toList())
+ }
+
+ @Synchronized
+ fun addChat(chatItemDto: ChatItemDto) {
+ val list = savedChats?.toMutableList() ?: mutableListOf()
+ list.add(chatItemDto)
+ saveChats(list.toList())
+ }
+
+ fun saveMessage(chatItemDto: ChatItemDto?, messageItemDto: ChatMessageItemDto) {
+ val list = savedChats?.toMutableList() ?: mutableListOf()
+ val index = list.indexOfFirst { it.uuid == chatItemDto?.uuid }
+ if (index != -1) {
+ val chatItem = list[index]
+ val messages = chatItem.messages.toMutableList()
+ messages.add(messageItemDto)
+ list[index] = ChatItemDto(chatItem.uuid, messages.toList(), chatItem.walletAddress)
+ saveChats(list.toList())
+ }
+ }
+
+ fun clear() {
+ savedChats = null
+ }
+
+ companion object {
+ const val KEY_SAVED_CHATS = "KEY_SAVED_CHATS"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatsRepository.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatsRepository.kt
new file mode 100644
index 000000000..e0e5748e9
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/chat_list/data/ChatsRepository.kt
@@ -0,0 +1,124 @@
+package com.tari.android.wallet.ui.fragment.chat_list.data
+
+import androidx.lifecycle.MutableLiveData
+import com.tari.android.wallet.extension.addTo
+import com.tari.android.wallet.model.TariWalletAddress
+import com.tari.android.wallet.ui.common.CommonViewModel
+import com.tari.android.wallet.util.TariBuild
+import java.util.UUID
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ChatsRepository @Inject constructor(private val chatsPrefRepository: ChatsPrefRepository) : CommonViewModel() {
+
+ val list = MutableLiveData>()
+
+ init {
+ component.inject(this)
+
+ chatsPrefRepository.updateNotifier.subscribe {
+ updateList()
+ }.addTo(compositeDisposable)
+ }
+
+ private fun updateList() {
+ val list = chatsPrefRepository.getSavedChats().toMutableList()
+
+ if (TariBuild.MOCKED && list.isEmpty()) {
+ val mockedList = mutableListOf(
+ ChatItemDto(
+ UUID.randomUUID().toString(),
+ listOf(
+ ChatMessageItemDto(
+ UUID.randomUUID().toString(),
+ "first",
+ "2 days ago",
+ false,
+ false
+ )
+ ),
+ TariBuild.mocked_wallet_address
+ ),
+ ChatItemDto(
+ UUID.randomUUID().toString(),
+ listOf(
+ ChatMessageItemDto(
+ UUID.randomUUID().toString(),
+ "second",
+ "2 days ago",
+ true,
+ false
+ )
+ ),
+ TariBuild.mocked_wallet_address
+ ),
+ ChatItemDto(
+ UUID.randomUUID().toString(),
+ listOf(
+ ChatMessageItemDto(
+ UUID.randomUUID().toString(),
+ "third",
+ "2 days ago",
+ false,
+ true
+ )
+ ),
+ TariBuild.mocked_wallet_address
+ ),
+ ChatItemDto(
+ UUID.randomUUID().toString(),
+ listOf(
+ ChatMessageItemDto(
+ UUID.randomUUID().toString(),
+ "fourth",
+ "2 days ago",
+ true,
+ true
+ )
+ ),
+ TariBuild.mocked_wallet_address
+ ),
+ ChatItemDto(
+ UUID.randomUUID().toString(),
+ listOf(
+ ChatMessageItemDto(
+ UUID.randomUUID().toString(),
+ "fifth",
+ "2 days ago",
+ false,
+ false
+ )
+ ),
+ TariBuild.mocked_wallet_address
+ ),
+ ChatItemDto(
+ UUID.randomUUID().toString(),
+ listOf(
+ ChatMessageItemDto(
+ UUID.randomUUID().toString(),
+ "sixth",
+ "2 days ago",
+ false,
+ false
+ )
+ ),
+ TariBuild.mocked_wallet_address
+ )
+ )
+
+ list.addAll(mockedList)
+ }
+
+ this.list.postValue(list)
+ }
+
+ fun getByUuid(uuid: String): ChatItemDto? = list.value?.find { it.uuid == uuid }
+
+ fun getByWalletAddress(walletAddress: TariWalletAddress): ChatItemDto? = list.value?.find { it.walletAddress == walletAddress }
+
+ fun addChat(chat: ChatItemDto) = chatsPrefRepository.addChat(chat)
+
+ fun addMessage(walletAddress: TariWalletAddress, message: ChatMessageItemDto) =
+ chatsPrefRepository.saveMessage(getByWalletAddress(walletAddress), message)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/AddContactFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/AddContactFragment.kt
index 93be17f81..89c80ee7c 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/AddContactFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/AddContactFragment.kt
@@ -15,7 +15,6 @@ class AddContactFragment : ContactSelectionFragment() {
ui.toolbar.ui.toolbarTitle.text = string(R.string.contact_book_add_contact_title)
ui.addFirstNameInput.visible()
- ui.addSurnameInput.visible()
viewModel.additionalFilter = { it.contact.getFFIDto() != null && it.contact.contact.getAlias().isEmpty() }
}
@@ -24,8 +23,10 @@ class AddContactFragment : ContactSelectionFragment() {
super.goToNext()
val user = viewModel.getUserDto()
- val firstName = ui.addFirstNameInput.ui.editText.text.toString()
- val surname = ui.addSurnameInput.ui.editText.text.toString()
+ val fullName = ui.addFirstNameInput.ui.editText.text.toString()
+ val split = fullName.split(" ")
+ val firstName = split.getOrNull(1).orEmpty().trim()
+ val surname = split.getOrNull(0).orEmpty().trim()
viewModel.contactsRepository.updateContactInfo(user, firstName, surname, "")
viewModel.navigation.postValue(Navigation.ContactBookNavigation.BackToContactBook())
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/SelectUserContactFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/SelectUserContactFragment.kt
index bd98f7001..c449d5806 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/SelectUserContactFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/add/SelectUserContactFragment.kt
@@ -27,7 +27,6 @@ class SelectUserContactFragment : ContactSelectionFragment() {
ui.toolbar.ui.toolbarTitle.text = string(R.string.transaction_send_to)
ui.addFirstNameInput.gone()
- ui.addSurnameInput.gone()
viewModel.isContactlessPayment.postValue(true)
viewModel.additionalFilter = { it.contact.getFFIDto() != null }
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/contactSelection/ContactSelectionFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/contactSelection/ContactSelectionFragment.kt
index ec4a32f87..9d94f06d7 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/contactSelection/ContactSelectionFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/contactSelection/ContactSelectionFragment.kt
@@ -113,8 +113,7 @@ open class ContactSelectionFragment : CommonFragment
+ val response = yatAdapter.searchTariYats(query)
+ response?.result?.entries?.firstOrNull()?.let { response ->
walletService.getWalletAddressFromHexString(response.value.address)?.let { pubKey ->
val yatUser = YatDto(query)
foundYatUser.postValue(Optional.ofNullable(yatUser))
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/data/ContactsRepository.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/data/ContactsRepository.kt
index ccaf7f0a3..dfb5b830d 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/data/ContactsRepository.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/data/ContactsRepository.kt
@@ -188,7 +188,8 @@ class ContactsRepository @Inject constructor(
private fun contactExists(contact: ContactDto): Boolean = this.publishSubject.value!!.any { it.uuid == contact.uuid }
- private fun contactExistsByWalletAddress(contact: ContactDto): Boolean = this.publishSubject.value!!.any { it.contact.extractWalletAddress() == contact.contact.extractWalletAddress() }
+ private fun contactExistsByWalletAddress(contact: ContactDto): Boolean =
+ this.publishSubject.value!!.any { it.contact.extractWalletAddress() == contact.contact.extractWalletAddress() }
@Synchronized
private fun withListUpdate(silently: Boolean = false, updateAction: (list: MutableList) -> Unit) {
@@ -235,11 +236,8 @@ class ContactsRepository @Inject constructor(
fun getContactForTx(tx: Tx): ContactDto = getContactByAddress(tx.tariContact.walletAddress)
fun getContactByAddress(address: TariWalletAddress): ContactDto =
- this@ContactsRepository.publishSubject.value!!.firstOrNull { it.getFFIDto()?.walletAddress == address } ?: ContactDto(
- FFIContactDto(
- address
- )
- )
+ this@ContactsRepository.publishSubject.value!!.firstOrNull { it.getFFIDto()?.walletAddress == address }
+ ?: ContactDto(FFIContactDto(address))
private fun subscribeToActions() {
EventBus.subscribe(this) { updateRecentUsedTime(it.tx.tariContact) }
@@ -315,12 +313,13 @@ class ContactsRepository @Inject constructor(
private fun onFFIContactAddedOrUpdated(contact: TariWalletAddress, alias: String, isFavorite: Boolean) {
if (ffiContactExist(contact)) {
- withFFIContact(contact) {
- it.getFFIDto()?.let { ffiContactDto ->
- ffiContactDto.setAlias(alias)
- ffiContactDto.isFavorite = isFavorite
- }
- }
+ //turn off updated because of name erasing
+// withFFIContact(contact) {
+// it.getFFIDto()?.let { ffiContactDto ->
+// ffiContactDto.setAlias(alias)
+// ffiContactDto.isFavorite = isFavorite
+// }
+// }
} else {
withListUpdate {
it.add(ContactDto(FFIContactDto(contact, alias, isFavorite)))
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/details/ContactDetailsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/details/ContactDetailsViewModel.kt
index 4677d92fb..1a45fbabf 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/details/ContactDetailsViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/details/ContactDetailsViewModel.kt
@@ -10,7 +10,6 @@ import com.tari.android.wallet.R.string.common_close
import com.tari.android.wallet.R.string.common_confirm
import com.tari.android.wallet.R.string.contact_book_add_contact_done_button
import com.tari.android.wallet.R.string.contact_book_add_contact_first_name_hint
-import com.tari.android.wallet.R.string.contact_book_add_contact_surname_hint
import com.tari.android.wallet.R.string.contact_book_add_contact_yat_hint
import com.tari.android.wallet.R.string.contact_book_contacts_book_unlink_message_firstLine
import com.tari.android.wallet.R.string.contact_book_contacts_book_unlink_message_secondLine
@@ -204,16 +203,13 @@ class ContactDetailsViewModel : CommonViewModel() {
fun onEditClick() {
val contact = contact.value!!
- val name = contact.contact.firstName
- val surname = contact.contact.surname
+ val name = (contact.contact.firstName + " " + contact.contact.surname).trim()
val phoneDto = contact.getPhoneDto()
val yatDto = contact.getYatDto()
var saveAction: () -> Boolean = { false }
- val nameModule = InputModule(name, resourceManager.getString(contact_book_add_contact_first_name_hint), true, false) { saveAction.invoke() }
- val surnameModule =
- InputModule(surname, resourceManager.getString(contact_book_add_contact_surname_hint), false, phoneDto == null) { saveAction.invoke() }
+ val nameModule = InputModule(name, resourceManager.getString(contact_book_add_contact_first_name_hint), true, true) { saveAction.invoke() }
val yatModule = phoneDto?.let {
YatInputModule(this::yatSearchAction, yatDto?.yat.orEmpty(), resourceManager.getString(contact_book_add_contact_yat_hint), false, true) {
saveAction.invoke()
@@ -225,11 +221,11 @@ class ContactDetailsViewModel : CommonViewModel() {
rightButtonTitle = resourceManager.getString(contact_book_add_contact_done_button)
) { saveAction.invoke() }
- val moduleList = mutableListOf(headModule, nameModule, surnameModule)
+ val moduleList = mutableListOf(headModule, nameModule)
yatModule?.let { moduleList.add(it) }
saveAction = {
- saveDetails(nameModule.value, surnameModule.value, yatModule?.value ?: "")
+ saveDetails(nameModule.value,yatModule?.value ?: "")
true
}
@@ -252,7 +248,10 @@ class ContactDetailsViewModel : CommonViewModel() {
return searchingJob?.await() != null
}
- private fun saveDetails(name: String, surname: String = "", yat: String = "") {
+ private fun saveDetails(newName: String, yat: String = "") {
+ val split = newName.split(" ")
+ val name = split.getOrNull(0).orEmpty().trim()
+ val surname = split.getOrNull(1).orEmpty().trim()
val contact = contact.value!!
updatingJob = null
this.contact.value = contactsRepository.updateContactInfo(contact, name, surname, yat)
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/ContactBookFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/ContactBookFragment.kt
index 9aef1940a..6a2724792 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/ContactBookFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/ContactBookFragment.kt
@@ -71,6 +71,7 @@ class ContactBookFragment : CommonFragment doShareViaQrCode(deeplink)
ShareType.LINK -> doShareViaLink(deeplink)
- ShareType.NFC -> doShareViaNFC()
ShareType.BLE -> doShareViaBLE()
}
}
@@ -150,23 +141,6 @@ class ShareViewModel : CommonViewModel() {
showShareSuccessDialog()
}
- private fun doShareViaNFC() {
- if (!tariNFCAdapter.isNFCAvailable()) {
- tariNFCAdapter.showNFCSettings()
- return
- }
- val args = ModularDialogArgs(
- DialogArgs(canceledOnTouchOutside = false, cancelable = false) { tariNFCAdapter.stopSharing() }, listOf(
- IconModule(R.drawable.vector_sharing_via_nfc),
- HeadModule(resourceManager.getString(R.string.share_via_nfc_title)),
- BodyModule(resourceManager.getString(R.string.share_via_nfc_message)),
- ButtonModule(resourceManager.getString(R.string.common_close), ButtonStyle.Close)
- )
- )
- modularDialog.postValue(args)
- tariNFCAdapter.startSharing(shareInfo.value.orEmpty())
- }
-
private fun doShareViaBLE() {
permissionManager.runWithPermission(tariBluetoothServer.bluetoothPermissions) {
startBLESharing()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/action_menu/ActionMenuView.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/action_menu/ActionMenuView.kt
index 02c2e8dff..d8374d2dc 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/action_menu/ActionMenuView.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/action_menu/ActionMenuView.kt
@@ -78,6 +78,7 @@ class ActionMenuView : CommonView {
this.layoutParams = FrameLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
changeSideButton.setOnClickListener { changeSide() }
this.closeButton.setOnClickListener { close() }
+ close()
gone()
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/share/ShareType.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/share/ShareType.kt
index 8ac5a578a..542f19f73 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/share/ShareType.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/root/share/ShareType.kt
@@ -3,6 +3,5 @@ package com.tari.android.wallet.ui.fragment.contact_book.root.share
enum class ShareType {
QR_CODE,
LINK,
- NFC,
BLE
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/transactionHistory/TransactionHistoryFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/transactionHistory/TransactionHistoryFragment.kt
index fb7406b01..b821c67fa 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/transactionHistory/TransactionHistoryFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/contact_book/transactionHistory/TransactionHistoryFragment.kt
@@ -55,6 +55,7 @@ class TransactionHistoryFragment : CommonFragment()
var list = MediatorLiveData>()
@@ -21,20 +27,28 @@ class TransactionHistoryViewModel : CommonViewModel() {
init {
component.inject(this)
+ list.addSource(contactRepository.publishSubject.toFlowable(BackpressureStrategy.LATEST).toLiveData()) {
+ updateList()
+ }
+
list.addSource(selectedContact) { updateList() }
- list.addSource(transactionRepository.debouncedList) { updateList() }
+ list.addSource(transactionRepository.list) { updateList() }
}
private fun updateList() {
- val filtered = transactionRepository.list.value?.filter {
+ val contact = selectedContact.value ?: return
+ val actualContact = contactRepository.getByUuid(contact.uuid)
+ if (contact != actualContact) selectedContact.postValue(actualContact)
+
+ val filtered: MutableList = transactionRepository.list.value?.filter {
if (it is TransactionItem) {
it.tx.tariContact.walletAddress == selectedContact.value?.contact?.extractWalletAddress()
} else {
false
}
- }
- list.postValue(filtered.orEmpty().toMutableList())
+ }.orEmpty().map { (it as TransactionItem).copy(contact = actualContact) }.toMutableList()
+ list.postValue(filtered)
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt
index e8effbe6a..df2e5a3f1 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeActivity.kt
@@ -34,9 +34,11 @@ package com.tari.android.wallet.ui.fragment.home
import android.Manifest.permission.POST_NOTIFICATIONS
import android.content.Intent
+import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.widget.ImageView
+import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
@@ -49,6 +51,7 @@ import com.tari.android.wallet.application.deeplinks.DeeplinkHandler
import com.tari.android.wallet.application.deeplinks.DeeplinkViewModel
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.network.NetworkRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.data.sharedPrefs.tariSettings.TariSettingsSharedRepository
import com.tari.android.wallet.databinding.ActivityHomeBinding
import com.tari.android.wallet.di.DiContainer.appComponent
@@ -70,20 +73,24 @@ import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule
import com.tari.android.wallet.ui.extension.parcelable
import com.tari.android.wallet.ui.extension.setVisible
import com.tari.android.wallet.ui.extension.string
+import com.tari.android.wallet.ui.fragment.auth.AuthActivity
+import com.tari.android.wallet.ui.fragment.chat_list.ChatListFragment
import com.tari.android.wallet.ui.fragment.contact_book.root.ContactBookFragment
import com.tari.android.wallet.ui.fragment.contact_book.root.action_menu.ContactBookActionMenuViewModel
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
+import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.INDEX_CHAT
import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.INDEX_CONTACT_BOOK
import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.INDEX_HOME
import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.INDEX_SETTINGS
-import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.INDEX_STORE
import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.NO_SMOOTH_SCROLL
import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowActivity
import com.tari.android.wallet.ui.fragment.settings.allSettings.AllSettingsFragment
+import com.tari.android.wallet.ui.fragment.settings.themeSelector.TariTheme
import com.tari.android.wallet.ui.fragment.splash.SplashActivity
import com.tari.android.wallet.ui.fragment.store.StoreFragment
import com.tari.android.wallet.ui.fragment.tx.HomeFragment
import com.tari.android.wallet.util.Constants
+import com.tari.android.wallet.util.TariBuild
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -95,6 +102,9 @@ class HomeActivity : CommonActivity() {
@Inject
lateinit var sharedPrefsRepository: SharedPrefsRepository
+ @Inject
+ lateinit var securityPrefRepository: SecurityPrefRepository
+
@Inject
lateinit var walletServiceLauncher: WalletServiceLauncher
@@ -119,6 +129,23 @@ class HomeActivity : CommonActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ appComponent.inject(this)
+
+ onBackPressedDispatcher.addCallback {
+ if (ui.actionMenuView.onBackPressed()) {
+ return@addCallback
+ }
+ if (supportFragmentManager.backStackEntryCount > 0) {
+ supportFragmentManager.popBackStack()
+ } else {
+ if (ui.viewPager.currentItem == INDEX_HOME) {
+ finish()
+ } else {
+ ui.viewPager.setCurrentItem(INDEX_HOME, NO_SMOOTH_SCROLL)
+ enableNavigationView(ui.homeImageView)
+ }
+ }
+ }
instance = WeakReference(this)
@@ -131,16 +158,14 @@ class HomeActivity : CommonActivity() {
subscribeToCommon(viewModel.shareViewModel.tariBluetoothClient)
subscribeToCommon(viewModel.shareViewModel.deeplinkViewModel)
subscribeToCommon(actionMenuViewModel)
- viewModel.nfcAdapter.context = this
viewModel.shareViewModel.tariBluetoothServer.init(this)
viewModel.shareViewModel.tariBluetoothClient.init(this)
setContainerId(R.id.nav_container)
-
overridePendingTransition(0, 0)
- appComponent.inject(this)
- if (!sharedPrefsRepository.isAuthenticated) {
+
+ if (!securityPrefRepository.isAuthenticated) {
val intent = Intent(this, SplashActivity::class.java)
.apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
this.intent?.data?.let(intent::setData)
@@ -149,6 +174,20 @@ class HomeActivity : CommonActivity() {
return
}
ui = ActivityHomeBinding.inflate(layoutInflater).also { setContentView(it.root) }
+
+ val buttonBg = when(tariSettingsRepository.currentTheme) {
+ TariTheme.AppBased -> {
+ when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
+ Configuration.UI_MODE_NIGHT_YES -> R.drawable.vector_disable_able_gradient_button_bg_external_dark
+ else -> R.drawable.vector_disable_able_gradient_button_bg_external
+ }
+ }
+ null,
+ TariTheme.Light -> R.drawable.vector_disable_able_gradient_button_bg_external
+ else -> R.drawable.vector_disable_able_gradient_button_bg_external_dark
+ }
+ ui.sendButtonExternalContainer.setBackgroundResource(buttonBg)
+
if (savedInstanceState == null) {
enableNavigationView(ui.homeImageView)
viewModel.doOnConnected {
@@ -178,12 +217,9 @@ class HomeActivity : CommonActivity() {
override fun onResume() {
super.onResume()
- viewModel.nfcAdapter.enableForegroundDispatch(this)
- }
-
- override fun onPause() {
- super.onPause()
- viewModel.nfcAdapter.disableForegroundDispatch(this)
+ if (!viewModel.securityPrefRepository.isAuthenticated) {
+ launch(AuthActivity::class.java)
+ }
}
private fun subscribeUI() = with(viewModel) {
@@ -195,6 +231,7 @@ class HomeActivity : CommonActivity() {
}
}
+ @Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
viewModel.shareViewModel.tariBluetoothServer.handleActivityResult(requestCode, resultCode, data)
@@ -204,8 +241,6 @@ class HomeActivity : CommonActivity() {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
- viewModel.nfcAdapter.onNewIntent(intent)
-
// onNewIntent might get called before onCreate, so we anticipate that here
checkScreensDeeplink(intent)
if (viewModel.serviceConnection.currentState.status == ServiceConnectionStatus.CONNECTED) {
@@ -220,22 +255,6 @@ class HomeActivity : CommonActivity() {
outState.putInt(KEY_PAGE, ui.viewPager.currentItem)
}
- override fun onBackPressed() {
- if (ui.actionMenuView.onBackPressed()) {
- return
- }
- if (supportFragmentManager.backStackEntryCount > 0) {
- super.onBackPressed()
- } else {
- if (ui.viewPager.currentItem == INDEX_HOME) {
- super.onBackPressed()
- } else {
- ui.viewPager.setCurrentItem(INDEX_HOME, NO_SMOOTH_SCROLL)
- enableNavigationView(ui.homeImageView)
- }
- }
- }
-
fun setBottomBarVisibility(isVisible: Boolean) {
val postDelay = if (!isVisible) 0 else Constants.UI.shortDurationMs
ui.bottomNavigationView.postDelayed({
@@ -251,20 +270,23 @@ class HomeActivity : CommonActivity() {
private fun setupBottomNavigation() {
enableNavigationView(ui.homeImageView)
- ui.viewPager.adapter = HomeAdapter(supportFragmentManager, this.lifecycle)
+ ui.viewPager.adapter = if (TariBuild.isChat) HomeChatAdapter(supportFragmentManager, this.lifecycle)
+ else HomeStoreAdapter(supportFragmentManager, this.lifecycle)
ui.viewPager.isUserInputEnabled = false
ui.viewPager.offscreenPageLimit = 3
ui.homeView.setOnClickListener {
ui.viewPager.setCurrentItem(INDEX_HOME, NO_SMOOTH_SCROLL)
enableNavigationView(ui.homeImageView)
}
+ ui.storeImageView.setImageResource(if (TariBuild.isChat) R.drawable.vector_home_book else R.drawable.vector_ttl_store_icon)
ui.storeView.setOnClickListener {
- ui.viewPager.setCurrentItem(INDEX_STORE, NO_SMOOTH_SCROLL)
+ ui.viewPager.setCurrentItem(INDEX_CONTACT_BOOK, NO_SMOOTH_SCROLL)
enableNavigationView(ui.storeImageView)
}
- ui.walletInfoView.setOnClickListener {
- ui.viewPager.setCurrentItem(INDEX_CONTACT_BOOK, NO_SMOOTH_SCROLL)
- enableNavigationView(ui.walletInfoImageView)
+ ui.chatImageView.setImageResource(if (TariBuild.isChat) R.drawable.vector_home_chat else R.drawable.vector_home_book)
+ ui.chatView.setOnClickListener {
+ ui.viewPager.setCurrentItem(INDEX_CHAT, NO_SMOOTH_SCROLL)
+ enableNavigationView(ui.chatImageView)
}
ui.settingsView.setOnClickListener {
ui.viewPager.setCurrentItem(INDEX_SETTINGS, NO_SMOOTH_SCROLL)
@@ -275,8 +297,8 @@ class HomeActivity : CommonActivity() {
private fun enableNavigationView(index: Int) {
val view: ImageView = when (index) {
INDEX_HOME -> ui.homeImageView
- INDEX_STORE -> ui.storeImageView
- INDEX_CONTACT_BOOK -> ui.walletInfoImageView
+ INDEX_CHAT -> ui.storeImageView
+ INDEX_CONTACT_BOOK -> ui.chatImageView
INDEX_SETTINGS -> ui.settingsImageView
else -> error("Unexpected index: $index")
}
@@ -284,7 +306,7 @@ class HomeActivity : CommonActivity() {
}
private fun enableNavigationView(view: ImageView) {
- arrayOf(ui.homeImageView, ui.storeImageView, ui.walletInfoImageView, ui.settingsImageView).forEach { it.clearColorFilter() }
+ arrayOf(ui.homeImageView, ui.storeImageView, ui.chatImageView, ui.settingsImageView).forEach { it.clearColorFilter() }
view.setColorFilter(viewModel.paletteManager.getPurpleBrand(this))
}
@@ -355,7 +377,7 @@ class HomeActivity : CommonActivity() {
fun willNotifyAboutNewTx(): Boolean = ui.viewPager.currentItem == INDEX_HOME
private fun processIntentDeepLink(intent: Intent) {
- deeplinkViewModel.tryToHandle(intent.data?.toString().orEmpty())
+ deeplinkViewModel.tryToHandle(intent.data?.toString().orEmpty(), false)
}
override fun onDestroy() {
@@ -364,11 +386,24 @@ class HomeActivity : CommonActivity() {
viewModelStore.clear()
}
- class HomeAdapter(fm: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle) {
+ class HomeStoreAdapter(fm: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle) {
+
+ override fun createFragment(position: Int): Fragment = when (position) {
+ INDEX_HOME -> HomeFragment()
+ INDEX_CHAT -> ContactBookFragment()
+ INDEX_CONTACT_BOOK -> StoreFragment.newInstance()
+ INDEX_SETTINGS -> AllSettingsFragment.newInstance()
+ else -> error("Unexpected position: $position")
+ }
+
+ override fun getItemCount(): Int = 4
+ }
+
+ class HomeChatAdapter(fm: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle) {
override fun createFragment(position: Int): Fragment = when (position) {
INDEX_HOME -> HomeFragment()
- INDEX_STORE -> StoreFragment.newInstance()
+ INDEX_CHAT -> ChatListFragment()
INDEX_CONTACT_BOOK -> ContactBookFragment()
INDEX_SETTINGS -> AllSettingsFragment.newInstance()
else -> error("Unexpected position: $position")
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt
index ab4a5af01..7f2a249b6 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/HomeViewModel.kt
@@ -1,6 +1,5 @@
package com.tari.android.wallet.ui.fragment.home
-import com.tari.android.wallet.infrastructure.nfc.TariNFCAdapter
import com.tari.android.wallet.ui.common.CommonViewModel
import com.tari.android.wallet.ui.fragment.contact_book.data.ContactsRepository
import com.tari.android.wallet.ui.fragment.contact_book.root.ShareViewModel
@@ -15,9 +14,6 @@ class HomeViewModel: CommonViewModel() {
@Inject
lateinit var contactsRepository: ContactsRepository
- @Inject
- lateinit var nfcAdapter: TariNFCAdapter
-
val shareViewModel = ShareViewModel()
init {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/homeTransactionHistory/HomeTransactionHistoryFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/homeTransactionHistory/HomeTransactionHistoryFragment.kt
index 19ae04bd9..8d59a222b 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/homeTransactionHistory/HomeTransactionHistoryFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/homeTransactionHistory/HomeTransactionHistoryFragment.kt
@@ -39,7 +39,10 @@ class HomeTransactionHistoryFragment : CommonFragment>()
val searchText = MutableLiveData("")
@@ -25,6 +31,10 @@ class HomeTransactionHistoryViewModel : CommonViewModel() {
init {
component.inject(this)
+ list.addSource(contactsRepository.publishSubject.toFlowable(BackpressureStrategy.LATEST).toLiveData()) {
+ updateList()
+ }
+
list.addSource(transactionRepository.list) { updateList() }
list.addSource(searchText) { updateList() }
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/Navigation.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/Navigation.kt
index 372736f82..2b428a343 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/Navigation.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/Navigation.kt
@@ -2,16 +2,22 @@ package com.tari.android.wallet.ui.fragment.home.navigation
import com.tari.android.wallet.application.deeplinks.DeepLink
import com.tari.android.wallet.model.MicroTari
+import com.tari.android.wallet.model.TariWalletAddress
import com.tari.android.wallet.model.Tx
import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.ContactDto
import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.YatDto
+import com.tari.android.wallet.ui.fragment.pinCode.PinCodeScreenBehavior
import com.tari.android.wallet.ui.fragment.send.common.TransactionData
sealed class Navigation {
- sealed class CustomBridgeNavigation : Navigation() {
- object ScanQrCode : CustomBridgeNavigation()
+ class EnterPinCodeNavigation(val behavior: PinCodeScreenBehavior, val stashedPin: String? = null): Navigation()
+
+ class ChangeBiometrics(): Navigation()
+ class FeatureAuth(): Navigation()
+
+ sealed class CustomBridgeNavigation : Navigation() {
object UploadQrCode : CustomBridgeNavigation()
}
@@ -46,7 +52,7 @@ sealed class Navigation {
class ToTxDetails(val tx: Tx) : TxListNavigation()
- object ToTTLStore : TxListNavigation()
+ object ToChat : TxListNavigation()
object ToAllSettings : TxListNavigation()
@@ -60,6 +66,12 @@ sealed class Navigation {
class ToTransfer : TxListNavigation()
}
+ sealed class ChatNavigation : Navigation() {
+ object ToAddChat : ChatNavigation()
+
+ class ToChat(val walletAddress: TariWalletAddress, val isNew: Boolean) : ChatNavigation()
+ }
+
sealed class AddAmountNavigation : Navigation() {
object OnAmountExceedsActualAvailableBalance : AddAmountNavigation()
@@ -76,6 +88,7 @@ sealed class Navigation {
sealed class AllSettingsNavigation : Navigation() {
object ToMyProfile : AllSettingsNavigation()
object ToBugReporting : AllSettingsNavigation()
+ object ToDataCollection : AllSettingsNavigation()
object ToAbout : AllSettingsNavigation()
object ToBackupSettings : AllSettingsNavigation()
object ToDeleteWallet : AllSettingsNavigation()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/TariNavigator.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/TariNavigator.kt
index 149683084..9c265bf15 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/TariNavigator.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/home/navigation/TariNavigator.kt
@@ -31,7 +31,10 @@ import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonStyle
import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule
import com.tari.android.wallet.ui.extension.showInternetConnectionErrorDialog
import com.tari.android.wallet.ui.extension.string
-import com.tari.android.wallet.ui.fragment.auth.AuthActivity
+import com.tari.android.wallet.ui.fragment.auth.FeatureAuthFragment
+import com.tari.android.wallet.ui.fragment.biometrics.ChangeBiometricsFragment
+import com.tari.android.wallet.ui.fragment.chat_list.addChat.AddChatFragment
+import com.tari.android.wallet.ui.fragment.chat_list.chat.ChatFragment
import com.tari.android.wallet.ui.fragment.contact_book.add.AddContactFragment
import com.tari.android.wallet.ui.fragment.contact_book.add.SelectUserContactFragment
import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.ContactDto
@@ -45,9 +48,9 @@ import com.tari.android.wallet.ui.fragment.home.homeTransactionHistory.HomeTrans
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation.AllSettingsNavigation
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation.ContactBookNavigation
import com.tari.android.wallet.ui.fragment.onboarding.activity.OnboardingFlowActivity
+import com.tari.android.wallet.ui.fragment.onboarding.localAuth.LocalAuthFragment
+import com.tari.android.wallet.ui.fragment.pinCode.EnterPinCodeFragment
import com.tari.android.wallet.ui.fragment.profile.WalletInfoFragment
-import com.tari.android.wallet.ui.fragment.qr.QRScannerActivity
-import com.tari.android.wallet.ui.fragment.qr.QrScannerSource
import com.tari.android.wallet.ui.fragment.restore.enterRestorationPassword.EnterRestorationPasswordFragment
import com.tari.android.wallet.ui.fragment.restore.inputSeedWords.InputSeedWordsFragment
import com.tari.android.wallet.ui.fragment.restore.walletRestoringFromSeedWords.WalletRestoringFromSeedWordsFragment
@@ -58,6 +61,7 @@ import com.tari.android.wallet.ui.fragment.send.finalize.FinalizeSendTxFragment
import com.tari.android.wallet.ui.fragment.send.finalize.TxFailureReason
import com.tari.android.wallet.ui.fragment.send.requestTari.RequestTariFragment
import com.tari.android.wallet.ui.fragment.send.transfer.TransferFragment
+import com.tari.android.wallet.ui.fragment.settings.allSettings.AllSettingsFragment
import com.tari.android.wallet.ui.fragment.settings.allSettings.about.TariAboutFragment
import com.tari.android.wallet.ui.fragment.settings.backgroundService.BackgroundServiceSettingsFragment
import com.tari.android.wallet.ui.fragment.settings.backup.backupOnboarding.BackupOnboardingFlowFragment
@@ -69,6 +73,7 @@ import com.tari.android.wallet.ui.fragment.settings.backup.writeDownSeedWords.Wr
import com.tari.android.wallet.ui.fragment.settings.baseNodeConfig.addBaseNode.AddCustomBaseNodeFragment
import com.tari.android.wallet.ui.fragment.settings.baseNodeConfig.changeBaseNode.ChangeBaseNodeFragment
import com.tari.android.wallet.ui.fragment.settings.bluetoothSettings.BluetoothSettingsFragment
+import com.tari.android.wallet.ui.fragment.settings.dataCollection.DataCollectionFragment
import com.tari.android.wallet.ui.fragment.settings.deleteWallet.DeleteWalletFragment
import com.tari.android.wallet.ui.fragment.settings.logs.activity.DebugActivity
import com.tari.android.wallet.ui.fragment.settings.logs.activity.DebugNavigation
@@ -91,6 +96,9 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
fun navigate(navigation: Navigation) {
when (navigation) {
+ is Navigation.EnterPinCodeNavigation -> addFragment(EnterPinCodeFragment.newInstance(navigation.behavior, navigation.stashedPin))
+ is Navigation.ChangeBiometrics -> addFragment(ChangeBiometricsFragment())
+ is Navigation.FeatureAuth -> addFragment(FeatureAuthFragment())
is ContactBookNavigation.ToAddContact -> toAddContact()
is ContactBookNavigation.ToContactDetails -> toContactDetails(navigation.contact)
is ContactBookNavigation.ToRequestTari -> toRequestTariFromContact(navigation.contact)
@@ -114,6 +122,7 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
AllSettingsNavigation.ToDeleteWallet -> toDeleteWallet()
AllSettingsNavigation.ToNetworkSelection -> toNetworkSelection()
AllSettingsNavigation.ToTorBridges -> toTorBridges()
+ AllSettingsNavigation.ToDataCollection -> addFragment(DataCollectionFragment())
AllSettingsNavigation.ToThemeSelection -> toThemeSelection()
AllSettingsNavigation.ToRequestTari -> addFragment(RequestTariFragment.newInstance())
Navigation.EnterRestorationPasswordNavigation.OnRestore -> onRestoreCompleted()
@@ -128,7 +137,7 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
Navigation.AddAmountNavigation.OnAmountExceedsActualAvailableBalance -> onAmountExceedsActualAvailableBalance()
is Navigation.AddAmountNavigation.ContinueToAddNote -> continueToAddNote(navigation.transactionData)
is Navigation.AddAmountNavigation.ContinueToFinalizing -> continueToFinalizeSendTx(navigation.transactionData)
- Navigation.TxListNavigation.ToTTLStore -> toTTLStore()
+ Navigation.TxListNavigation.ToChat -> toChat()
is Navigation.TxListNavigation.ToTxDetails -> toTxDetails(navigation.tx, null)
is Navigation.TxListNavigation.ToSendTariToUser -> toSendTari(navigation.contact, navigation.amount)
is Navigation.TxListNavigation.ToSendWithDeeplink -> toSendWithDeeplink(navigation.sendDeeplink)
@@ -145,11 +154,16 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
Navigation.BackupSettingsNavigation.ToConfirmPassword -> toConfirmPassword()
Navigation.BackupSettingsNavigation.ToWalletBackupWithRecoveryPhrase -> toWalletBackupWithRecoveryPhrase()
Navigation.BackupSettingsNavigation.ToLearnMore -> toBackupOnboardingFlow()
- Navigation.CustomBridgeNavigation.ScanQrCode -> {
- QRScannerActivity.startScanner(activity, QrScannerSource.TorBridges)
+ Navigation.CustomBridgeNavigation.UploadQrCode -> Unit
+ is Navigation.ChatNavigation.ToChat -> {
+ if (navigation.isNew) {
+ onBackPressed()
+ }
+
+ addFragment(ChatFragment.newInstance(navigation.walletAddress))
}
- Navigation.CustomBridgeNavigation.UploadQrCode -> Unit
+ Navigation.ChatNavigation.ToAddChat -> addFragment(AddChatFragment())
else -> Unit
}
}
@@ -175,12 +189,14 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
fun onRestoreCompleted() {
// wallet restored, setup shared prefs accordingly
prefs.onboardingCompleted = true
- prefs.onboardingAuthSetupCompleted = true
+ prefs.onboardingStarted = true
+ prefs.onboardingAuthSetupStarted = true
+ prefs.onboardingAuthSetupCompleted = false
prefs.onboardingDisplayedAtHome = true
tariSettingsSharedRepository.isRestoredWallet = true
activity.finish()
- activity.startActivity(Intent(this.activity, AuthActivity::class.java).apply {
+ activity.startActivity(Intent(this.activity, OnboardingFlowActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
})
}
@@ -194,7 +210,7 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
}
})
- fun toTTLStore() = (activity as HomeActivity).ui.viewPager.setCurrentItem(INDEX_STORE, NO_SMOOTH_SCROLL)
+ fun toChat() = (activity as HomeActivity).ui.viewPager.setCurrentItem(INDEX_CHAT, NO_SMOOTH_SCROLL)
fun toAllSettings() = (activity as HomeActivity).ui.viewPager.setCurrentItem(INDEX_SETTINGS, NO_SMOOTH_SCROLL)
@@ -234,7 +250,7 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
fun toSendTari(user: ContactDto, amount: MicroTari?) = sendToUser(user, amount)
- fun toSendWithDeeplink(deeplink: DeepLink.Send) {
+ fun toSendWithDeeplink(deeplink: DeepLink.Send) {
popUpTo(HomeFragment::class.java.simpleName)
sendToUserByDeeplink(deeplink)
}
@@ -249,6 +265,16 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
fun backToContactBook() = popUpTo(ContactBookFragment::class.java.simpleName)
+ fun backToAllSettings() = popUpTo(AllSettingsFragment::class.java.simpleName)
+
+ fun backAfterAuth() {
+ if (activity is HomeActivity) {
+ popUpTo(AllSettingsFragment::class.java.simpleName)
+ } else {
+ popUpTo(LocalAuthFragment::class.java.simpleName)
+ }
+ }
+
fun toLinkContact(contact: ContactDto) = addFragment(ContactLinkFragment.createFragment(contact))
fun toContactTransactionHistory(contact: ContactDto) = addFragment(TransactionHistoryFragment.createFragment(contact))
@@ -371,7 +397,6 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
//popup fragment
private fun popUpTo(tag: String) = activity.popUpTo(tag)
-
companion object {
const val PARAMETER_NOTE = "note"
const val PARAMETER_AMOUNT = "amount"
@@ -379,8 +404,8 @@ class TariNavigator @Inject constructor(val prefs: SharedPrefsRepository, val ta
const val PARAMETER_CONTACT = "tari_contact_dto_args"
const val INDEX_HOME = 0
- const val INDEX_STORE = 1
- const val INDEX_CONTACT_BOOK = 2
+ const val INDEX_CONTACT_BOOK = 1
+ const val INDEX_CHAT = 2
const val INDEX_SETTINGS = 3
const val NO_SMOOTH_SCROLL = false
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt
index dbeb7b0e2..642f17ba5 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/activity/OnboardingFlowActivity.kt
@@ -34,6 +34,7 @@ package com.tari.android.wallet.ui.fragment.onboarding.activity
import android.content.Intent
import android.os.Bundle
+import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
@@ -82,6 +83,12 @@ class OnboardingFlowActivity : CommonActivity 1) {
+ supportFragmentManager.popBackStack()
+ }
+ }
+
val viewModel: OnboardingFlowViewModel by viewModels()
bindViewModel(viewModel)
@@ -113,20 +120,11 @@ class OnboardingFlowActivity : CommonActivity 1) {
- supportFragmentManager.popBackStack()
- }
- }
-
override fun continueToCreateWallet() {
sharedPrefsWrapper.onboardingStarted = true
supportFragmentManager.beginTransaction()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthFragment.kt
index 9da1dc029..ed63e4607 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthFragment.kt
@@ -39,40 +39,25 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.daasuu.ei.Ease
import com.daasuu.ei.EasingInterpolator
-import com.tari.android.wallet.R
-import com.tari.android.wallet.R.dimen.auth_button_bottom_margin
-import com.tari.android.wallet.R.string.auth_failed_desc
-import com.tari.android.wallet.R.string.auth_failed_title
-import com.tari.android.wallet.R.string.auth_not_available_or_canceled_desc
-import com.tari.android.wallet.R.string.auth_not_available_or_canceled_title
-import com.tari.android.wallet.R.string.auth_prompt_button_text
-import com.tari.android.wallet.R.string.auth_prompt_button_touch_id_text
-import com.tari.android.wallet.R.string.common_cancel
-import com.tari.android.wallet.R.string.common_ok
import com.tari.android.wallet.R.string.onboarding_auth_biometric_prompt
-import com.tari.android.wallet.R.string.onboarding_auth_device_lock_code_prompt
import com.tari.android.wallet.R.string.onboarding_auth_title
-import com.tari.android.wallet.R.string.proceed
import com.tari.android.wallet.application.WalletState
import com.tari.android.wallet.databinding.FragmentLocalAuthBinding
import com.tari.android.wallet.event.EventBus
import com.tari.android.wallet.extension.addTo
-import com.tari.android.wallet.extension.observeOnLoad
+import com.tari.android.wallet.extension.observe
import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationException
-import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationType
import com.tari.android.wallet.ui.common.CommonFragment
-import com.tari.android.wallet.ui.extension.animateClick
-import com.tari.android.wallet.ui.extension.dimenPx
import com.tari.android.wallet.ui.extension.doOnGlobalLayout
-import com.tari.android.wallet.ui.extension.invisible
+import com.tari.android.wallet.ui.extension.setOnThrottledClickListener
+import com.tari.android.wallet.ui.extension.setVisible
import com.tari.android.wallet.ui.extension.string
-import com.tari.android.wallet.ui.extension.temporarilyDisableClick
-import com.tari.android.wallet.ui.extension.visible
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
+import com.tari.android.wallet.ui.fragment.pinCode.PinCodeScreenBehavior
import com.tari.android.wallet.util.Constants.UI.Auth
import kotlinx.coroutines.launch
@@ -93,28 +78,23 @@ class LocalAuthFragment : CommonFragment
val alpha = valueAnimator.animatedValue as Float
ui.smallGemImageView.alpha = alpha
- ui.authTypeImageView.alpha = alpha
+ ui.authTypeBiometrics.alpha = alpha
+ ui.authTypePasscode.alpha = alpha
ui.authDescTextView.alpha = alpha
- ui.enableAuthButtonContainerView.alpha = alpha
}
startDelay = Auth.viewFadeAnimDelayMs
}
AnimatorSet().apply {
- playTogether(titleTextAnim, buttonContainerViewAnim, fadeInAnim)
+ playTogether(titleTextAnim, fadeInAnim)
interpolator = EasingInterpolator(Ease.QUINT_IN)
startDelay = Auth.localAuthAnimDurationMs
duration = Auth.localAuthAnimDurationMs
@@ -138,70 +118,26 @@ class LocalAuthFragment : CommonFragment
- // user has chosen to proceed without authentication
- viewModel.sharedPrefsWrapper.isAuthenticated = true
- dialog.cancel()
- authSuccess()
- }
- .setNegativeButton(string(common_cancel), null)
- .create().apply {
- setTitle(string(auth_not_available_or_canceled_title))
- show()
- }
- }
-
- private fun authSuccess() {
- // check if the wallet is ready & switch to wait mode if not & start listening
- ui.progressBarContainerView.visible()
- ui.enableAuthButton.invisible()
-
+ private fun proceedToMain() {
EventBus.walletState.publishSubject
.filter { it == WalletState.Running }
.subscribe {
- viewModel.sharedPrefsWrapper.isAuthenticated = true
- viewModel.sharedPrefsWrapper.onboardingAuthSetupCompleted = true
+ viewModel.securityPrefRepository.isAuthenticated = true
+ viewModel.sharedPrefsRepository.onboardingAuthSetupCompleted = true
viewModel.backupManager.backupNow()
+ viewModel.navigation.postValue(Navigation.EnterPinCodeNavigation(PinCodeScreenBehavior.CreateConfirm))
(requireActivity() as? LocalAuthListener)?.onAuthSuccess()
}.addTo(viewModel.compositeDisposable)
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthViewModel.kt
index d6181340b..378b7aea8 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/LocalAuthViewModel.kt
@@ -1,30 +1,43 @@
package com.tari.android.wallet.ui.fragment.onboarding.localAuth
-import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
+import com.tari.android.wallet.extension.addTo
import com.tari.android.wallet.infrastructure.backup.BackupManager
import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationService
-import com.tari.android.wallet.infrastructure.security.biometric.BiometricAuthenticationType
import com.tari.android.wallet.ui.common.CommonViewModel
import javax.inject.Inject
class LocalAuthViewModel : CommonViewModel() {
- @Inject
- lateinit var sharedPrefsWrapper: SharedPrefsRepository
-
@Inject
lateinit var authService: BiometricAuthenticationService
@Inject
lateinit var backupManager: BackupManager
- private val _authType = MutableLiveData()
- val authType: LiveData = _authType
+ val secureState = MutableLiveData(SecureState(true, false, false))
+
init {
component.inject(this)
- _authType.value = authService.authType
+ sharedPrefsRepository.onboardingAuthSetupStarted = true
+ updateState()
+
+ securityPrefRepository.updateNotifier.subscribe {
+ updateState()
+ }.addTo(compositeDisposable)
+ }
+
+ fun updateState() {
+ secureState.value = SecureState(
+ authService.isBiometricAuthAvailable,
+ securityPrefRepository.pinCode != null,
+ securityPrefRepository.biometricsAuth == true
+ )
+ }
+
+ fun securedWithBiometrics() {
+ securityPrefRepository.biometricsAuth = true
+ secureState.value = secureState.value!!.copy(biometricsSecured = true)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/SecureState.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/SecureState.kt
new file mode 100644
index 000000000..83aa00108
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/onboarding/localAuth/SecureState.kt
@@ -0,0 +1,3 @@
+package com.tari.android.wallet.ui.fragment.onboarding.localAuth
+
+data class SecureState(val biometricsAvailable: Boolean, val pinCodeSecured: Boolean, val biometricsSecured: Boolean)
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/EnterPinCodeFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/EnterPinCodeFragment.kt
new file mode 100644
index 000000000..14379bfc0
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/EnterPinCodeFragment.kt
@@ -0,0 +1,216 @@
+package com.tari.android.wallet.ui.fragment.pinCode
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import com.tari.android.wallet.R
+import com.tari.android.wallet.databinding.FragmentEnterPincodeBinding
+import com.tari.android.wallet.extension.addTo
+import com.tari.android.wallet.extension.observe
+import com.tari.android.wallet.ui.common.CommonFragment
+import com.tari.android.wallet.ui.extension.gone
+import com.tari.android.wallet.ui.extension.invisible
+import com.tari.android.wallet.ui.extension.setOnThrottledClickListener
+import com.tari.android.wallet.ui.extension.setVisible
+import com.tari.android.wallet.ui.extension.visible
+import com.tari.android.wallet.ui.fragment.auth.AuthActivity
+import com.tari.android.wallet.ui.fragment.auth.FeatureAuthFragment
+import io.reactivex.Observable
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import java.time.Duration
+import java.time.LocalDateTime
+import java.util.concurrent.TimeUnit
+
+class EnterPinCodeFragment : CommonFragment() {
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
+ FragmentEnterPincodeBinding.inflate(inflater, container, false).also { ui = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val viewModel: EnterPinCodeViewModel by viewModels()
+ bindViewModel(viewModel)
+
+ val behavior = arguments?.getInt(PIN_CODE_EXTRA_KEY)?.let { PinCodeScreenBehavior.values()[it] } ?: PinCodeScreenBehavior.CreateConfirm
+ val stashedPinCode = arguments?.getString(PIN_CODE_STASHED_KEY)
+ viewModel.init(behavior, stashedPinCode)
+
+ initUI()
+ ui.continueBtn.setOnThrottledClickListener { viewModel.doMainAction() }
+ observeUI()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ viewModel.currentNums.value = ""
+ }
+
+ private fun initUI() = with(ui.numpad) {
+ initNumpad()
+ biometricAuth.setOnClickListener {
+ (requireActivity() as? AuthActivity)?.showBiometricAuth()
+ requireActivity().supportFragmentManager.fragments.firstOrNull { it is FeatureAuthFragment }?.let {
+ (it as? FeatureAuthFragment)?.showBiometricAuth()
+ }
+ }
+ decimalPointButton.gone()
+ }
+
+ private fun observeUI() = with(viewModel) {
+ observe(behavior) {
+ val isVisible =
+ (it == PinCodeScreenBehavior.Auth || it == PinCodeScreenBehavior.FeatureAuth) && viewModel.securityPrefRepository.biometricsAuth == true
+ ui.numpad.biometricAuth.setVisible(isVisible)
+ if (isVisible) {
+ ui.numpad.decimalPointButton.gone()
+ } else {
+ ui.numpad.decimalPointButton.invisible()
+ }
+ }
+
+ observe(subtitleText) {
+ ui.subtitle.text = it
+ ui.toolbar.ui.toolbarTitle.text = it
+ }
+
+ observe(toolbarIsVisible) { ui.toolbar.setVisible(it) }
+
+ observe(buttonIsVisible) { ui.continueBtn.setVisible(it) }
+
+ observe(buttonTitle) { ui.continueBtn.text = it }
+
+ observe(currentNums) {
+ val length = it.length
+ ui.pinCode1Dot.setVisible(length > 0)
+ ui.pinCode2Dot.setVisible(length > 1)
+ ui.pinCode3Dot.setVisible(length > 2)
+ ui.pinCode4Dot.setVisible(length > 3)
+ ui.pinCode5Dot.setVisible(length > 4)
+ ui.pinCode6Dot.setVisible(length > 5)
+ ui.continueBtn.isEnabled = length >= 6
+ if (length < 6) {
+ viewModel.errorMessage.postValue("")
+ }
+ }
+
+ observe(errorMessage) {
+ setState(it.isNotEmpty())
+ ui.errorMessage.text = it
+ ui.errorMessage.setVisible(it.isNotEmpty())
+ }
+
+ observe(successfullyAuth) {
+ (requireActivity() as? AuthActivity)?.continueToHomeActivity()
+ requireActivity().supportFragmentManager.fragments.firstOrNull { it is FeatureAuthFragment }?.let {
+ (it as? FeatureAuthFragment)?.authSuccessfully()
+ }
+ }
+
+ observe(nextEnterTime) {
+ val nextEnterTime = viewModel.nextEnterTime.value
+ val now = LocalDateTime.now()
+ val isLater = now.isBefore(nextEnterTime)
+ setSecurityState(isLater)
+ ui.errorMessageCountdown.setVisible(isLater)
+ ui.errorMessage.setVisible(!isLater)
+ startCountdown(nextEnterTime)
+ }
+ }
+
+ private fun startCountdown(dateTime: LocalDateTime?) {
+ if (dateTime != null && dateTime.isAfter(LocalDateTime.now())) {
+ updateText(Duration.between(LocalDateTime.now(), dateTime))
+ Observable.timer(1, TimeUnit.SECONDS)
+ .repeat()
+ .map { Duration.between(LocalDateTime.now(), dateTime) }
+ .takeWhile {
+ val shouldTake = LocalDateTime.now().isBefore(dateTime)
+ if (!shouldTake) {
+ viewModel.nextEnterTime.postValue(LocalDateTime.now())
+ }
+ shouldTake
+ }
+ .subscribe { lifecycleScope.launch(Dispatchers.Main) { updateText(it) } }
+ .addTo(viewModel.compositeDisposable)
+ }
+ }
+
+ private fun updateText(duration: Duration) {
+ val seconds = duration.seconds
+ val minutes = seconds / 60
+ val hours = minutes / 60
+ var timeText = ""
+ if (hours > 0) {
+ timeText += "${hours}h "
+ }
+ if (minutes > 0) {
+ timeText += "${minutes % 60}m "
+ }
+ timeText += "${seconds % 60}s"
+ val errorText = if (!duration.isNegative) "Too many attempts. You should wait $timeText" else ""
+ ui.errorMessageCountdown.text = errorText
+ ui.errorMessageCountdown.visible()
+ ui.errorMessage.invisible()
+ }
+
+ private fun setSecurityState(isDisabled: Boolean) = with(ui) {
+ pinCodeContainer.setVisible(!isDisabled)
+ subtitle.setVisible(!isDisabled)
+ for (index in 0 until numpad.root.childCount) {
+ numpad.root.getChildAt(index).alpha = if (isDisabled) 0.5f else 1f
+ }
+ if (isDisabled) clearNumpad() else initNumpad()
+ numpad.biometricAuth.alpha = 1f
+ }
+
+ private fun setState(isError: Boolean) {
+ val backResource = if (isError) R.drawable.vector_pin_input_dot_error else R.drawable.vector_pin_input_dot_normal
+ val allPinCodeViews = listOf(ui.pinCode1Dot, ui.pinCode2Dot, ui.pinCode3Dot, ui.pinCode4Dot, ui.pinCode5Dot, ui.pinCode6Dot)
+ allPinCodeViews.forEach { it.setBackgroundResource(backResource) }
+ }
+
+ private fun initNumpad() = with(ui.numpad) {
+ pad0Button.setOnClickListener { viewModel.addNum("0") }
+ pad1Button.setOnClickListener { viewModel.addNum("1") }
+ pad2Button.setOnClickListener { viewModel.addNum("2") }
+ pad3Button.setOnClickListener { viewModel.addNum("3") }
+ pad4Button.setOnClickListener { viewModel.addNum("4") }
+ pad5Button.setOnClickListener { viewModel.addNum("5") }
+ pad6Button.setOnClickListener { viewModel.addNum("6") }
+ pad7Button.setOnClickListener { viewModel.addNum("7") }
+ pad8Button.setOnClickListener { viewModel.addNum("8") }
+ pad9Button.setOnClickListener { viewModel.addNum("9") }
+ deleteButton.setOnClickListener { viewModel.removeLast() }
+ }
+
+ private fun clearNumpad() = with(ui.numpad) {
+ pad0Button.setOnClickListener { }
+ pad1Button.setOnClickListener { }
+ pad2Button.setOnClickListener { }
+ pad3Button.setOnClickListener { }
+ pad4Button.setOnClickListener { }
+ pad5Button.setOnClickListener { }
+ pad6Button.setOnClickListener { }
+ pad7Button.setOnClickListener { }
+ pad8Button.setOnClickListener { }
+ pad9Button.setOnClickListener { }
+ deleteButton.setOnClickListener { }
+ }
+
+ companion object {
+ const val PIN_CODE_EXTRA_KEY = "pin_code_extra_key"
+ const val PIN_CODE_STASHED_KEY = "pin_code_stashed_key"
+
+ fun newInstance(behavior: PinCodeScreenBehavior, pinCodeStashed: String? = null) = EnterPinCodeFragment().apply {
+ arguments = Bundle().apply {
+ putInt(PIN_CODE_EXTRA_KEY, behavior.ordinal)
+ putString(PIN_CODE_STASHED_KEY, pinCodeStashed)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/EnterPinCodeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/EnterPinCodeViewModel.kt
new file mode 100644
index 000000000..d7f6b903b
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/EnterPinCodeViewModel.kt
@@ -0,0 +1,154 @@
+package com.tari.android.wallet.ui.fragment.pinCode
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.map
+import com.tari.android.wallet.R
+import com.tari.android.wallet.data.sharedPrefs.security.LoginAttemptDto
+import com.tari.android.wallet.extension.addTo
+import com.tari.android.wallet.ui.common.CommonViewModel
+import com.tari.android.wallet.ui.common.SingleLiveEvent
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
+import java.time.LocalDateTime
+import java.time.OffsetDateTime
+
+class EnterPinCodeViewModel : CommonViewModel() {
+
+ val behavior = MutableLiveData()
+
+ val stashedPin = MutableLiveData()
+
+ val subtitleText = behavior.map {
+ val id = when (it) {
+ PinCodeScreenBehavior.Create -> R.string.pin_code_subtitle_create
+ PinCodeScreenBehavior.CreateConfirm -> R.string.pin_code_subtitle_create_confirm
+ PinCodeScreenBehavior.ChangeNew -> R.string.pin_code_subtitle_change_new
+ PinCodeScreenBehavior.ChangeNewConfirm -> R.string.pin_code_subtitle_change_new_confirm
+ PinCodeScreenBehavior.Auth -> R.string.pin_code_subtitle_auth
+ PinCodeScreenBehavior.FeatureAuth -> R.string.pin_code_subtitle_feature_auth
+ else -> R.string.common_continue
+ }
+ resourceManager.getString(id)
+ }
+
+ val toolbarIsVisible = behavior.map {
+ it != PinCodeScreenBehavior.Auth && it != PinCodeScreenBehavior.FeatureAuth
+ }
+
+ val buttonIsVisible = behavior.map {
+ false
+ }
+
+ val currentNums = MutableLiveData("")
+
+ val errorMessage = MutableLiveData("")
+
+ val buttonTitle = behavior.map {
+ val id = when (it) {
+ PinCodeScreenBehavior.Create -> R.string.common_continue
+ PinCodeScreenBehavior.CreateConfirm -> R.string.common_confirm
+ PinCodeScreenBehavior.ChangeNew -> R.string.common_continue
+ PinCodeScreenBehavior.ChangeNewConfirm -> R.string.common_confirm
+ PinCodeScreenBehavior.Auth -> R.string.common_confirm
+ else -> R.string.common_continue
+ }
+ resourceManager.getString(id)
+ }
+
+ val successfullyAuth = SingleLiveEvent()
+
+ val nextEnterTime = MutableLiveData()
+
+ init {
+ component.inject(this)
+
+ doFraudLogic()
+ securityPrefRepository.updateNotifier.subscribe { doFraudLogic() }.addTo(compositeDisposable)
+ }
+
+ private fun doFraudLogic() {
+ val attempts = securityPrefRepository.attempts.orEmpty()
+ val lastTimeInMills = attempts.lastOrNull()?.timeInMills
+ val localDateTime = LocalDateTime.ofEpochSecond((lastTimeInMills ?: 0) / 1000, 0, OffsetDateTime.now().offset)
+ val nextDateTime = when (attempts.size) {
+ in 0..3 -> LocalDateTime.now().minusMinutes(1)
+ 4 -> localDateTime.plusMinutes(1)
+ 5 -> localDateTime.plusMinutes(5)
+ 6 -> localDateTime.plusMinutes(60)
+ else -> localDateTime.plusMinutes(60 * 5)
+ }
+ nextEnterTime.postValue(nextDateTime)
+ }
+
+ fun init(behavior: PinCodeScreenBehavior, stashedPin: String? = null) {
+ this.behavior.value = behavior
+ this.stashedPin.value = stashedPin
+ }
+
+ fun addNum(num: String) {
+ if ((currentNums.value?.length ?: 0) >= 6) {
+ if (errorMessage.value.orEmpty().isNotEmpty()) {
+ errorMessage.value = ""
+ currentNums.value = num
+ }
+ return
+ }
+ currentNums.value += num
+ if (currentNums.value.orEmpty().length == 6) {
+ doMainAction()
+ }
+ }
+
+ fun removeLast() {
+ currentNums.value = currentNums.value?.dropLast(1)
+ }
+
+ fun doMainAction() {
+ when (behavior.value) {
+ PinCodeScreenBehavior.Create -> createPinCode()
+ PinCodeScreenBehavior.CreateConfirm -> createPinCodeConfirm()
+ PinCodeScreenBehavior.ChangeNew -> changeNewPinCode()
+ PinCodeScreenBehavior.ChangeNewConfirm -> changeNewPinCodeConfirm()
+ PinCodeScreenBehavior.Auth -> authPinCode()
+ PinCodeScreenBehavior.FeatureAuth -> authPinCode()
+ null -> Unit
+ }
+ }
+
+ private fun createPinCode() {
+ navigation.postValue(Navigation.EnterPinCodeNavigation(PinCodeScreenBehavior.CreateConfirm, currentNums.value))
+ }
+
+ private fun createPinCodeConfirm() {
+ if (currentNums.value != stashedPin.value) {
+ backPressed.postValue(Unit)
+ return
+ }
+ securityPrefRepository.pinCode = currentNums.value.orEmpty()
+ tariNavigator.backAfterAuth()
+ }
+
+ private fun changeNewPinCode() {
+ navigation.postValue(Navigation.EnterPinCodeNavigation(PinCodeScreenBehavior.ChangeNewConfirm, currentNums.value))
+ }
+
+ private fun changeNewPinCodeConfirm() {
+ if (currentNums.value != stashedPin.value) {
+ backPressed.postValue(Unit)
+ return
+ }
+ securityPrefRepository.pinCode = currentNums.value.orEmpty()
+ tariNavigator.backAfterAuth()
+ }
+
+ private fun authPinCode() {
+ val isSuccessfully = currentNums.value == securityPrefRepository.pinCode
+
+ securityPrefRepository.saveAttempt(LoginAttemptDto(System.currentTimeMillis(), isSuccessfully))
+
+ if (!isSuccessfully) {
+ errorMessage.value = resourceManager.getString(R.string.pin_code_error_message)
+ return
+ }
+ successfullyAuth.postValue(Unit)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/PinCodeScreenBehavior.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/PinCodeScreenBehavior.kt
new file mode 100644
index 000000000..ccbeb6249
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/pinCode/PinCodeScreenBehavior.kt
@@ -0,0 +1,10 @@
+package com.tari.android.wallet.ui.fragment.pinCode
+
+enum class PinCodeScreenBehavior() {
+ Create,
+ CreateConfirm,
+ ChangeNew,
+ ChangeNewConfirm,
+ Auth,
+ FeatureAuth,
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/RoundButtonWithIconView.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/RoundButtonWithIconView.kt
new file mode 100644
index 000000000..88e0e634d
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/RoundButtonWithIconView.kt
@@ -0,0 +1,53 @@
+package com.tari.android.wallet.ui.fragment.profile
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.core.view.updateLayoutParams
+import com.tari.android.wallet.R
+import com.tari.android.wallet.databinding.ViewShareOptionBinding
+import com.tari.android.wallet.ui.common.domain.PaletteManager
+import com.tari.android.wallet.ui.extension.setOnThrottledClickListener
+
+class RoundButtonWithIconView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyle: Int = 0,
+ defStyleRes: Int = 0
+) : FrameLayout(context, attrs, defStyle, defStyleRes) {
+
+ val ui = ViewShareOptionBinding.inflate(LayoutInflater.from(context), this, true)
+
+ init {
+ layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
+ weight = 1f
+ }
+ }
+
+ fun setArgs(text: String, icon: Int, action: () -> Unit, size: Size = Size.Medium, isSelected: Boolean = false) {
+ this.setOnThrottledClickListener { action() }
+ ui.icon.setImageResource(icon)
+ val padding = context.resources.getDimensionPixelSize(size.padding)
+ ui.optionBackground.setPadding(padding, padding, padding, padding)
+ ui.optionBackground.updateLayoutParams {
+ val backSize = context.resources.getDimensionPixelSize(size.value)
+ height = backSize
+ width = backSize
+ }
+ ui.text.text = text
+ val paletteManager = PaletteManager()
+ val textColor = if (isSelected) paletteManager.getTextHeading(context) else paletteManager.getTextBody(context)
+ ui.text.setTextColor(textColor)
+ val backgroundColor = if (isSelected) paletteManager.getPurpleBrand(context) else paletteManager.getBackgroundPrimary(context)
+ ui.optionBackground.updateBack(backColor = backgroundColor)
+ val iconColor = if (isSelected) paletteManager.getBackgroundPrimary(context) else paletteManager.getTextHeading(context)
+ ui.icon.setColorFilter(iconColor)
+ }
+
+ enum class Size(val value: Int, val padding: Int) {
+ Big(R.dimen.contact_book_share_button_size_big, R.dimen.contact_book_share_button_padding_big),
+ Medium(R.dimen.contact_book_share_button_size_medium, R.dimen.contact_book_share_button_padding_medium)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/WalletInfoFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/WalletInfoFragment.kt
index ffdc97ebd..f0fcf651b 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/WalletInfoFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/profile/WalletInfoFragment.kt
@@ -56,6 +56,7 @@ import com.tari.android.wallet.ui.extension.temporarilyDisableClick
import com.tari.android.wallet.ui.fragment.contact_book.root.share.ShareOptionArgs
import com.tari.android.wallet.ui.fragment.contact_book.root.share.ShareOptionView
import com.tari.android.wallet.ui.fragment.contact_book.root.share.ShareType
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
class WalletInfoFragment : CommonFragment() {
@@ -110,19 +111,24 @@ class WalletInfoFragment : CommonFragment = MutableLiveData()
val emojiId: LiveData = _emojiId
@@ -117,24 +113,21 @@ class WalletInfoViewModel : CommonViewModel() {
}
fun showEditAliasDialog() {
- val name = sharedPrefsWrapper.name.orEmpty()
- val surname = sharedPrefsWrapper.surname.orEmpty()
+ val name = (sharedPrefsWrapper.name.orEmpty() + " " + sharedPrefsWrapper.surname.orEmpty()).trim()
var saveAction: () -> Boolean = { false }
val nameModule =
InputModule(name, resourceManager.getString(R.string.contact_book_add_contact_first_name_hint), true, false) { saveAction.invoke() }
- val surnameModule =
- InputModule(surname, resourceManager.getString(R.string.contact_book_add_contact_surname_hint), false, true) { saveAction.invoke() }
val headModule = HeadModule(
resourceManager.getString(R.string.wallet_info_alias_edit_title),
rightButtonTitle = resourceManager.getString(R.string.contact_book_add_contact_done_button)
) { saveAction.invoke() }
- val moduleList = mutableListOf(headModule, nameModule, surnameModule)
+ val moduleList = mutableListOf(headModule, nameModule)
saveAction = {
- saveDetails(nameModule.value, surnameModule.value)
+ saveDetails(nameModule.value)
true
}
@@ -146,10 +139,11 @@ class WalletInfoViewModel : CommonViewModel() {
navigation.postValue(Navigation.AllSettingsNavigation.ToRequestTari)
}
- private fun saveDetails(name: String, surname: String) {
- sharedPrefsWrapper.name = name
- sharedPrefsWrapper.surname = surname
- alias.postValue("$name $surname")
+ private fun saveDetails(name: String) {
+ val split = name.split(" ")
+ sharedPrefsWrapper.name = split.getOrNull(0).orEmpty().trim()
+ sharedPrefsWrapper.surname = split.getOrNull(1).orEmpty().trim()
+ alias.postValue(name)
dismissDialog.postValue(Unit)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerActivity.kt
index 3ba726c62..84f79fac0 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerActivity.kt
@@ -99,7 +99,7 @@ class QRScannerActivity : CommonActivity, grantResults: IntArray) {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerViewModel.kt
index 53778a898..14f233423 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/qr/QRScannerViewModel.kt
@@ -44,7 +44,7 @@ class QRScannerViewModel : CommonViewModel() {
}
fun onAlternativeApply() {
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
executeWithDelay(deeplinkViewModel) {
deeplinkViewModel.executeRawDeeplink(scannedDeeplink.value!!)
}
@@ -86,6 +86,7 @@ class QRScannerViewModel : CommonViewModel() {
is DeepLink.UserProfile -> navigateBack(deepLink)
is DeepLink.Contacts,
+ is DeepLink.TorBridges,
is DeepLink.AddBaseNode -> setAlternativeText(deepLink)
}
}
@@ -96,6 +97,7 @@ class QRScannerViewModel : CommonViewModel() {
is DeepLink.Send,
is DeepLink.Contacts,
+ is DeepLink.TorBridges,
is DeepLink.AddBaseNode -> setAlternativeText(deepLink)
}
}
@@ -106,6 +108,7 @@ class QRScannerViewModel : CommonViewModel() {
is DeepLink.UserProfile,
is DeepLink.Contacts -> navigateBack(deepLink)
+ is DeepLink.TorBridges,
is DeepLink.AddBaseNode -> setAlternativeText(deepLink)
}
}
@@ -114,9 +117,10 @@ class QRScannerViewModel : CommonViewModel() {
when (deepLink) {
is DeepLink.Send,
is DeepLink.UserProfile,
+ is DeepLink.AddBaseNode,
is DeepLink.Contacts -> setAlternativeText(deepLink)
- is DeepLink.AddBaseNode -> navigateBack(deepLink)
+ is DeepLink.TorBridges -> navigateBack(deepLink)
}
}
@@ -134,7 +138,7 @@ class QRScannerViewModel : CommonViewModel() {
is DeepLink.UserProfile -> resourceManager.getString(R.string.qr_code_scanner_labels_actions_profile)
is DeepLink.Contacts -> resourceManager.getString(R.string.qr_code_scanner_labels_actions_contacts)
is DeepLink.AddBaseNode -> resourceManager.getString(R.string.qr_code_scanner_labels_actions_base_node_add)
-// is DeepLink.TorBridge -> resourceManager.getString(R.string.qr_code_scanner_labels_actions_transaction_send)
+ is DeepLink.TorBridges -> resourceManager.getString(R.string.qr_code_scanner_labels_actions_tor_bridges)
}
alternativeText.postValue(text)
}
@@ -145,5 +149,6 @@ class QRScannerViewModel : CommonViewModel() {
fun onRetry() {
proceedScan.postValue(Unit)
+ scanError.postValue(false)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/activity/WalletRestoreActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/activity/WalletRestoreActivity.kt
index 33b18ef4c..18584278a 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/activity/WalletRestoreActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/activity/WalletRestoreActivity.kt
@@ -70,11 +70,16 @@ class WalletRestoreActivity : CommonActivity = _state
fun onBack() {
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
viewModelScope.launch(Dispatchers.IO) {
backupManager.signOut()
}
@@ -105,7 +105,7 @@ class EnterRestorationPasswordViewModel : CommonViewModel() {
description = message,
cancelable = false,
canceledOnTouchOutside = false,
- onClose = { _backPressed.call() })
+ onClose = { backPressed.call() })
modularDialog.postValue(args.getModular(resourceManager))
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt
index d1f60e6e4..d7be6b66b 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/restore/walletRestoringFromSeedWords/WalletRestoringFromSeedWordsViewModel.kt
@@ -5,7 +5,6 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.tari.android.wallet.R
import com.tari.android.wallet.application.baseNodes.BaseNodes
-import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.data.sharedPrefs.baseNode.BaseNodeDto
import com.tari.android.wallet.event.EventBus
import com.tari.android.wallet.extension.addTo
@@ -31,9 +30,6 @@ class WalletRestoringFromSeedWordsViewModel : CommonViewModel() {
@Inject
lateinit var seedPhraseRepository: SeedPhraseRepository
- @Inject
- lateinit var sharedPrefsRepository: SharedPrefsRepository
-
@Inject
lateinit var walletServiceLauncher: WalletServiceLauncher
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt
index 464c6c0e0..56c9dfd39 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/AddAmountFragment.kt
@@ -228,13 +228,13 @@ class AddAmountFragment : CommonFragment balanceInfo.availableBalance) {
+ if (amount > balanceInfo.availableBalance && !TariBuild.MOCKED) {
lifecycleScope.launch(Dispatchers.Main) {
actualBalanceExceeded()
}
} else {
lifecycleScope.launch(Dispatchers.Main) {
- if (fee > amount) {
+ if (fee > amount && !TariBuild.MOCKED) {
val args = ErrorDialogArgs(
string(error_fee_more_than_amount_title),
string(error_fee_more_than_amount_description)
@@ -292,7 +292,7 @@ class AddAmountFragment : CommonFragment availableBalance) {
+ if (!TariBuild.MOCKED && (keyboardController.currentAmount + viewModel.selectedFeeData?.calculatedFee!!) > availableBalance) {
showErrorState()
} else {
showSuccessState()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt
index a3c776cc3..7070d8e8f 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addAmount/keyboard/KeyboardController.kt
@@ -14,7 +14,16 @@ import com.tari.android.wallet.R
import com.tari.android.wallet.databinding.ViewInputAmountBinding
import com.tari.android.wallet.databinding.ViewNumpadBinding
import com.tari.android.wallet.model.MicroTari
-import com.tari.android.wallet.ui.extension.*
+import com.tari.android.wallet.ui.extension.dimen
+import com.tari.android.wallet.ui.extension.dimenPx
+import com.tari.android.wallet.ui.extension.getFirstChild
+import com.tari.android.wallet.ui.extension.getLastChild
+import com.tari.android.wallet.ui.extension.setLayoutSize
+import com.tari.android.wallet.ui.extension.setLayoutWidth
+import com.tari.android.wallet.ui.extension.setStartMargin
+import com.tari.android.wallet.ui.extension.setTextSizePx
+import com.tari.android.wallet.ui.extension.setTopMargin
+import com.tari.android.wallet.ui.extension.setWidthAndHeightToMeasured
import com.tari.android.wallet.util.Constants
import com.tari.android.wallet.util.WalletUtil
import java.math.BigInteger
@@ -95,14 +104,14 @@ class KeyboardController {
if (isFirstLaunch && startAmount != Double.MIN_VALUE) {
val handler = Handler(Looper.getMainLooper())
isFirstLaunch = false
- startAmount.toString().withIndex().forEach { (index, char) ->
- handler.postDelayed({
+ handler.post {
+ startAmount.toString().withIndex().forEach { (index, char) ->
if (Character.isDigit(char)) {
onDigitOrSeparatorClicked(char.toString())
} else {
onDigitOrSeparatorClicked(decimalSeparator)
}
- }, (index + 1) * Constants.UI.AddAmount.numPadDigitEnterAnimDurationMs * 2)
+ }
}
handler.postDelayed(
this::setActionBindings,
@@ -200,7 +209,6 @@ class KeyboardController {
* Digit or separator clicked.
*/
private fun onDigitOrSeparatorClicked(digit: String) {
- if (digitAnimIsRunning) return
// check if entering first digit
var enteringFirstDigit = false
if (elements.size == 1 && elements[0].first == "0") {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt
index 6a9921f86..29b4acb68 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/send/addNote/AddNoteFragment.kt
@@ -59,8 +59,9 @@ import com.daasuu.ei.Ease
import com.daasuu.ei.EasingInterpolator
import com.giphy.sdk.core.models.Media
import com.tari.android.wallet.R
-import com.tari.android.wallet.R.color.*
-import com.tari.android.wallet.R.dimen.*
+import com.tari.android.wallet.R.dimen.add_note_gif_inner_margin
+import com.tari.android.wallet.R.dimen.add_note_slide_button_left_margin
+import com.tari.android.wallet.R.dimen.add_note_slide_button_width
import com.tari.android.wallet.databinding.FragmentAddNoteBinding
import com.tari.android.wallet.event.EventBus
import com.tari.android.wallet.extension.observe
@@ -71,11 +72,26 @@ import com.tari.android.wallet.ui.common.CommonFragment
import com.tari.android.wallet.ui.common.gyphy.repository.GIFItem
import com.tari.android.wallet.ui.component.fullEmojiId.EmojiIdSummaryViewController
import com.tari.android.wallet.ui.component.fullEmojiId.FullEmojiIdViewController
-import com.tari.android.wallet.ui.extension.*
+import com.tari.android.wallet.ui.extension.dimen
+import com.tari.android.wallet.ui.extension.dimenPx
+import com.tari.android.wallet.ui.extension.getStartMargin
+import com.tari.android.wallet.ui.extension.gone
+import com.tari.android.wallet.ui.extension.hideKeyboard
+import com.tari.android.wallet.ui.extension.invisible
+import com.tari.android.wallet.ui.extension.parcelable
+import com.tari.android.wallet.ui.extension.postDelayed
+import com.tari.android.wallet.ui.extension.setStartMargin
+import com.tari.android.wallet.ui.extension.showInternetConnectionErrorDialog
+import com.tari.android.wallet.ui.extension.temporarilyDisableClick
+import com.tari.android.wallet.ui.extension.visible
import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.ContactDto
import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.PARAMETER_NOTE
import com.tari.android.wallet.ui.fragment.home.navigation.TariNavigator.Companion.PARAMETER_TRANSACTION
-import com.tari.android.wallet.ui.fragment.send.addNote.gif.*
+import com.tari.android.wallet.ui.fragment.send.addNote.gif.ChooseGIFDialogFragment
+import com.tari.android.wallet.ui.fragment.send.addNote.gif.GIFContainer
+import com.tari.android.wallet.ui.fragment.send.addNote.gif.GIFThumbnailAdapter
+import com.tari.android.wallet.ui.fragment.send.addNote.gif.HorizontalInnerMarginDecoration
+import com.tari.android.wallet.ui.fragment.send.addNote.gif.ThumbnailGIFsViewModel
import com.tari.android.wallet.ui.fragment.send.addNote.gif.ThumbnailGIFsViewModel.Companion.REQUEST_CODE_GIF
import com.tari.android.wallet.ui.fragment.send.common.TransactionData
import com.tari.android.wallet.util.Constants
@@ -128,6 +144,7 @@ class AddNoteFragment : CommonFragment
}
}
+ @Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_GIF) {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt
index 6573b17e1..f0ea57b2d 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/AllSettingsViewModel.kt
@@ -8,9 +8,12 @@ import com.tari.android.wallet.R.drawable.vector_all_settings_background_service
import com.tari.android.wallet.R.drawable.vector_all_settings_backup_options_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_bluetooth
import com.tari.android.wallet.R.drawable.vector_all_settings_bridge_configuration_icon
+import com.tari.android.wallet.R.drawable.vector_all_settings_cart
import com.tari.android.wallet.R.drawable.vector_all_settings_contribute_to_tari_icon
+import com.tari.android.wallet.R.drawable.vector_all_settings_data_collection
import com.tari.android.wallet.R.drawable.vector_all_settings_delete_button_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_disclaimer_icon
+import com.tari.android.wallet.R.drawable.vector_all_settings_passcode
import com.tari.android.wallet.R.drawable.vector_all_settings_privacy_policy_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_report_bug_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_select_base_node_icon
@@ -19,14 +22,19 @@ import com.tari.android.wallet.R.drawable.vector_all_settings_select_theme_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_user_agreement_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_visit_tari_icon
import com.tari.android.wallet.R.drawable.vector_all_settings_yat_icon
+import com.tari.android.wallet.R.drawable.vector_fingerprint
import com.tari.android.wallet.R.string.all_settings_advanced_settings_label
import com.tari.android.wallet.R.string.all_settings_background_service
+import com.tari.android.wallet.R.string.all_settings_biometrics
import com.tari.android.wallet.R.string.all_settings_bluetooth_settings
import com.tari.android.wallet.R.string.all_settings_bridge_configuration
import com.tari.android.wallet.R.string.all_settings_connect_yats
import com.tari.android.wallet.R.string.all_settings_contribute
+import com.tari.android.wallet.R.string.all_settings_create_pin_code
+import com.tari.android.wallet.R.string.all_settings_data_collection
import com.tari.android.wallet.R.string.all_settings_delete_wallet
import com.tari.android.wallet.R.string.all_settings_disclaimer
+import com.tari.android.wallet.R.string.all_settings_pin_code
import com.tari.android.wallet.R.string.all_settings_privacy_policy
import com.tari.android.wallet.R.string.all_settings_report_a_bug
import com.tari.android.wallet.R.string.all_settings_secondary_settings_label
@@ -34,6 +42,7 @@ import com.tari.android.wallet.R.string.all_settings_security_label
import com.tari.android.wallet.R.string.all_settings_select_base_node
import com.tari.android.wallet.R.string.all_settings_select_network
import com.tari.android.wallet.R.string.all_settings_select_theme
+import com.tari.android.wallet.R.string.all_settings_store
import com.tari.android.wallet.R.string.all_settings_user_agreement
import com.tari.android.wallet.R.string.all_settings_version_text_copy_title
import com.tari.android.wallet.R.string.all_settings_version_text_copy_toast_message
@@ -47,9 +56,11 @@ import com.tari.android.wallet.R.string.github_repo_url
import com.tari.android.wallet.R.string.privacy_policy_url
import com.tari.android.wallet.R.string.tari_about_title
import com.tari.android.wallet.R.string.tari_url
+import com.tari.android.wallet.R.string.ttl_store_url
import com.tari.android.wallet.R.string.user_agreement_url
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
import com.tari.android.wallet.event.EventBus
+import com.tari.android.wallet.extension.addTo
import com.tari.android.wallet.infrastructure.backup.BackupManager
import com.tari.android.wallet.infrastructure.backup.BackupState
import com.tari.android.wallet.infrastructure.backup.BackupsState
@@ -59,7 +70,9 @@ import com.tari.android.wallet.ui.common.SingleLiveEvent
import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
import com.tari.android.wallet.ui.common.recyclerView.items.DividerViewHolderItem
import com.tari.android.wallet.ui.dialog.error.ErrorDialogArgs
+import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation.AllSettingsNavigation
+import com.tari.android.wallet.ui.fragment.pinCode.PinCodeScreenBehavior
import com.tari.android.wallet.ui.fragment.settings.allSettings.PresentationBackupState.BackupStateStatus.InProgress
import com.tari.android.wallet.ui.fragment.settings.allSettings.PresentationBackupState.BackupStateStatus.Success
import com.tari.android.wallet.ui.fragment.settings.allSettings.PresentationBackupState.BackupStateStatus.Warning
@@ -72,6 +85,7 @@ import com.tari.android.wallet.ui.fragment.settings.allSettings.version.Settings
import com.tari.android.wallet.ui.fragment.settings.backup.data.BackupSettingsRepository
import com.tari.android.wallet.ui.fragment.settings.userAutorization.BiometricAuthenticationViewModel
import com.tari.android.wallet.yat.YatAdapter
+import com.tari.android.wallet.yat.YatSharedRepository
import javax.inject.Inject
class AllSettingsViewModel : CommonViewModel() {
@@ -79,7 +93,7 @@ class AllSettingsViewModel : CommonViewModel() {
lateinit var authenticationViewModel: BiometricAuthenticationViewModel
private val backupOption = SettingsBackupOptionViewHolderItem(leftIconId = vector_all_settings_backup_options_icon) {
- authenticationViewModel.requireAuthorization { navigation.postValue(AllSettingsNavigation.ToBackupSettings) }
+ runWithAuthorization { navigation.postValue(AllSettingsNavigation.ToBackupSettings) }
}
@Inject
@@ -94,6 +108,9 @@ class AllSettingsViewModel : CommonViewModel() {
@Inject
lateinit var settingsRepository: SharedPrefsRepository
+ @Inject
+ lateinit var yatSharedPrefsRepository: YatSharedRepository
+
private val _openYatOnboarding = SingleLiveEvent()
val openYatOnboarding: LiveData = _openYatOnboarding
@@ -104,6 +121,8 @@ class AllSettingsViewModel : CommonViewModel() {
component.inject(this)
initOptions()
EventBus.backupState.subscribe(this) { backupState -> onBackupStateChanged(backupState) }
+
+ settingsRepository.updateNotifier.subscribe { initOptions() }.addTo(compositeDisposable)
}
private fun initOptions() {
@@ -114,9 +133,10 @@ class AllSettingsViewModel : CommonViewModel() {
)
val alias = settingsRepository.name.orEmpty() + " " + settingsRepository.surname.orEmpty()
+ val pinCode = securityPrefRepository.pinCode
val allOptions = mutableListOf(
- MyProfileViewHolderItem(settingsRepository.emojiId.orEmpty(), alias) {
+ MyProfileViewHolderItem(settingsRepository.emojiId.orEmpty(), yatSharedPrefsRepository.connectedYat.orEmpty(), alias) {
navigation.postValue(AllSettingsNavigation.ToMyProfile)
},
DividerViewHolderItem(),
@@ -126,7 +146,34 @@ class AllSettingsViewModel : CommonViewModel() {
SettingsTitleViewHolderItem(resourceManager.getString(all_settings_security_label)),
backupOption,
DividerViewHolderItem(),
+ ButtonViewDto(resourceManager.getString(all_settings_data_collection), vector_all_settings_data_collection) {
+ navigation.postValue(AllSettingsNavigation.ToDataCollection)
+ },
+ DividerViewHolderItem(),
+ if (pinCode != null) {
+ ButtonViewDto(resourceManager.getString(all_settings_pin_code), vector_all_settings_passcode) {
+ runWithAuthorization {
+ navigation.postValue(Navigation.EnterPinCodeNavigation(PinCodeScreenBehavior.ChangeNew))
+ }
+ }
+ } else {
+ ButtonViewDto(resourceManager.getString(all_settings_create_pin_code), vector_all_settings_passcode) {
+ runWithAuthorization {
+ navigation.postValue(Navigation.EnterPinCodeNavigation(PinCodeScreenBehavior.Create))
+ }
+ }
+ },
+ DividerViewHolderItem(),
+ ButtonViewDto(resourceManager.getString(all_settings_biometrics), vector_fingerprint) {
+ runWithAuthorization {
+ navigation.postValue(Navigation.ChangeBiometrics())
+ }
+ },
SettingsTitleViewHolderItem(resourceManager.getString(all_settings_secondary_settings_label)),
+ ButtonViewDto(resourceManager.getString(all_settings_store), vector_all_settings_cart) {
+ _openLink.postValue(resourceManager.getString(ttl_store_url))
+ },
+ DividerViewHolderItem(),
ButtonViewDto(resourceManager.getString(tari_about_title), vector_all_settings_about_icon) {
navigation.postValue(AllSettingsNavigation.ToAbout)
},
@@ -189,7 +236,7 @@ class AllSettingsViewModel : CommonViewModel() {
DividerViewHolderItem(),
SettingsVersionViewHolderItem(versionText) { _copyToClipboard.postValue(versionArgs) }
)
- _allSettingsOptions.value = allOptions
+ _allSettingsOptions.postValue(allOptions)
}
private fun onBackupStateChanged(backupState: BackupsState?) {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolder.kt
index 56e537a13..0f3e626d7 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolder.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolder.kt
@@ -11,12 +11,15 @@ class MyProfileViewHolder(view: ItemMyProfileBinding) :
CommonViewHolder(view) {
private val emojiIdSummaryController = EmojiIdSummaryViewController(ui.participantEmojiIdView)
+ private val yatController = EmojiIdSummaryViewController(ui.participantYatIdView)
override fun bind(item: MyProfileViewHolderItem) {
super.bind(item)
ui.firstEmojiTextView.text = item.emojiId.extractEmojis()[0]
ui.alias.text = item.alias
ui.alias.setVisible(item.alias.isNotBlank())
+ ui.participantYatIdView.root.setVisible(item.yat.isNotBlank())
+ yatController.display(item.yat)
emojiIdSummaryController.display(item.emojiId)
ui.root.setOnClickListener { item.action.invoke() }
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolderItem.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolderItem.kt
index 8849ce1f9..8711ef406 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolderItem.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/allSettings/myProfile/MyProfileViewHolderItem.kt
@@ -2,6 +2,6 @@ package com.tari.android.wallet.ui.fragment.settings.allSettings.myProfile
import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
-class MyProfileViewHolderItem(val emojiId: String, val alias: String, val action: () -> Unit) : CommonViewHolderItem() {
+class MyProfileViewHolderItem(val emojiId: String, val yat: String, val alias: String, val action: () -> Unit) : CommonViewHolderItem() {
override val viewHolderUUID: String = "MyProfileViewHolderItem$emojiId"
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt
index 38c2a3b56..570affaf1 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/backup/backupSettings/BackupSettingsFragment.kt
@@ -73,6 +73,7 @@ class BackupSettingsFragment : CommonFragment) : Iterable {
val length
get() = seedWords.size
- private fun sorted(): SeedPhrase = SeedPhrase(if (Build.MOCKED) seedWords else seedWords.sorted())
+ private fun sorted(): SeedPhrase = SeedPhrase(if (TariBuild.MOCKED) seedWords else seedWords.sorted())
fun consistsOf(result: List): Boolean = seedWords == result
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt
index dff9ab090..96f2f4cbf 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/addBaseNode/AddCustomBaseNodeViewModel.kt
@@ -58,7 +58,7 @@ class AddCustomBaseNodeViewModel : CommonViewModel() {
val baseNodeDto = BaseNodeDto(name, publicKeyHex, address, true)
baseNodeSharedRepository.addUserBaseNode(baseNodeDto)
baseNodes.setBaseNode(baseNodeDto)
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
} catch (e: Throwable) {
baseNodes.setNextBaseNode()
addBaseNodePeerFailed()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt
index 4ce5f86ef..ca8180698 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/baseNodeConfig/changeBaseNode/ChangeBaseNodeViewModel.kt
@@ -43,7 +43,7 @@ class ChangeBaseNodeViewModel : CommonViewModel() {
fun selectBaseNode(baseNodeDto: BaseNodeDto) {
baseNodes.setBaseNode(baseNodeDto)
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
}
fun showQrCode(baseNodeDto: BaseNodeDto) {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/bugReporting/BugsReportingViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/bugReporting/BugsReportingViewModel.kt
index 0a061cdc7..8162b0bcb 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/bugReporting/BugsReportingViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/bugReporting/BugsReportingViewModel.kt
@@ -17,7 +17,7 @@ class BugsReportingViewModel : CommonViewModel() {
fun send(name: String, email: String, bugDescription: String) = viewModelScope.launch {
bugReportingService.share(name, email, bugDescription)
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/dataCollection/DataCollectionFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/dataCollection/DataCollectionFragment.kt
new file mode 100644
index 000000000..f6498dd54
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/dataCollection/DataCollectionFragment.kt
@@ -0,0 +1,33 @@
+package com.tari.android.wallet.ui.fragment.settings.dataCollection
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.viewModels
+import com.tari.android.wallet.databinding.FragmentDataCollectionBinding
+import com.tari.android.wallet.extension.observe
+import com.tari.android.wallet.ui.common.CommonFragment
+import com.tari.android.wallet.ui.component.loadingSwitch.TariLoadingSwitchState
+
+class DataCollectionFragment : CommonFragment() {
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ FragmentDataCollectionBinding.inflate(inflater, container, false).also { ui = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val viewModel: DataCollectionViewModel by viewModels()
+ bindViewModel(viewModel)
+
+ ui.loadingSwitchView.setOnCheckedChangeListener {
+ viewModel.updateState(it)
+ }
+
+ observe(viewModel.state) {
+ ui.loadingSwitchView.setState(TariLoadingSwitchState(it, false))
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/dataCollection/DataCollectionViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/dataCollection/DataCollectionViewModel.kt
new file mode 100644
index 000000000..e8fa8ee4a
--- /dev/null
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/dataCollection/DataCollectionViewModel.kt
@@ -0,0 +1,24 @@
+package com.tari.android.wallet.ui.fragment.settings.dataCollection
+
+import androidx.lifecycle.MutableLiveData
+import com.tari.android.wallet.data.sharedPrefs.sentry.SentryPrefRepository
+import com.tari.android.wallet.ui.common.CommonViewModel
+import javax.inject.Inject
+
+class DataCollectionViewModel : CommonViewModel() {
+
+ @Inject
+ lateinit var sentryPrefRepository: SentryPrefRepository
+
+ val state: MutableLiveData = MutableLiveData()
+
+ init {
+ component.inject(this)
+ state.value = sentryPrefRepository.isEnabled == true
+ }
+
+ fun updateState(state: Boolean) {
+ sentryPrefRepository.isEnabled = state
+ this.state.value = state
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/logs/logs/LogsViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/logs/logs/LogsViewModel.kt
index 6f53ec365..3db4c9393 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/logs/logs/LogsViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/logs/logs/LogsViewModel.kt
@@ -50,7 +50,7 @@ class LogsViewModel : CommonViewModel() {
resourceManager.getString(R.string.common_error_title),
resourceManager.getString(R.string.debug_logs_cant_open_file),
) {
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
}
modularDialog.postValue(errorArgs.getModular(resourceManager))
logger.e(e, "Out of memory on reading big log file")
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt
index d4ae7a627..b14d7991e 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/networkSelection/NetworkSelectionViewModel.kt
@@ -46,7 +46,7 @@ class NetworkSelectionViewModel : CommonViewModel() {
fun selectNetwork(networkViewHolderItem: NetworkViewHolderItem) {
if (networkViewHolderItem.network.network == networkRepository.currentNetwork!!.network) {
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
return
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionFragment.kt
index bcea99de7..92d73fa7a 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/TorBridgesSelectionFragment.kt
@@ -44,6 +44,10 @@ class TorBridgesSelectionFragment : CommonFragment {
torBridgeItem.isSelected = !torBridgeItem.isSelected
}
@@ -86,6 +93,19 @@ class TorBridgesSelectionViewModel : CommonViewModel() {
_torBridges.postValue(_torBridges.value!!.map { it.deepCopy() as TorBridgeViewHolderItem }.toMutableList())
}
+ fun showBridgeQrCode(torBridgeItem: TorBridgeViewHolderItem) {
+ if (torBridgeItem !is TorBridgeViewHolderItem.Bridge) return
+ val data = deeplinkHandler.getDeeplink(DeepLink.TorBridges(listOf(torBridgeItem.bridgeConfiguration)))
+ val args = ModularDialogArgs(
+ DialogArgs(true, canceledOnTouchOutside = true), listOf(
+ HeadModule(resourceManager.getString(R.string.share_via_qr_code_title)),
+ ShareQrCodeModule(data),
+ ButtonModule(resourceManager.getString(R.string.common_close), ButtonStyle.Close)
+ )
+ )
+ modularDialog.postValue(args)
+ }
+
fun connect() {
val selectedBridges = _torBridges.value.orEmpty().filter { it.isSelected }
if (selectedBridges.any { it is TorBridgeViewHolderItem.Empty }) {
@@ -124,6 +144,7 @@ class TorBridgesSelectionViewModel : CommonViewModel() {
) { stopConnecting() }
modularDialog.postValue(errorArgs.getModular(resourceManager))
}
+
is TorProxyState.Running -> {
if (it.bootstrapStatus.progress == 100) {
EventBus.torProxyState.unsubscribe(this)
@@ -142,8 +163,8 @@ class TorBridgesSelectionViewModel : CommonViewModel() {
BodyModule(description),
ButtonModule(resourceManager.getString(R.string.common_confirm), ButtonStyle.Normal) {
dismissDialog.postValue(Unit)
- _backPressed.postValue(Unit)
- },
+ backPressed.postValue(Unit)
+ },
)
)
modularDialog.postValue(args)
@@ -162,6 +183,7 @@ class TorBridgesSelectionViewModel : CommonViewModel() {
_loadingDialog.postValue(nextArgs)
}
}
+
else -> Unit
}
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesFragment.kt
index 7cb53a671..6fde6b0d7 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesFragment.kt
@@ -7,13 +7,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
-import com.google.gson.Gson
import com.tari.android.wallet.R
import com.tari.android.wallet.databinding.FragmentCustomTorBridgesBinding
+import com.tari.android.wallet.extension.observe
import com.tari.android.wallet.ui.common.CommonFragment
import com.tari.android.wallet.ui.component.tari.toolbar.TariToolbarActionArg
import com.tari.android.wallet.ui.extension.setOnThrottledClickListener
import com.tari.android.wallet.ui.fragment.qr.QRScannerActivity
+import com.tari.android.wallet.ui.fragment.qr.QrScannerSource
class CustomTorBridgesFragment : CommonFragment() {
@@ -31,21 +32,23 @@ class CustomTorBridgesFragment : CommonFragment()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt
index 4049c9e17..3ef3445bd 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/settings/torBridges/customBridges/CustomTorBridgesViewModel.kt
@@ -1,10 +1,12 @@
package com.tari.android.wallet.ui.fragment.settings.torBridges.customBridges
import com.tari.android.wallet.R
-import com.tari.android.wallet.application.WalletManager
+import com.tari.android.wallet.application.deeplinks.DeepLink
+import com.tari.android.wallet.application.deeplinks.DeeplinkHandler
import com.tari.android.wallet.data.sharedPrefs.tor.TorBridgeConfiguration
import com.tari.android.wallet.data.sharedPrefs.tor.TorSharedRepository
import com.tari.android.wallet.ui.common.CommonViewModel
+import com.tari.android.wallet.ui.common.SingleLiveEvent
import com.tari.android.wallet.ui.dialog.error.ErrorDialogArgs
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
import javax.inject.Inject
@@ -15,7 +17,9 @@ class CustomTorBridgesViewModel : CommonViewModel() {
lateinit var torSharedRepository: TorSharedRepository
@Inject
- lateinit var walletManager: WalletManager
+ lateinit var deeplinkHandler: DeeplinkHandler
+
+ var text = SingleLiveEvent()
init {
component.inject(this)
@@ -23,8 +27,6 @@ class CustomTorBridgesViewModel : CommonViewModel() {
fun openRequestPage() = _openLink.postValue(resourceManager.getString(R.string.tor_bridges_url))
- fun navigateToScanQr() = navigation.postValue(Navigation.CustomBridgeNavigation.ScanQrCode)
-
fun navigateToUploadQr() = navigation.postValue(Navigation.CustomBridgeNavigation.UploadQrCode)
fun connect(inputStr: String) {
@@ -61,7 +63,15 @@ class CustomTorBridgesViewModel : CommonViewModel() {
}
newBridges.forEach { torSharedRepository.addTorBridgeConfiguration(it) }
- _backPressed.postValue(Unit)
+ backPressed.postValue(Unit)
+ }
+
+ fun handleQrCode(input: String) {
+ val deeplink = deeplinkHandler.handle(input)
+ if (deeplink is DeepLink.TorBridges) {
+ val text = deeplinkHandler.getDeeplink(deeplink)
+ this.text.postValue(text)
+ }
}
private fun incorrectFormat() {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt
index 102830973..c463b42b9 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/splash/SplashActivity.kt
@@ -35,9 +35,11 @@ package com.tari.android.wallet.ui.fragment.splash
import android.app.Activity
import android.content.Intent
import android.os.Bundle
+import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import com.tari.android.wallet.data.WalletConfig
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
+import com.tari.android.wallet.data.sharedPrefs.security.SecurityPrefRepository
import com.tari.android.wallet.di.DiContainer.appComponent
import com.tari.android.wallet.service.service.WalletServiceLauncher
import com.tari.android.wallet.ui.fragment.auth.AuthActivity
@@ -58,6 +60,9 @@ class SplashActivity : AppCompatActivity() {
@Inject
lateinit var sharedPrefsRepository: SharedPrefsRepository
+ @Inject
+ lateinit var securityPrefRepository: SecurityPrefRepository
+
@Inject
lateinit var walletServiceLauncher: WalletServiceLauncher
@@ -65,6 +70,8 @@ class SplashActivity : AppCompatActivity() {
appComponent.inject(this)
super.onCreate(savedInstanceState)
+ onBackPressedDispatcher.addCallback { }
+
if (sharedPrefsRepository.checkIfIsDataCleared()) {
walletServiceLauncher.stopAndDelete()
}
@@ -75,6 +82,10 @@ class SplashActivity : AppCompatActivity() {
WalletUtil.clearWalletFiles(walletConfig.getWalletFilesDirPath())
sharedPrefsRepository.clear()
}
+ if (securityPrefRepository.pinCode == null) {
+ launch(OnboardingFlowActivity::class.java)
+ return
+ }
launch(if (exists) AuthActivity::class.java else OnboardingFlowActivity::class.java)
}
@@ -85,6 +96,4 @@ class SplashActivity : AppCompatActivity() {
startActivity(intent)
finish()
}
-
- override fun onBackPressed() = Unit
}
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragment.kt
index 9907b1a00..b127f1a9a 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragment.kt
@@ -32,13 +32,20 @@
*/
package com.tari.android.wallet.ui.fragment.tx
-import android.animation.*
import android.annotation.SuppressLint
-import android.os.*
-import android.view.*
+import android.app.Activity
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.tari.android.wallet.R
+import com.tari.android.wallet.application.deeplinks.DeeplinkViewModel
import com.tari.android.wallet.databinding.FragmentHomeBinding
import com.tari.android.wallet.event.EventBus
import com.tari.android.wallet.extension.observe
@@ -49,7 +56,7 @@ import com.tari.android.wallet.ui.common.recyclerView.AdapterFactory
import com.tari.android.wallet.ui.common.recyclerView.CommonAdapter
import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
import com.tari.android.wallet.ui.component.networkStateIndicator.ConnectionIndicatorViewModel
-import com.tari.android.wallet.ui.extension.*
+import com.tari.android.wallet.ui.extension.setVisible
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
import com.tari.android.wallet.ui.fragment.qr.QRScannerActivity
import com.tari.android.wallet.ui.fragment.qr.QrScannerSource
@@ -70,6 +77,8 @@ class HomeFragment : CommonFragment(
// This listener is used only to animate the visibility of the scroll depth gradient view.
private lateinit var balanceViewController: BalanceViewController
+ private val deeplinkViewModel: DeeplinkViewModel by viewModels()
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
FragmentHomeBinding.inflate(inflater, container, false).also { ui = it }.root
@@ -82,6 +91,7 @@ class HomeFragment : CommonFragment(
viewModel.serviceConnection.reconnectToService()
subscribeVM(viewModel.stagedWalletSecurityManager)
+ subscribeVM(deeplinkViewModel)
checkPermission()
setupUI()
@@ -99,6 +109,7 @@ class HomeFragment : CommonFragment(
observe(txList) {
ui.transactionsRecyclerView.setVisible(it.isNotEmpty())
+ ui.viewAllTxsButton.setVisible(it.isNotEmpty())
ui.emptyState.setVisible(it.isEmpty())
adapter.update(it)
adapter.notifyDataSetChanged()
@@ -166,6 +177,14 @@ class HomeFragment : CommonFragment(
}
}
+ @Deprecated("Deprecated in Java")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (requestCode == QRScannerActivity.REQUEST_QR_SCANNER && resultCode == Activity.RESULT_OK && data != null) {
+ val qrData = data.getStringExtra(QRScannerActivity.EXTRA_QR_DATA) ?: return
+ deeplinkViewModel.tryToHandle(qrData)
+ }
+ }
+
private fun updateBalanceInfoUI(restart: Boolean) {
val balanceInfo = viewModel.balanceInfo.value!!
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragmentViewModel.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragmentViewModel.kt
index 8a706e8d9..4e701df57 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragmentViewModel.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/HomeFragmentViewModel.kt
@@ -6,12 +6,14 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.toLiveData
import androidx.lifecycle.viewModelScope
+import com.tari.android.wallet.R
import com.tari.android.wallet.R.string.error_no_connection_description
import com.tari.android.wallet.R.string.error_no_connection_title
import com.tari.android.wallet.R.string.error_node_unreachable_description
import com.tari.android.wallet.R.string.error_node_unreachable_title
import com.tari.android.wallet.application.securityStage.StagedWalletSecurityManager
import com.tari.android.wallet.data.sharedPrefs.SharedPrefsRepository
+import com.tari.android.wallet.data.sharedPrefs.sentry.SentryPrefRepository
import com.tari.android.wallet.event.Event
import com.tari.android.wallet.event.EventBus
import com.tari.android.wallet.extension.addTo
@@ -22,6 +24,12 @@ import com.tari.android.wallet.ui.common.CommonViewModel
import com.tari.android.wallet.ui.common.SingleLiveEvent
import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
import com.tari.android.wallet.ui.dialog.error.ErrorDialogArgs
+import com.tari.android.wallet.ui.dialog.modular.DialogArgs
+import com.tari.android.wallet.ui.dialog.modular.ModularDialogArgs
+import com.tari.android.wallet.ui.dialog.modular.modules.body.BodyModule
+import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonModule
+import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonStyle
+import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule
import com.tari.android.wallet.ui.fragment.contact_book.data.ContactsRepository
import com.tari.android.wallet.ui.fragment.home.navigation.Navigation
import com.tari.android.wallet.ui.fragment.send.finalize.TxFailureReason
@@ -51,6 +59,9 @@ class HomeFragmentViewModel : CommonViewModel() {
@Inject
lateinit var transactionRepository: TransactionRepository
+ @Inject
+ lateinit var sentryPrefRepository: SentryPrefRepository
+
val stagedWalletSecurityManager = StagedWalletSecurityManager()
private val _balanceInfo = MutableLiveData()
@@ -77,8 +88,11 @@ class HomeFragmentViewModel : CommonViewModel() {
val emojies = sharedPrefsWrapper.emojiId.orEmpty().extractEmojis()
emojiMedium.postValue(emojies.take(3).joinToString(""))
emoji.postValue(emojies.take(1).joinToString(""))
+
+ checkForDataConsent()
}
+
private fun updateList() {
val list = transactionRepository.list.value ?: return
txList.postValue(list.filterIsInstance().sortedBy { it.tx.timestamp }.takeLast(amountOfTransactions).toMutableList())
@@ -90,6 +104,25 @@ class HomeFragmentViewModel : CommonViewModel() {
}
}
+ private fun checkForDataConsent() {
+ if (sentryPrefRepository.isEnabled == null) {
+ sentryPrefRepository.isEnabled = false
+ val args = ModularDialogArgs(DialogArgs(cancelable = false, canceledOnTouchOutside = false), listOf(
+ HeadModule(resourceManager.getString(R.string.data_collection_dialog_title)),
+ BodyModule(resourceManager.getString(R.string.data_collection_dialog_description)),
+ ButtonModule(resourceManager.getString(R.string.data_collection_dialog_positive), ButtonStyle.Normal) {
+ sentryPrefRepository.isEnabled = true
+ dismissDialog.postValue(Unit)
+ },
+ ButtonModule(resourceManager.getString(R.string.data_collection_dialog_negative), ButtonStyle.Close) {
+ sentryPrefRepository.isEnabled = false
+ dismissDialog.postValue(Unit)
+ }
+ ))
+ modularDialog.postValue(args)
+ }
+ }
+
private fun onServiceConnected() {
subscribeToEventBus()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TransactionRepository.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TransactionRepository.kt
index 051bf56b6..b8f702d90 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TransactionRepository.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/TransactionRepository.kt
@@ -18,7 +18,6 @@ import com.tari.android.wallet.model.MicroTari
import com.tari.android.wallet.model.PendingInboundTx
import com.tari.android.wallet.model.PendingOutboundTx
import com.tari.android.wallet.model.TariContact
-import com.tari.android.wallet.model.TariWalletAddress
import com.tari.android.wallet.model.Tx
import com.tari.android.wallet.model.TxId
import com.tari.android.wallet.model.TxStatus
@@ -30,7 +29,8 @@ import com.tari.android.wallet.ui.common.recyclerView.CommonViewHolderItem
import com.tari.android.wallet.ui.common.recyclerView.items.TitleViewHolderItem
import com.tari.android.wallet.ui.fragment.contact_book.data.ContactsRepository
import com.tari.android.wallet.ui.fragment.tx.adapter.TransactionItem
-import com.tari.android.wallet.util.Build.MOCKED
+import com.tari.android.wallet.util.TariBuild
+import com.tari.android.wallet.util.TariBuild.MOCKED
import io.reactivex.BackpressureStrategy
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -175,10 +175,8 @@ class TransactionRepository @Inject constructor() : CommonViewModel() {
if (MOCKED) {
- val emojiId =
- "\uD83C\uDFB9\uD83C\uDFA4\uD83C\uDF20\uD83C\uDFAA\uD83D\uDC16\uD83C\uDF5A\uD83D\uDE08\uD83C\uDF73\uD83C\uDFED\uD83D\uDC2F\uD83D\uDC29\uD83D\uDC33\uD83D\uDC2D\uD83D\uDC35\uD83D\uDC11\uD83C\uDF4E\uD83D\uDE02\uD83C\uDFB3\uD83C\uDF34\uD83C\uDF6D\uD83D\uDC0D\uD83C\uDF1F\uD83D\uDCBC\uD83C\uDFB9\uD83D\uDC3A\uD83D\uDC79\uD83C\uDF77\uD83D\uDC3B\uD83D\uDEAB\uD83D\uDE92\uD83D\uDCB3\uD83C\uDFAE\uD83D\uDD2A"
- val hex = "5A4A0A4F7427E33469858088838A721FE1560C316F09C55A8EA6388FFBF1C152DA"
val title = TitleViewHolderItem("Mocked Transactions", true)
+ val messageGiphy = " https://giphy.com/embed/5885nYOgBHdCw"
val item = TransactionItem(
CompletedTx().apply {
@@ -186,9 +184,10 @@ class TransactionRepository @Inject constructor() : CommonViewModel() {
status = TxStatus.MINED_CONFIRMED
amount = MicroTari(BigInteger.valueOf(100000))
fee = MicroTari(BigInteger.valueOf(1000))
+ message = messageGiphy
timestamp = BigInteger.valueOf(System.currentTimeMillis())
id = BigInteger.valueOf(1)
- tariContact = TariContact(TariWalletAddress(hex, emojiId), "test1")
+ tariContact = TariContact(TariBuild.moched_zero_contact, "test1")
},
contactsRepository.ffiBridge.getContactForTx(CompletedTx()),
0,
@@ -203,8 +202,8 @@ class TransactionRepository @Inject constructor() : CommonViewModel() {
fee = MicroTari(BigInteger.valueOf(1000))
timestamp = BigInteger.valueOf(System.currentTimeMillis())
id = BigInteger.valueOf(1)
- message = "message"
- tariContact = TariContact(TariWalletAddress(hex, emojiId), "test2")
+ message = messageGiphy
+ tariContact = TariContact(TariBuild.moched_zero_contact, "test2")
}
val item2 = TransactionItem(
tx2,
@@ -217,11 +216,12 @@ class TransactionRepository @Inject constructor() : CommonViewModel() {
val tx3 = CompletedTx().apply {
direction = Tx.Direction.INBOUND
status = TxStatus.MINED_CONFIRMED
+ message = messageGiphy
amount = MicroTari(BigInteger.valueOf(111000))
fee = MicroTari(BigInteger.valueOf(1000))
timestamp = BigInteger.valueOf(System.currentTimeMillis())
id = BigInteger.valueOf(1)
- tariContact = TariContact(TariWalletAddress(hex, emojiId), "test3")
+ tariContact = TariContact(TariBuild.mocked_wallet_address, "test3")
}
val item3 = TransactionItem(
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/WaveView.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/WaveView.kt
index 662091abc..34199105f 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/WaveView.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/WaveView.kt
@@ -56,11 +56,11 @@ class WaveView : View {
waveLength = width * 1.5F
}
- override fun onDraw(canvas: Canvas?) {
+ override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
doWave()
- canvas?.drawPath(path, paint)
+ canvas.drawPath(path, paint)
}
private fun doWave() {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt
index c487a8c9c..71a92364a 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TransactionItem.kt
@@ -16,7 +16,7 @@ data class TransactionItem(
override val viewHolderUUID: String = "TransactionItem" + tx.id
- override fun hashCode(): Int = HashcodeUtils.generate(tx.id, contact?.contact, position, requiredConfirmationCount, contact?.contact?.getAlias())
+ override fun hashCode(): Int = HashcodeUtils.generate(tx.id, contact?.contact?.getAlias(), contact?.contact, position, requiredConfirmationCount, contact?.contact?.getAlias())
override fun equals(other: Any?): Boolean {
return if (other is TransactionItem) {
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListHomeViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListHomeViewHolder.kt
index 5c85c9235..2102903e8 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListHomeViewHolder.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListHomeViewHolder.kt
@@ -53,8 +53,8 @@ class TxListHomeViewHolder(view: ItemHomeTxListBinding) : CommonViewHolder {
- val alias = contact.contact.getAlias()
+ contact != null && contact.contact.getAlias().isNotEmpty() || txUser.walletAddress.isZeros() -> {
+ val alias = contact?.contact?.getAlias().orEmpty().ifBlank { itemView.context.getString(R.string.unknown_source) }
val fullText = when (tx.direction) {
Tx.Direction.INBOUND -> string(R.string.tx_list_sent_a_payment, alias)
Tx.Direction.OUTBOUND -> string(R.string.tx_list_you_paid_with_alias, alias)
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt
index 6aa15c728..960ef98d1 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/adapter/TxListViewHolder.kt
@@ -91,8 +91,8 @@ class TxListViewHolder(view: ItemTxListBinding) : CommonViewHolder {
- val alias = contact.contact.getAlias()
+ contact != null && contact.contact.getAlias().isNotEmpty() || txUser.walletAddress.isZeros() -> {
+ val alias = contact?.contact?.getAlias().orEmpty().ifBlank { itemView.context.getString(R.string.unknown_source) }
val fullText = when (tx.direction) {
Tx.Direction.INBOUND -> string(R.string.tx_list_sent_a_payment, alias)
Tx.Direction.OUTBOUND -> string(R.string.tx_list_you_paid_with_alias, alias)
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt
index af28b176a..0e7803aca 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/TxDetailsFragment.kt
@@ -39,17 +39,45 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import com.bumptech.glide.Glide
-import com.tari.android.wallet.R.color.*
import com.tari.android.wallet.R.dimen.add_amount_element_text_size
import com.tari.android.wallet.R.dimen.add_amount_gem_size
-import com.tari.android.wallet.R.string.*
+import com.tari.android.wallet.R.string.common_are_you_sure
+import com.tari.android.wallet.R.string.common_from
+import com.tari.android.wallet.R.string.common_to
+import com.tari.android.wallet.R.string.tx_detail_add_contact
+import com.tari.android.wallet.R.string.tx_detail_completing_final_processing
+import com.tari.android.wallet.R.string.tx_detail_edit
+import com.tari.android.wallet.R.string.tx_detail_fee_tooltip_desc
+import com.tari.android.wallet.R.string.tx_detail_fee_tooltip_transaction_fee
+import com.tari.android.wallet.R.string.tx_detail_payment_cancelled
+import com.tari.android.wallet.R.string.tx_detail_payment_received
+import com.tari.android.wallet.R.string.tx_detail_payment_sent
+import com.tari.android.wallet.R.string.tx_detail_pending_payment_received
+import com.tari.android.wallet.R.string.tx_detail_waiting_for_recipient
+import com.tari.android.wallet.R.string.tx_detail_waiting_for_sender_to_complete
+import com.tari.android.wallet.R.string.tx_details_cancel_dialog_cancel
+import com.tari.android.wallet.R.string.tx_details_cancel_dialog_description
+import com.tari.android.wallet.R.string.tx_details_cancel_dialog_not_cancel
+import com.tari.android.wallet.R.string.tx_details_fee_value
+import com.tari.android.wallet.R.string.tx_list_you_received_one_side_payment
import com.tari.android.wallet.databinding.FragmentTxDetailsBinding
import com.tari.android.wallet.extension.observe
import com.tari.android.wallet.extension.txFormattedDate
-import com.tari.android.wallet.model.*
+import com.tari.android.wallet.model.CancelledTx
+import com.tari.android.wallet.model.CompletedTx
+import com.tari.android.wallet.model.MicroTari
+import com.tari.android.wallet.model.PendingOutboundTx
+import com.tari.android.wallet.model.Tx
import com.tari.android.wallet.model.Tx.Direction.INBOUND
import com.tari.android.wallet.model.Tx.Direction.OUTBOUND
-import com.tari.android.wallet.model.TxStatus.*
+import com.tari.android.wallet.model.TxId
+import com.tari.android.wallet.model.TxNote
+import com.tari.android.wallet.model.TxStatus.COINBASE
+import com.tari.android.wallet.model.TxStatus.FAUX_CONFIRMED
+import com.tari.android.wallet.model.TxStatus.FAUX_UNCONFIRMED
+import com.tari.android.wallet.model.TxStatus.IMPORTED
+import com.tari.android.wallet.model.TxStatus.MINED_CONFIRMED
+import com.tari.android.wallet.model.TxStatus.PENDING
import com.tari.android.wallet.ui.animation.collapseAndHideAnimation
import com.tari.android.wallet.ui.common.CommonFragment
import com.tari.android.wallet.ui.component.fullEmojiId.EmojiIdSummaryViewController
@@ -62,13 +90,25 @@ import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonModule
import com.tari.android.wallet.ui.dialog.modular.modules.button.ButtonStyle
import com.tari.android.wallet.ui.dialog.modular.modules.head.HeadModule
import com.tari.android.wallet.ui.dialog.tooltipDialog.TooltipDialogArgs
-import com.tari.android.wallet.ui.extension.*
+import com.tari.android.wallet.ui.extension.dimen
+import com.tari.android.wallet.ui.extension.getFirstChild
+import com.tari.android.wallet.ui.extension.getLastChild
+import com.tari.android.wallet.ui.extension.gone
+import com.tari.android.wallet.ui.extension.hideKeyboard
+import com.tari.android.wallet.ui.extension.invisible
+import com.tari.android.wallet.ui.extension.parcelable
+import com.tari.android.wallet.ui.extension.setLayoutSize
+import com.tari.android.wallet.ui.extension.setTextSizePx
+import com.tari.android.wallet.ui.extension.setVisible
+import com.tari.android.wallet.ui.extension.string
+import com.tari.android.wallet.ui.extension.temporarilyDisableClick
+import com.tari.android.wallet.ui.extension.visible
import com.tari.android.wallet.ui.fragment.contact_book.data.contacts.ContactDto
import com.tari.android.wallet.ui.fragment.tx.details.gif.GIFView
import com.tari.android.wallet.ui.fragment.tx.details.gif.GIFViewModel
import com.tari.android.wallet.ui.fragment.tx.details.gif.TxState
import com.tari.android.wallet.util.WalletUtil
-import java.util.*
+import java.util.Date
/**
* Activity class - Transaction detail.
@@ -92,6 +132,8 @@ class TxDetailsFragment : CommonFragment Boolean = { false }
val nameModule = InputModule(name, resourceManager.getString(R.string.contact_book_add_contact_first_name_hint), true, false) { saveAction.invoke() }
- val surnameModule =
- InputModule(surname, resourceManager.getString(R.string.contact_book_add_contact_surname_hint), false, phoneDto == null) { saveAction.invoke() }
val headModule = HeadModule(
resourceManager.getString(R.string.contact_book_details_edit_title),
rightButtonTitle = resourceManager.getString(R.string.contact_book_add_contact_done_button)
) { saveAction.invoke() }
- val moduleList = mutableListOf(headModule, nameModule, surnameModule)
+ val moduleList = mutableListOf(headModule, nameModule)
saveAction = {
- saveDetails(nameModule.value, surnameModule.value)
+ saveDetails(nameModule.value)
true
}
@@ -195,7 +191,10 @@ class TxDetailsViewModel : CommonViewModel() {
_inputDialog.postValue(args)
}
- private fun saveDetails(name: String, surname: String = "") {
+ private fun saveDetails(newName: String) {
+ val split = newName.split(" ")
+ val name = split.getOrNull(0).orEmpty().trim()
+ val surname = split.getOrNull(1).orEmpty().trim()
val contact = contact.value!!
this.contact.value = contactsRepository.updateContactInfo(contact, name, surname, contact.getYatDto()?.yat.orEmpty())
dismissDialog.postValue(Unit)
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/gif/GIFView.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/gif/GIFView.kt
index 616c59a13..6aac4fae9 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/gif/GIFView.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/tx/details/gif/GIFView.kt
@@ -99,7 +99,7 @@ class GIFView(
override fun onLoadFailed(
e: GlideException?,
model: Any?,
- target: Target?,
+ target: Target,
isFirstResource: Boolean
): Boolean {
onFailure()
@@ -107,10 +107,10 @@ class GIFView(
}
override fun onResourceReady(
- resource: GifDrawable?,
- model: Any?,
+ resource: GifDrawable,
+ model: Any,
target: Target?,
- dataSource: DataSource?,
+ dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
hideDownloadingUI()
diff --git a/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListFragment.kt b/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListFragment.kt
index 6672a0480..1342831ac 100644
--- a/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListFragment.kt
+++ b/app/src/main/java/com/tari/android/wallet/ui/fragment/utxos/list/UtxosListFragment.kt
@@ -14,6 +14,7 @@ import com.tari.android.wallet.extension.observeOnLoad
import com.tari.android.wallet.ui.common.CommonFragment
import com.tari.android.wallet.ui.common.recyclerView.CommonAdapter
import com.tari.android.wallet.ui.extension.gone
+import com.tari.android.wallet.ui.extension.hideKeyboard
import com.tari.android.wallet.ui.extension.setVisible
import com.tari.android.wallet.ui.extension.visible
import com.tari.android.wallet.ui.fragment.utxos.list.adapters.UtxosListAdapter
@@ -43,6 +44,8 @@ class UtxosListFragment : CommonFragment>>>>>> cb06ea1bc7c0b86add6505cb8e8235be91f6dd50
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt b/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt
index fece16d14..ebafbc166 100644
--- a/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt
+++ b/app/src/main/java/com/tari/android/wallet/yat/YatAdapter.kt
@@ -33,7 +33,7 @@ class YatAdapter(
fun initYat(application: Application) {
val config = YatConfiguration(BuildConfig.YAT_ORGANIZATION_RETURN_URL, BuildConfig.YAT_ORGANIZATION_NAME, BuildConfig.YAT_ORGANIZATION_KEY)
- YatIntegration.setup(application, config, YatIntegration.ColorMode.LIGHT, this, environment = YatIntegration.Environment.SandBox)
+ YatIntegration.setup(application, config, YatIntegration.ColorMode.LIGHT, this, environment = YatIntegration.Environment.Production)
}
fun searchTariYats(query: String): PaymentAddressResponse? =
diff --git a/app/src/main/res/drawable-xhdpi/tari_fingerprint.png b/app/src/main/res/drawable-xhdpi/tari_fingerprint.png
deleted file mode 100644
index f1baa7350..000000000
Binary files a/app/src/main/res/drawable-xhdpi/tari_fingerprint.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/tari_numpad.png b/app/src/main/res/drawable-xhdpi/tari_numpad.png
deleted file mode 100644
index a4b9f36d3..000000000
Binary files a/app/src/main/res/drawable-xhdpi/tari_numpad.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/tari_fingerprint.png b/app/src/main/res/drawable-xxhdpi/tari_fingerprint.png
deleted file mode 100644
index 483ddfbe4..000000000
Binary files a/app/src/main/res/drawable-xxhdpi/tari_fingerprint.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/tari_numpad.png b/app/src/main/res/drawable-xxhdpi/tari_numpad.png
deleted file mode 100644
index 4c977499c..000000000
Binary files a/app/src/main/res/drawable-xxhdpi/tari_numpad.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/tari_fingerprint.png b/app/src/main/res/drawable-xxxhdpi/tari_fingerprint.png
deleted file mode 100644
index 278583923..000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/tari_fingerprint.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/tari_numpad.png b/app/src/main/res/drawable-xxxhdpi/tari_numpad.png
deleted file mode 100644
index 2e837bfbb..000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/tari_numpad.png and /dev/null differ
diff --git a/app/src/main/res/drawable/vector_all_settings_bluetooth.xml b/app/src/main/res/drawable/vector_all_settings_bluetooth.xml
index eeeadecad..9b3fd82e8 100644
--- a/app/src/main/res/drawable/vector_all_settings_bluetooth.xml
+++ b/app/src/main/res/drawable/vector_all_settings_bluetooth.xml
@@ -1,10 +1,14 @@
-
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_all_settings_card.xml b/app/src/main/res/drawable/vector_all_settings_card.xml
new file mode 100644
index 000000000..17a2c01b8
--- /dev/null
+++ b/app/src/main/res/drawable/vector_all_settings_card.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_all_settings_cart.xml b/app/src/main/res/drawable/vector_all_settings_cart.xml
new file mode 100644
index 000000000..90ae7eb8d
--- /dev/null
+++ b/app/src/main/res/drawable/vector_all_settings_cart.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_all_settings_data_collection.xml b/app/src/main/res/drawable/vector_all_settings_data_collection.xml
new file mode 100644
index 000000000..992e1d05f
--- /dev/null
+++ b/app/src/main/res/drawable/vector_all_settings_data_collection.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_all_settings_passcode.xml b/app/src/main/res/drawable/vector_all_settings_passcode.xml
new file mode 100644
index 000000000..23315e409
--- /dev/null
+++ b/app/src/main/res/drawable/vector_all_settings_passcode.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_chat_add.xml b/app/src/main/res/drawable/vector_chat_add.xml
new file mode 100644
index 000000000..3cceafa7d
--- /dev/null
+++ b/app/src/main/res/drawable/vector_chat_add.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_chat_empty_list.xml b/app/src/main/res/drawable/vector_chat_empty_list.xml
new file mode 100644
index 000000000..dd74a30d7
--- /dev/null
+++ b/app/src/main/res/drawable/vector_chat_empty_list.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_chat_empty_messages.xml b/app/src/main/res/drawable/vector_chat_empty_messages.xml
new file mode 100644
index 000000000..183474c4f
--- /dev/null
+++ b/app/src/main/res/drawable/vector_chat_empty_messages.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_chat_input_attach.xml b/app/src/main/res/drawable/vector_chat_input_attach.xml
new file mode 100644
index 000000000..a4a2fefe6
--- /dev/null
+++ b/app/src/main/res/drawable/vector_chat_input_attach.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_chat_input_send.xml b/app/src/main/res/drawable/vector_chat_input_send.xml
new file mode 100644
index 000000000..e7177d556
--- /dev/null
+++ b/app/src/main/res/drawable/vector_chat_input_send.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_chat_unread_count.xml b/app/src/main/res/drawable/vector_chat_unread_count.xml
new file mode 100644
index 000000000..b597d4872
--- /dev/null
+++ b/app/src/main/res/drawable/vector_chat_unread_count.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_disable_able_gradient_button_bg_external_dark.xml b/app/src/main/res/drawable/vector_disable_able_gradient_button_bg_external_dark.xml
new file mode 100644
index 000000000..49bd3d5f5
--- /dev/null
+++ b/app/src/main/res/drawable/vector_disable_able_gradient_button_bg_external_dark.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/vector_fingerprint.xml b/app/src/main/res/drawable/vector_fingerprint.xml
new file mode 100644
index 000000000..dcc26f7a2
--- /dev/null
+++ b/app/src/main/res/drawable/vector_fingerprint.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/vector_home_book.xml b/app/src/main/res/drawable/vector_home_book.xml
new file mode 100644
index 000000000..617523c44
--- /dev/null
+++ b/app/src/main/res/drawable/vector_home_book.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_home_chat.xml b/app/src/main/res/drawable/vector_home_chat.xml
new file mode 100644
index 000000000..d9166c284
--- /dev/null
+++ b/app/src/main/res/drawable/vector_home_chat.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_home_home.xml b/app/src/main/res/drawable/vector_home_home.xml
new file mode 100644
index 000000000..0859731df
--- /dev/null
+++ b/app/src/main/res/drawable/vector_home_home.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_home_menu.xml b/app/src/main/res/drawable/vector_home_menu.xml
new file mode 100644
index 000000000..9502a91ef
--- /dev/null
+++ b/app/src/main/res/drawable/vector_home_menu.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/vector_pin_input_background.xml b/app/src/main/res/drawable/vector_pin_input_background.xml
new file mode 100644
index 000000000..fce539ef3
--- /dev/null
+++ b/app/src/main/res/drawable/vector_pin_input_background.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/vector_pin_input_dot_error.xml b/app/src/main/res/drawable/vector_pin_input_dot_error.xml
new file mode 100644
index 000000000..6c2eefb8b
--- /dev/null
+++ b/app/src/main/res/drawable/vector_pin_input_dot_error.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/vector_pin_input_dot_normal.xml b/app/src/main/res/drawable/vector_pin_input_dot_normal.xml
new file mode 100644
index 000000000..f6111ed5b
--- /dev/null
+++ b/app/src/main/res/drawable/vector_pin_input_dot_normal.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/vector_wallet_wallet.xml b/app/src/main/res/drawable/vector_wallet_wallet.xml
new file mode 100644
index 000000000..a8dd386ff
--- /dev/null
+++ b/app/src/main/res/drawable/vector_wallet_wallet.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/vector_wallet_yat.xml b/app/src/main/res/drawable/vector_wallet_yat.xml
new file mode 100644
index 000000000..7a8676072
--- /dev/null
+++ b/app/src/main/res/drawable/vector_wallet_yat.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_auth.xml b/app/src/main/res/layout/activity_auth.xml
index 0293a2b2c..cfaa55542 100644
--- a/app/src/main/res/layout/activity_auth.xml
+++ b/app/src/main/res/layout/activity_auth.xml
@@ -1,66 +1,46 @@
-
+ android:layout_height="match_parent">
-
-
-
-
-
+
-
-
-
+
+
+
+
+
-
+
-
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
index 4bbf78298..222bf3f52 100644
--- a/app/src/main/res/layout/activity_home.xml
+++ b/app/src/main/res/layout/activity_home.xml
@@ -58,7 +58,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:src="@drawable/vector_home_icon" />
+ android:src="@drawable/vector_home_home" />
+ android:src="@drawable/vector_home_book" />
+ android:src="@drawable/vector_home_chat" />
+ android:src="@drawable/vector_home_menu" />
@@ -113,12 +113,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_chat.xml b/app/src/main/res/layout/fragment_chat.xml
new file mode 100644
index 000000000..7c1f8c7a9
--- /dev/null
+++ b/app/src/main/res/layout/fragment_chat.xml
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_chat_list.xml b/app/src/main/res/layout/fragment_chat_list.xml
new file mode 100644
index 000000000..281e5ec09
--- /dev/null
+++ b/app/src/main/res/layout/fragment_chat_list.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_contact_book_root.xml b/app/src/main/res/layout/fragment_contact_book_root.xml
index aa2c8d674..276f5aa41 100644
--- a/app/src/main/res/layout/fragment_contact_book_root.xml
+++ b/app/src/main/res/layout/fragment_contact_book_root.xml
@@ -163,11 +163,13 @@
+ app:queryBackground="@null"
+ tools:text="Search"/>
diff --git a/app/src/main/res/layout/fragment_contacts_selection.xml b/app/src/main/res/layout/fragment_contacts_selection.xml
index cc5a02c0a..99932c2b9 100644
--- a/app/src/main/res/layout/fragment_contacts_selection.xml
+++ b/app/src/main/res/layout/fragment_contacts_selection.xml
@@ -33,15 +33,6 @@
android:visibility="gone"
app:hintText="@string/contact_book_add_contact_first_name_hint" />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_enter_pincode.xml b/app/src/main/res/layout/fragment_enter_pincode.xml
new file mode 100644
index 000000000..4b767a7c9
--- /dev/null
+++ b/app/src/main/res/layout/fragment_enter_pincode.xml
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_feature_auth.xml b/app/src/main/res/layout/fragment_feature_auth.xml
new file mode 100644
index 000000000..0cdf4f9dc
--- /dev/null
+++ b/app/src/main/res/layout/fragment_feature_auth.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index cfbecfe2c..4e256b03a 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -195,14 +195,6 @@
android:layout_marginTop="-4dp"
android:orientation="horizontal">
-
-
diff --git a/app/src/main/res/layout/fragment_local_auth.xml b/app/src/main/res/layout/fragment_local_auth.xml
index b6565f0b6..99fcd3f7a 100644
--- a/app/src/main/res/layout/fragment_local_auth.xml
+++ b/app/src/main/res/layout/fragment_local_auth.xml
@@ -2,116 +2,154 @@
+
+
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:translationY="-10dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
-
-
-
+ android:layout_marginTop="50dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+ android:padding="24dp">
+ android:src="@drawable/vector_all_settings_passcode"
+ android:tint="?attr/palette_brand_purple"
+ tools:alpha="1" />
-
-
-
+ android:src="@drawable/vector_fingerprint"
+ android:tint="?attr/palette_brand_purple"
+ tools:alpha="1" />
-
+
+
+
-
+ android:layout_height="wrap_content"
+ android:layout_below="@id/prompt_text_view"
+ android:layout_gravity="center"
+ android:layout_marginHorizontal="@dimen/common_horizontal_margin"
+ android:alpha="0"
+ android:gravity="center"
+ android:letterSpacing="-0.02"
+ android:lineSpacingExtra="10dp"
+ android:text="@string/auth_prompt_desc"
+ android:textColor="?attr/palette_text_body"
+ android:textSize="14sp"
+ android:visibility="visible"
+ app:customFont="medium" />
-
+
-
-
+
-
+
+
+
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_tx_details.xml b/app/src/main/res/layout/fragment_tx_details.xml
index fa176ff29..5e50416f5 100644
--- a/app/src/main/res/layout/fragment_tx_details.xml
+++ b/app/src/main/res/layout/fragment_tx_details.xml
@@ -172,10 +172,11 @@
android:gravity="center_horizontal"
android:orientation="vertical">
-
@@ -184,21 +185,27 @@
android:id="@+id/amount_gem_image_view"
android:layout_width="@dimen/add_amount_gem_size"
android:layout_height="@dimen/add_amount_gem_size"
- android:layout_centerVertical="true"
+ android:layout_gravity="center_vertical"
android:layout_marginEnd="6dp"
- android:layout_toStartOf="@id/amount_text_view"
android:src="@drawable/vector_gem" />
-
+ tools:text="150.000000000000000" />
+
+
+
+ android:layout_height="match_parent"
+ tools:visibility="gone" />
diff --git a/app/src/main/res/layout/fragment_wallet_info.xml b/app/src/main/res/layout/fragment_wallet_info.xml
index e5329ed82..b93d63aa8 100644
--- a/app/src/main/res/layout/fragment_wallet_info.xml
+++ b/app/src/main/res/layout/fragment_wallet_info.xml
@@ -66,36 +66,88 @@
android:layout_gravity="center" />
+ app:customFont="black" />
+
+
+
+
+
+
+
+
+
+
+
+
+ app:customFont="medium" />
-
-
diff --git a/app/src/main/res/layout/item_chat_cell.xml b/app/src/main/res/layout/item_chat_cell.xml
new file mode 100644
index 000000000..7db992acf
--- /dev/null
+++ b/app/src/main/res/layout/item_chat_cell.xml
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_chat_item.xml b/app/src/main/res/layout/item_chat_item.xml
new file mode 100644
index 000000000..d2de840ff
--- /dev/null
+++ b/app/src/main/res/layout/item_chat_item.xml
@@ -0,0 +1,235 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_home_tx_list.xml b/app/src/main/res/layout/item_home_tx_list.xml
index f7a8e70c4..058b4080b 100644
--- a/app/src/main/res/layout/item_home_tx_list.xml
+++ b/app/src/main/res/layout/item_home_tx_list.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_view"
android:layout_width="match_parent"
- android:layout_height="60dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/tari_home_tx_bg"
android:clickable="true"
@@ -16,6 +16,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
+ android:paddingVertical="16dp"
android:paddingHorizontal="10dp">
+
+
+ app:customFont="heavy"
+ tools:visibility="gone" />
+
+
+
80dp
22dp
+ 46dp
+ 12dp
+ 14dp
+
diff --git a/app/src/main/res/values/light_colors_palette.xml b/app/src/main/res/values/light_colors_palette.xml
index 1ff8785b1..72bec2989 100644
--- a/app/src/main/res/values/light_colors_palette.xml
+++ b/app/src/main/res/values/light_colors_palette.xml
@@ -3,7 +3,7 @@
#FFFFFF
#F6F6F6
- #ECECEC
+ #EEEEF0
#E1E1E1
@@ -48,7 +48,7 @@
#FFFFFF
- #F6F6F6
+ #F5F5F7
#000000
diff --git a/app/src/main/res/values/palette_styles.xml b/app/src/main/res/values/palette_styles.xml
index 57a24963c..99e29787e 100644
--- a/app/src/main/res/values/palette_styles.xml
+++ b/app/src/main/res/values/palette_styles.xml
@@ -3,6 +3,7 @@
+
+