diff --git a/.idea/.name b/.idea/.name index d0206d0f3..72af3841f 100644 --- a/.idea/.name +++ b/.idea/.name @@ -1 +1 @@ -Tonkeeper R \ No newline at end of file +TON Apps \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23db..f1044879e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ + - + diff --git a/apps/signer/build.gradle.kts b/apps/signer/build.gradle.kts index a12e3e680..fed26c3ee 100644 --- a/apps/signer/build.gradle.kts +++ b/apps/signer/build.gradle.kts @@ -9,11 +9,11 @@ android { compileSdk = Build.compileSdkVersion defaultConfig { - applicationId = "com.tonapps.signer" + applicationId = Build.namespacePrefix("signer") minSdk = Build.minSdkVersion targetSdk = 34 - versionCode = 8 - versionName = "0.0.8" + versionCode = 10 + versionName = "0.1.0" } lint { @@ -68,6 +68,7 @@ dependencies { implementation(Dependence.AndroidX.fragment) implementation(Dependence.AndroidX.recyclerView) implementation(Dependence.AndroidX.viewPager2) + implementation(Dependence.AndroidX.splashscreen) implementation(Dependence.UI.material) implementation(Dependence.AndroidX.Camera.base) diff --git a/apps/signer/src/main/AndroidManifest.xml b/apps/signer/src/main/AndroidManifest.xml index b69d17758..42c19eb6a 100644 --- a/apps/signer/src/main/AndroidManifest.xml +++ b/apps/signer/src/main/AndroidManifest.xml @@ -34,10 +34,11 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" + android:supportsRtl="false" android:theme="@style/Theme.Signer.Starting" android:hardwareAccelerated="true" - android:largeHeap="true"> + android:largeHeap="true" + android:localeConfig="@xml/locales_config"> @@ -64,7 +64,7 @@ diff --git a/apps/signer/src/main/ic_launcher-playstore.png b/apps/signer/src/main/ic_launcher-playstore.png index 75977e3a3..76640c8a1 100644 Binary files a/apps/signer/src/main/ic_launcher-playstore.png and b/apps/signer/src/main/ic_launcher-playstore.png differ diff --git a/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt b/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt index 02b05a203..50842f51d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.ton.api.pub.PublicKeyEd25519 +import org.ton.crypto.hex class KeyRepository( private val dataSource: KeyDataSource, @@ -27,6 +28,12 @@ class KeyRepository( init { Scope.repositories.launch(Dispatchers.IO) { + /*val testKey = KeyEntity( + id = 1, + name = "Test", + publicKey = PublicKeyEd25519(hex("db642e022c80911fe61f19eb4f22d7fb95c1ea0b589c0f74ecf0cbf6db746c13")) + ) + _keysEntityFlow.value = listOf(testKey)*/ _keysEntityFlow.value = dataSource.getEntities() } } @@ -43,10 +50,13 @@ class KeyRepository( _keysEntityFlow.value?.size ?: 0 } - fun findIdByPublicKey(publicKey: PublicKeyEd25519): Flow = flow { - val id = dataSource.findIdByPublicKey(publicKey) - emit(id) - }.filterNotNull() + fun findIdByPublicKey(publicKey: PublicKeyEd25519): Long? { + val id = dataSource.findIdByPublicKey(publicKey) ?: return null + if (0 >= id) { + return null + } + return id + } suspend fun setName(id: Long, name: String) = withContext(Dispatchers.IO) { dataSource.setName(id, name) diff --git a/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt b/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt index c232599bc..a882cd53b 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt @@ -19,11 +19,18 @@ object TKDeepLink { return builder.build() } - fun buildLinkUri(publicKey: PublicKeyEd25519, name: String): Uri { + fun buildLinkUri( + publicKey: PublicKeyEd25519, + name: String, + local: Boolean + ): Uri { val baseUri = Uri.parse("${APP_SCHEME}://signer/link") val builder = baseUri.buildUpon() builder.appendQueryParameter("pk", publicKey.base64()) builder.appendQueryParameter("name", name) + if (local) { + builder.appendQueryParameter("local", "true") + } return builder.build() } @@ -32,6 +39,7 @@ object TKDeepLink { val builder = baseUri.buildUpon() builder.appendQueryParameter("pk", publicKey.base64()) builder.appendQueryParameter("name", name) + builder.appendQueryParameter("local", "true") return builder.build() } diff --git a/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt b/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt index 0048c450b..df7e74f4d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt @@ -40,7 +40,7 @@ object Password { val dialog = PasswordDialog(context, ::trySend) dialog.setOnDismissListener { if (isActive) { - close(Throwable("User canceled")) + close(UserCancelThrowable ) } else { close() } @@ -48,4 +48,8 @@ object Password { dialog.show() awaitClose { dialog.destroy() } }.flowOn(Dispatchers.Main).take(1) + + object UserCancelThrowable : Throwable("User canceled") { + private fun readResolve(): Any = UserCancelThrowable + } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt index b891b8cfc..543db65bb 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt @@ -48,6 +48,7 @@ class CameraFragment: BaseFragment(R.layout.fragment_camera), BaseFragment.Botto } private var isFlashAvailable = false + private var isReady = false private val qrAnalyzer = QRImageAnalyzer() private val chunks = mutableListOf() @@ -95,6 +96,9 @@ class CameraFragment: BaseFragment(R.layout.fragment_camera), BaseFragment.Botto } private fun handleBarcode(barcode: Barcode) { + if (isReady) { + return + } val data = barcode.rawValue ?: return if (data.startsWith("${Key.SCHEME}://")) { @@ -108,12 +112,13 @@ class CameraFragment: BaseFragment(R.layout.fragment_camera), BaseFragment.Botto val uri = chunks.joinToString("").uriOrNull ?: return if (rootViewModel.processDeepLink(uri, false)) { + isReady = true finishDelay() } } private fun finishDelay() { - postDelayed(ModalView.animationDuration) { + postDelayed(300) { finish() } } diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt index 4ca16f44d..21ec4a3ee 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt @@ -2,6 +2,7 @@ package com.tonapps.signer.screen.create import android.graphics.Color import android.os.Bundle +import android.util.Log import android.view.View import androidx.core.view.doOnLayout import androidx.lifecycle.lifecycleScope @@ -53,6 +54,7 @@ class CreateFragment: BaseFragment(R.layout.fragment_create), BaseFragment.Swipe adapter = PagerAdapter(this, createViewModel.pages) pagerView = view.findViewById(R.id.pager) + pagerView.offscreenPageLimit = adapter.itemCount pagerView.isUserInputEnabled = false pagerView.adapter = adapter @@ -65,7 +67,7 @@ class CreateFragment: BaseFragment(R.layout.fragment_create), BaseFragment.Swipe private fun setPage(index: Int) { val currentIndex = pagerView.currentItem if (currentIndex != index) { - pagerView.setCurrentItem(index, true) + post { pagerView.setCurrentItem(index, true) } } } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt index eac9a59b6..b02e24a47 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt @@ -29,6 +29,10 @@ import kotlinx.coroutines.launch import org.ton.api.pk.PrivateKeyEd25519 import org.ton.mnemonic.Mnemonic import com.tonapps.security.tryCallGC +import com.tonapps.signer.extensions.authorizationRequiredError +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.withContext import javax.crypto.SecretKey class CreateViewModel( @@ -54,15 +58,19 @@ class CreateViewModel( add(PageType.Name) } - private val _onReady = Channel(Channel.BUFFERED) - val onReady: Flow = _onReady.receiveAsFlow() + private val _onReady = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + val onReady: Flow = _onReady.asSharedFlow() - private val _currentPage = MutableStateFlow(pages.first()) + private val _currentPage = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) val currentPage = _currentPage.asSharedFlow() private val _uiTopOffset = MutableStateFlow(0) val uiTopOffset = _uiTopOffset.asStateFlow() + init { + _currentPage.tryEmit(pages.first()) + } + fun pageIndex() = currentPage.map { pageIndex(it) } fun page(pageType: PageType) = currentPage.filter { it == pageType } @@ -98,22 +106,27 @@ class CreateViewModel( return true } - fun addKey(context: Context) { - viewModelScope.launch(Dispatchers.IO) { - try { - val name = args.name ?: throw IllegalStateException("Name is null") - val secret = masterSecret(context).single() - Password.setUnlock() - - if (import) { - val mnemonic = args.mnemonic ?: throw IllegalStateException("Mnemonic is null") - addNewKey(secret, name, mnemonic) - } else { - createNewKey(secret, name) - } - - _onReady.trySend(Unit) - } catch (e: Throwable) { + fun addKey(context: Context) = flow { + try { + val name = args.name ?: throw IllegalStateException("Name is null") + val secret = masterSecret(context).single() + Password.setUnlock() + + if (import) { + val mnemonic = args.mnemonic ?: throw IllegalStateException("Mnemonic is null") + addNewKey(secret, name, mnemonic) + } else { + createNewKey(secret, name) + } + + emit(true) + _onReady.tryEmit(Unit) + + } catch (e: Throwable) { + emit(false) + if (e is Password.UserCancelThrowable) { + context.authorizationRequiredError() + } else { CrashActivity.open(e, context) _currentPage.tryEmit(pages.first()) } @@ -131,14 +144,21 @@ class CreateViewModel( private fun createMasterSecret(password: CharArray) = flow { emit(vault.createMasterSecret(password)) - }.take(1) + }.take(1).flowOn(Dispatchers.IO) - private suspend fun createNewKey(secret: SecretKey, name: String) { + private suspend fun createNewKey( + secret: SecretKey, + name: String + ) = withContext(Dispatchers.IO) { val mnemonic = Mnemonic.generate() addNewKey(secret, name, mnemonic) } - private suspend fun addNewKey(secret: SecretKey, name: String, mnemonic: List) { + private suspend fun addNewKey( + secret: SecretKey, + name: String, + mnemonic: List + ) = withContext(Dispatchers.IO) { val seed = Mnemonic.toSeed(mnemonic) val publicKey = PrivateKeyEd25519(seed).publicKey() diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt index 598936d01..d592e7e6d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt @@ -1,12 +1,15 @@ package com.tonapps.signer.screen.create.child import android.os.Bundle +import android.util.Log import android.view.View import android.widget.Button import androidx.lifecycle.lifecycleScope import com.tonapps.signer.R +import com.tonapps.signer.extensions.authorizationRequiredError import com.tonapps.signer.screen.create.CreateViewModel import com.tonapps.signer.screen.create.pager.PageType +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.koin.androidx.viewmodel.ext.android.getViewModel @@ -56,6 +59,10 @@ class CreateNameFragment: BaseFragment(R.layout.fragment_create_name) { nameInput.focus() } + collectFlow(createViewModel.page(PageType.RepeatPassword)) { + nameInput.clear() + } + collectFlow(createViewModel.uiTopOffset) { contentView.setPaddingTop(it) } @@ -66,12 +73,23 @@ class CreateNameFragment: BaseFragment(R.layout.fragment_create_name) { if (name.isBlank()) { return } - createViewModel.setName(name) - createViewModel.addKey(requireContext()) + collectFlow(createViewModel.addKey(requireContext())) { done -> + if (!done) { + applyDefaultState() + } + } + applyLoadingState() + } + private fun applyLoadingState() { loaderView.visibility = View.VISIBLE doneButton.visibility = View.GONE nameInput.hideKeyboard() } + + private fun applyDefaultState() { + loaderView.visibility = View.GONE + doneButton.visibility = View.VISIBLE + } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt index 903cd2d5b..525264925 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt @@ -83,6 +83,12 @@ class CreatePasswordFragment : BaseFragment(R.layout.fragment_create_password) { passwordInput.focusWithKeyboard() } + if (isRepeat) { + collectFlow(createViewModel.page(PageType.Password)) { + passwordInput.clear() + } + } + collectFlow(createViewModel.uiTopOffset) { contentView.setPaddingTop(it) } diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt index 8655b52f1..89974c39d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt @@ -114,11 +114,10 @@ class KeyFragment: BaseFragment(R.layout.fragment_key), BaseFragment.SwipeBack { } private fun setExportByUri(publicKey: PublicKeyEd25519, name: String) { - val uri = TKDeepLink.buildLinkUri(publicKey, name) - qrView.setContent(uri.toString()) + qrView.setContent(TKDeepLink.buildLinkUri(publicKey, name, false).toString()) exportTonkeeperView.setOnClickListener { - TKDeepLink.openOrInstall(requireContext(), uri) + TKDeepLink.openOrInstall(requireContext(), TKDeepLink.buildLinkUri(publicKey, name, true)) } exportTonkeeperWebView.setOnClickListener { diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt new file mode 100644 index 000000000..6d50b4d02 --- /dev/null +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt @@ -0,0 +1,31 @@ +package com.tonapps.signer.screen.legal + +import android.os.Bundle +import android.view.View +import com.tonapps.signer.R +import uikit.base.BaseFragment +import uikit.navigation.Navigation.Companion.navigation +import uikit.widget.HeaderView + +class LegalFragment: BaseFragment(R.layout.fragment_legal), BaseFragment.SwipeBack { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val header = view.findViewById(R.id.header) + header.doOnCloseClick = { finish() } + + val termsView = view.findViewById(R.id.terms) + termsView.setOnClickListener { + navigation?.openURL("https://tonkeeper.com/terms", true) + } + + val privacyView = view.findViewById(R.id.privacy) + privacyView.setOnClickListener { + navigation?.openURL("https://tonkeeper.com/privacy", true) + } + } + + companion object { + fun newInstance() = LegalFragment() + } +} \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt index 75ea797b3..175092311 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt @@ -16,6 +16,7 @@ import com.tonapps.signer.SimpleState import com.tonapps.signer.extensions.toast import com.tonapps.signer.password.Password import com.tonapps.signer.password.ui.PasswordView +import com.tonapps.signer.screen.crash.CrashActivity import com.tonapps.signer.screen.intro.IntroFragment import com.tonapps.signer.screen.main.MainFragment import com.tonapps.signer.screen.root.action.RootAction @@ -138,12 +139,29 @@ class RootActivity: NavigationActivity() { private fun onAction(action: RootAction) { when (action) { - is RootAction.RequestBodySign -> add(SignFragment.newInstance(action.id, action.body, action.v, action.returnResult)) + is RootAction.RequestBodySign -> requestSign(action) is RootAction.ResponseBoc -> responseBoc(action.boc) is RootAction.ResponseKey -> responseKey(action.publicKey, action.name) } } + private fun requestSign(request: RootAction.RequestBodySign) { + removeSignSheets { + add(SignFragment.newInstance(request.id, request.body, request.v, request.returnResult)) + } + } + + private fun removeSignSheets(runnable: Runnable) { + val transaction = supportFragmentManager.beginTransaction() + supportFragmentManager.fragments.forEach { + if (it is SignFragment) { + transaction.remove(it) + } + } + transaction.runOnCommit(runnable) + transaction.commitNow() + } + private fun responseBoc(boc: String) { val intent = Intent() intent.putExtra(Key.BOC, boc) @@ -207,14 +225,18 @@ class RootActivity: NavigationActivity() { checkPasswordJob?.cancel() } - /*override fun onWindowFocusChanged(hasFocus: Boolean) { + override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) + if (BuildConfig.DEBUG) { + return + } + if (hasFocus) { baseContainer.visibility = View.VISIBLE } else { baseContainer.visibility = View.GONE } - }*/ + } override fun onResume() { super.onResume() diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt index b0a7ceb0a..85bbd2c82 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt @@ -11,7 +11,10 @@ import com.tonapps.signer.password.Password import com.tonapps.signer.screen.root.action.RootAction import com.tonapps.signer.vault.SignerVault import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -22,6 +25,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch import org.ton.cell.Cell +import uikit.extensions.collectFlow class RootViewModel( private val vault: SignerVault, @@ -32,8 +36,8 @@ class RootViewModel( it.isNotEmpty() }.distinctUntilChanged() - private val _action = Channel(Channel.BUFFERED) - val action = _action.receiveAsFlow() + private val _action = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + val action = _action.asSharedFlow() fun checkPassword(password: CharArray) = flow { val valid = vault.isValidPassword(password) @@ -51,7 +55,7 @@ class RootViewModel( } fun responseSignedBoc(boc: String) { - _action.trySend(RootAction.ResponseBoc(boc)) + _action.tryEmit(RootAction.ResponseBoc(boc)) } fun processDeepLink(uri: Uri, fromApp: Boolean): Boolean { @@ -71,17 +75,13 @@ class RootViewModel( } private fun signRequest(signRequest: SignRequestEntity) { - keyRepository.findIdByPublicKey(signRequest.publicKey).onEach { id -> + viewModelScope.launch(Dispatchers.IO) { + val id = keyRepository.findIdByPublicKey(signRequest.publicKey) ?: return@launch sign(id, signRequest.body, signRequest.v, signRequest.returnResult) - }.launchIn(viewModelScope) + } } private fun sign(id: Long, body: Cell, v: String, returnResult: ReturnResultEntity) { - _action.trySend(RootAction.RequestBodySign(id, body, v, returnResult)) - } - - override fun onCleared() { - super.onCleared() - _action.close() + _action.tryEmit(RootAction.RequestBodySign(id, body, v, returnResult)) } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt index 2360b4ea7..655748ef2 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt @@ -10,6 +10,7 @@ import com.tonapps.signer.BuildConfig import com.tonapps.signer.R import com.tonapps.signer.screen.change.ChangeFragment import com.tonapps.signer.screen.debug.DebugFragment +import com.tonapps.signer.screen.legal.LegalFragment import uikit.base.BaseFragment import uikit.navigation.Navigation.Companion.navigation import uikit.widget.HeaderView @@ -24,6 +25,7 @@ class SettingsFragment: BaseFragment(R.layout.fragment_settings), BaseFragment.S private lateinit var scrollView: NestedScrollView private lateinit var changeView: View private lateinit var supportView: View + private lateinit var legalView: View private lateinit var versionView: AppCompatTextView override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -39,6 +41,11 @@ class SettingsFragment: BaseFragment(R.layout.fragment_settings), BaseFragment.S supportView = view.findViewById(R.id.support) supportView.setOnClickListener { openSupport() } + legalView = view.findViewById(R.id.legal) + legalView.setOnClickListener { + navigation?.add(LegalFragment.newInstance()) + } + versionView = view.findViewById(R.id.version) versionView.text = getString(R.string.version, BuildConfig.VERSION_NAME) versionView.setOnClickListener { @@ -47,8 +54,8 @@ class SettingsFragment: BaseFragment(R.layout.fragment_settings), BaseFragment.S } private fun openSupport() { - val uri = Uri.parse("mailto:support@tonkeeper.com") - val intent = Intent(Intent.ACTION_SENDTO, uri) + val uri = Uri.parse("https://t.me/tonkeeper_supportbot") + val intent = Intent(Intent.ACTION_VIEW, uri) startActivity(intent) } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt index 8f0e8e5d3..8abb4efbe 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt @@ -169,7 +169,7 @@ class SignFragment: BaseFragment(R.layout.fragment_sign), BaseFragment.Modal { } private fun finishDelay() { - postDelayed(ModalView.animationDuration) { + postDelayed(300) { finish() } } diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt index 0c09f0e12..ad2c66bdd 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt @@ -48,9 +48,7 @@ class SignViewModel( private val vault: SignerVault, ): ViewModel() { - val keyEntity = repository.getKey(id) - .filterNotNull() - .shareIn(viewModelScope, SharingStarted.Lazily, 1) + val keyEntity = repository.getKey(id).filterNotNull() private val _actionsFlow = MutableStateFlow?>(null) val actionsFlow = _actionsFlow.asStateFlow().filterNotNull() diff --git a/apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml b/apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..448c3f743 --- /dev/null +++ b/apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/signer/src/main/res/drawable/bg_intro.xml b/apps/signer/src/main/res/drawable/bg_intro.xml index 8d7802f60..b85517a7b 100644 --- a/apps/signer/src/main/res/drawable/bg_intro.xml +++ b/apps/signer/src/main/res/drawable/bg_intro.xml @@ -1,64 +1,79 @@ + android:width="200dp" + android:height="254dp" + android:viewportWidth="200" + android:viewportHeight="254"> - - - - - - - - - - - - - - - - - - - - - - - - - + android:pathData="m0,0.67h200v253.33h-200z"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/signer/src/main/res/drawable/bg_splash.xml b/apps/signer/src/main/res/drawable/bg_splash.xml index a2ac2d736..b5a0e99a2 100644 --- a/apps/signer/src/main/res/drawable/bg_splash.xml +++ b/apps/signer/src/main/res/drawable/bg_splash.xml @@ -1,8 +1,4 @@ - + \ No newline at end of file diff --git a/apps/signer/src/main/res/drawable/bg_wrong.xml b/apps/signer/src/main/res/drawable/bg_wrong.xml new file mode 100644 index 000000000..d1c0daf1f --- /dev/null +++ b/apps/signer/src/main/res/drawable/bg_wrong.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml b/apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml new file mode 100644 index 000000000..1b91ae97c --- /dev/null +++ b/apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/signer/src/main/res/drawable/ic_launcher_background.xml b/apps/signer/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..cbccc117c --- /dev/null +++ b/apps/signer/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/signer/src/main/res/drawable/ic_launcher_foreground.xml b/apps/signer/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index d329c683a..000000000 --- a/apps/signer/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/apps/signer/src/main/res/layout/fragment_add_key.xml b/apps/signer/src/main/res/layout/fragment_add_key.xml index 9f3b6387c..a7389302b 100644 --- a/apps/signer/src/main/res/layout/fragment_add_key.xml +++ b/apps/signer/src/main/res/layout/fragment_add_key.xml @@ -19,7 +19,7 @@ diff --git a/apps/signer/src/main/res/layout/fragment_camera.xml b/apps/signer/src/main/res/layout/fragment_camera.xml index 6773dff46..8ca8369e8 100644 --- a/apps/signer/src/main/res/layout/fragment_camera.xml +++ b/apps/signer/src/main/res/layout/fragment_camera.xml @@ -27,7 +27,7 @@ app:ignoreSystemOffset="true" android:icon="@drawable/ic_chevron_down_16"/> - + + - + diff --git a/apps/signer/src/main/res/layout/fragment_camera_permission.xml b/apps/signer/src/main/res/layout/fragment_camera_permission.xml index 9fa18b9a9..acc1e4b0a 100644 --- a/apps/signer/src/main/res/layout/fragment_camera_permission.xml +++ b/apps/signer/src/main/res/layout/fragment_camera_permission.xml @@ -23,7 +23,8 @@ android:layout_width="84dp" android:layout_height="84dp" android:layout_gravity="center" - android:src="@drawable/ic_camera_84"/> + android:src="@drawable/ic_camera_84" + android:tint="?attr/accentBlueColor"/> + + + + + + + + + + + android:layout_margin="@dimen/offsetLarge"> - - - + android:layout_marginHorizontal="@dimen/offsetMedium" + android:title="@string/app_name" + android:description="@string/intro_subtitle"/>