From b93e9625a81b25d766b27d4de9cde3fc81c4342c Mon Sep 17 00:00:00 2001 From: polstianka Date: Sat, 5 Oct 2024 08:35:52 -0700 Subject: [PATCH] push fixeds --- .../main/java/com/tonapps/wallet/api/API.kt | 34 ++++++----- .../wallet/data/backup/BackupRepository.kt | 8 --- .../wallet/data/dapps/DAppsRepository.kt | 1 + apps/wallet/instance/app/build.gradle.kts | 1 + .../instance/app/src/main/AndroidManifest.xml | 10 ++++ .../main/java/com/tonapps/tonkeeper/App.kt | 5 +- .../java/com/tonapps/tonkeeper/Environment.kt | 2 +- .../tonkeeper/deeplink/DeepLinkRoute.kt | 2 +- .../tonapps/tonkeeper/extensions/Context.kt | 4 ++ .../tonkeeper/koin/viewModelWalletModule.kt | 1 - .../tonapps/tonkeeper/koin/workerModule.kt | 9 +++ .../tonkeeper/manager/push/PushManager.kt | 19 +++--- .../manager/tonconnect/TonConnectManager.kt | 26 ++++---- .../manager/tonconnect/bridge/Bridge.kt | 1 + .../tonapps/tonkeeper/ui/base/BaseWalletVM.kt | 48 +++------------ .../tonkeeper/ui/component/WordEditText.kt | 3 +- .../ui/screen/browser/dapp/DAppViewModel.kt | 13 ++-- .../ui/screen/events/EventsViewModel.kt | 55 ++++++++--------- .../tonkeeper/ui/screen/init/InitViewModel.kt | 9 +-- .../ui/screen/init/step/WordsScreen.kt | 21 +++++-- .../NotificationsManageViewModel.kt | 10 +++- .../tonkeeper/ui/screen/root/RootViewModel.kt | 21 +++---- .../transaction/SendTransactionViewModel.kt | 10 ++-- .../screen/settings/main/SettingsViewModel.kt | 5 +- .../main/list/holder/SetupSwitchHolder.kt | 6 +- .../tonkeeper/worker/DAppPushToggleWorker.kt | 60 +++++++++++++++++++ .../com/tonapps/tonkeeper/worker/Extension.kt | 23 +++++++ .../tonkeeper/worker/PushToggleWorker.kt | 58 ++++++++++++++++++ buildSrc/src/main/kotlin/Dependence.kt | 33 +++++----- .../java/com/tonapps/extensions/BaseDialog.kt | 41 ------------- .../main/java/uikit/extensions/EditText.kt | 5 +- 31 files changed, 324 insertions(+), 220 deletions(-) create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/workerModule.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/DAppPushToggleWorker.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/Extension.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/PushToggleWorker.kt delete mode 100644 lib/extensions/src/main/java/com/tonapps/extensions/BaseDialog.kt diff --git a/apps/wallet/api/src/main/java/com/tonapps/wallet/api/API.kt b/apps/wallet/api/src/main/java/com/tonapps/wallet/api/API.kt index 825d918e2..85343c958 100644 --- a/apps/wallet/api/src/main/java/com/tonapps/wallet/api/API.kt +++ b/apps/wallet/api/src/main/java/com/tonapps/wallet/api/API.kt @@ -495,16 +495,14 @@ class API( clientId: String, body: String ) { - try { - val mimeType = "text/plain".toMediaType() - val url = "${BRIDGE_URL}/message?client_id=$publicKeyHex&to=$clientId&ttl=300" - val response = withRetry { - tonAPIHttpClient.post(url, body.toRequestBody(mimeType)) - } ?: throw Exception("Empty response") - if (!response.isSuccessful) { - throw Exception("Failed sending event[code=${response.code};body=${response.body?.string()}]") - } - } catch (e: Throwable) { } + val mimeType = "text/plain".toMediaType() + val url = "${BRIDGE_URL}/message?client_id=$publicKeyHex&to=$clientId&ttl=300" + val response = withRetry { + tonAPIHttpClient.post(url, body.toRequestBody(mimeType)) + } ?: throw Exception("Null response") + if (!response.isSuccessful) { + throw Exception("Failed sending event[code=${response.code};body=${response.body?.string()}]") + } } fun estimateGaslessCost( @@ -716,12 +714,16 @@ class API( json.put("silent", silent) val data = json.toString().replace("\\/", "/").trim() - return withRetry { - tonAPIHttpClient.postJSON(url, data, ArrayMap().apply { - set("X-TonConnect-Auth", token) - set("Connection", "close") - }).isSuccessful - } ?: false + val headers = ArrayMap().apply { + set("X-TonConnect-Auth", token) + set("Connection", "close") + } + + val response = withRetry { + tonAPIHttpClient.postJSON(url, data, headers) + } + + return response?.isSuccessful ?: false } fun pushTonconnectUnsubscribe( diff --git a/apps/wallet/data/backup/src/main/java/com/tonapps/wallet/data/backup/BackupRepository.kt b/apps/wallet/data/backup/src/main/java/com/tonapps/wallet/data/backup/BackupRepository.kt index acff20258..b19351473 100644 --- a/apps/wallet/data/backup/src/main/java/com/tonapps/wallet/data/backup/BackupRepository.kt +++ b/apps/wallet/data/backup/src/main/java/com/tonapps/wallet/data/backup/BackupRepository.kt @@ -89,12 +89,4 @@ class BackupRepository( addBackup(walletId, source, date) } } - - fun addBackupsAsync( - walletIds: List, - source: BackupEntity.Source = BackupEntity.Source.LOCAL, - date: Long = System.currentTimeMillis() - ) { - scope.launch(Dispatchers.IO) { addBackups(walletIds, source, date) } - } } \ No newline at end of file diff --git a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/DAppsRepository.kt b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/DAppsRepository.kt index daa8cb6e2..4e78bef9f 100644 --- a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/DAppsRepository.kt +++ b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/DAppsRepository.kt @@ -2,6 +2,7 @@ package com.tonapps.wallet.data.dapps import android.content.Context import android.net.Uri +import android.util.Log import androidx.collection.ArrayMap import androidx.core.net.toUri import com.tonapps.blockchain.ton.extensions.toRawAddress diff --git a/apps/wallet/instance/app/build.gradle.kts b/apps/wallet/instance/app/build.gradle.kts index 8a7aedae7..9def5a8fd 100644 --- a/apps/wallet/instance/app/build.gradle.kts +++ b/apps/wallet/instance/app/build.gradle.kts @@ -30,6 +30,7 @@ android { dependencies { implementation(Dependence.Koin.core) + implementation(Dependence.Koin.workmanager) implementation(Dependence.KotlinX.datetime) implementation(Dependence.j2objc) implementation(Dependence.cbor) diff --git a/apps/wallet/instance/app/src/main/AndroidManifest.xml b/apps/wallet/instance/app/src/main/AndroidManifest.xml index aa4da4608..23eb60cec 100644 --- a/apps/wallet/instance/app/src/main/AndroidManifest.xml +++ b/apps/wallet/instance/app/src/main/AndroidManifest.xml @@ -145,6 +145,16 @@ + + + \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/App.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/App.kt index 6c0ad466d..148aeeab0 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/App.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/App.kt @@ -17,6 +17,7 @@ import com.tonapps.extensions.setLocales import com.tonapps.icu.CurrencyFormatter import com.tonapps.tonkeeper.koin.koinModel import com.tonapps.tonkeeper.koin.viewModelWalletModule +import com.tonapps.tonkeeper.koin.workerModule import com.tonapps.tonkeeperx.BuildConfig import com.tonapps.wallet.api.apiModule import com.tonapps.wallet.data.account.accountModule @@ -39,6 +40,7 @@ import com.tonapps.wallet.data.settings.SettingsRepository import com.tonapps.wallet.data.staking.stakingModule import org.koin.core.component.KoinComponent import org.koin.android.ext.android.inject +import org.koin.androidx.workmanager.koin.workManagerFactory import java.util.concurrent.Executors class App: Application(), CameraXConfig.Provider, KoinComponent { @@ -72,7 +74,8 @@ class App: Application(), CameraXConfig.Provider, KoinComponent { instance = this startKoin { androidContext(this@App) - modules(koinModel, dAppsModule, viewModelWalletModule, purchaseModule, batteryModule, stakingModule, passcodeModule, rnLegacyModule, backupModule, dataModule, browserModule, apiModule, accountModule, ratesModule, tokenModule, eventsModule, collectiblesModule) + modules(koinModel, workerModule, dAppsModule, viewModelWalletModule, purchaseModule, batteryModule, stakingModule, passcodeModule, rnLegacyModule, backupModule, dataModule, browserModule, apiModule, accountModule, ratesModule, tokenModule, eventsModule, collectiblesModule) + workManagerFactory() } setLocales(settingsRepository.localeList) AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/Environment.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/Environment.kt index 707128b9d..1fbb6d69d 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/Environment.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/Environment.kt @@ -16,7 +16,7 @@ class Environment(context: Context) { resultCode == ConnectionResult.SUCCESS } - val isGooglePlayBillingAvailable: Boolean by lazy { + val isGooglePlayAvailable: Boolean by lazy { installerSource == AppInstall.Source.GOOGLE_PLAY && isGooglePlayServicesAvailable } } \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/deeplink/DeepLinkRoute.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/deeplink/DeepLinkRoute.kt index 46a3f3ce6..e130ebe0f 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/deeplink/DeepLinkRoute.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/deeplink/DeepLinkRoute.kt @@ -142,7 +142,7 @@ sealed class DeepLinkRoute { val domain = uri.hostOrNull ?: return Unknown(uri) try { return when (domain) { - "backup" -> Backups + "backup", "backups" -> Backups "staking" -> Staking "buy-ton" -> Purchase "send" -> Send diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/extensions/Context.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/extensions/Context.kt index 8eb4ea843..ff83fedcf 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/extensions/Context.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/extensions/Context.kt @@ -15,6 +15,7 @@ import android.util.Log import androidx.annotation.ColorInt import androidx.annotation.StringRes import androidx.core.content.ContextCompat +import androidx.work.WorkManager import com.tonapps.blockchain.ton.contract.WalletVersion import com.tonapps.extensions.bestMessage import com.tonapps.tonkeeper.manager.tonconnect.TonConnectManager @@ -28,6 +29,9 @@ import com.tonapps.wallet.localization.Localization import uikit.navigation.Navigation import uikit.navigation.Navigation.Companion.navigation +val Context.workManager: WorkManager + get() = WorkManager.getInstance(this) + fun Context.safeExternalOpenUri(uri: Uri) { if (TonConnectManager.isTonConnectDeepLink(uri)) { return diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/viewModelWalletModule.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/viewModelWalletModule.kt index 09114d356..ed875f5f8 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/viewModelWalletModule.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/viewModelWalletModule.kt @@ -28,7 +28,6 @@ import com.tonapps.tonkeeper.ui.screen.staking.unstake.UnStakeViewModel import com.tonapps.tonkeeper.ui.screen.staking.stake.StakingViewModel import com.tonapps.tonkeeper.ui.screen.send.transaction.SendTransactionViewModel import com.tonapps.tonkeeper.ui.screen.staking.withdraw.StakeWithdrawViewModel -import org.koin.androidx.viewmodel.dsl.viewModel val viewModelWalletModule = module { viewModelOf(::WalletViewModel) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/workerModule.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/workerModule.kt new file mode 100644 index 000000000..57d7d1ed2 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/koin/workerModule.kt @@ -0,0 +1,9 @@ +package com.tonapps.tonkeeper.koin + +import com.tonapps.tonkeeper.worker.DAppPushToggleWorker +import org.koin.androidx.workmanager.dsl.workerOf +import org.koin.dsl.module + +val workerModule = module { + workerOf(::DAppPushToggleWorker) +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/push/PushManager.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/push/PushManager.kt index 5cb8d319b..f687d810d 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/push/PushManager.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/push/PushManager.kt @@ -1,6 +1,7 @@ package com.tonapps.tonkeeper.manager.push import android.content.Context +import android.util.Log import com.tonapps.extensions.locale import com.tonapps.wallet.api.API import com.tonapps.wallet.data.account.AccountRepository @@ -24,8 +25,14 @@ class PushManager( private val dAppsRepository: DAppsRepository, ) { - enum class State { - Enable, Disable, Delete + enum class State(val code: Int) { + Enable(1), Disable(0), Delete(-1); + + companion object { + fun of(code: Int): State { + return entries.firstOrNull { it.code == code } ?: Disable + } + } } fun newFirebaseToken() { @@ -36,14 +43,6 @@ class PushManager( } } - fun walletAsync(wallet: WalletEntity, state: State) { - scope.launch { wallet(wallet, state) } - } - - fun walletsAsync(wallets: List, state: State) { - scope.launch { wallets(wallets, state) } - } - suspend fun wallet(wallet: WalletEntity, state: State) = wallets(listOf(wallet), state) suspend fun wallets(wallets: List, state: State): Boolean = withContext(Dispatchers.IO) { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/TonConnectManager.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/TonConnectManager.kt index 140216ee4..eaec62e61 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/TonConnectManager.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/TonConnectManager.kt @@ -3,7 +3,6 @@ package com.tonapps.tonkeeper.manager.tonconnect import android.content.Context import android.net.Uri import android.util.ArrayMap -import android.util.Log import androidx.core.net.toUri import com.tonapps.blockchain.ton.extensions.equalsAddress import com.tonapps.blockchain.ton.proof.TONProof @@ -22,6 +21,7 @@ import com.tonapps.tonkeeper.manager.tonconnect.bridge.model.BridgeError import com.tonapps.tonkeeper.manager.tonconnect.bridge.model.BridgeMethod import com.tonapps.tonkeeper.manager.tonconnect.exceptions.ManifestException import com.tonapps.tonkeeper.ui.screen.tonconnect.TonConnectScreen +import com.tonapps.tonkeeper.worker.DAppPushToggleWorker import com.tonapps.wallet.api.API import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.dapps.DAppsRepository @@ -137,7 +137,7 @@ class TonConnectManager( proof: TONProof.Result?, pushEnabled: Boolean, type: AppConnectEntity.Type - ): AppConnectEntity { + ): AppConnectEntity = withContext(Dispatchers.IO) { val timestamp = proof?.timestamp ?: (System.currentTimeMillis() / 1000L) val connection = AppConnectEntity( accountId = wallet.accountId, @@ -154,15 +154,7 @@ class TonConnectManager( if (!dAppsRepository.newConnect(connection)) { throw Exception("Failed to save connection") } - setPushEnabled(wallet, appUrl, pushEnabled) - return connection - } - - suspend fun setPushEnabled(wallet: WalletEntity, appUrl: Uri, enabled: Boolean) { - val connections = dAppsRepository.setPushEnabled(wallet.accountId, wallet.testnet, appUrl, enabled) - if (!pushManager.dAppPush(wallet, connections, enabled)) { - dAppsRepository.setPushEnabled(wallet.accountId, wallet.testnet, appUrl, !enabled) - } + connection } fun processDeeplink( @@ -222,7 +214,7 @@ class TonConnectManager( ) val bundle = activity.addForResult(screen) val response = screen.contract.parseResult(bundle) - newConnect( + val connect = newConnect( wallet = response.wallet, keyPair = keyPair, clientId = clientId, @@ -231,6 +223,16 @@ class TonConnectManager( pushEnabled = response.notifications, type = if (tonConnect.jsInject) AppConnectEntity.Type.Internal else AppConnectEntity.Type.External ) + + activity.runOnUiThread { + DAppPushToggleWorker.run( + context = activity, + wallet = response.wallet, + appUrl = app.url, + enable = response.notifications + ) + } + JsonBuilder.connectEventSuccess( wallet = response.wallet, proof = response.proof, diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/Bridge.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/Bridge.kt index 405af279e..41e0e8a14 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/Bridge.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/Bridge.kt @@ -1,5 +1,6 @@ package com.tonapps.tonkeeper.manager.tonconnect.bridge +import android.util.Log import com.tonapps.blockchain.ton.proof.TONProof import com.tonapps.extensions.base64 import com.tonapps.extensions.optStringCompat diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/base/BaseWalletVM.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/base/BaseWalletVM.kt index bf001eb1c..4b7070d99 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/base/BaseWalletVM.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/base/BaseWalletVM.kt @@ -16,6 +16,7 @@ import com.tonapps.tonkeeper.extensions.showToast import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect @@ -24,6 +25,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.observeOn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import uikit.base.BaseFragment import uikit.navigation.Navigation import uikit.navigation.Navigation.Companion.navigation @@ -49,10 +51,6 @@ abstract class BaseWalletVM( val context: Context get() = holder?.uiContext ?: getApplication() - private val uiHandler: Handler by lazy { - Handler(context.mainLooper) - } - private val navigation: Navigation? get() = Navigation.from(context) @@ -68,18 +66,6 @@ abstract class BaseWalletVM( this.onEach { action(it) }.launch() } - fun Flow.safeCollectFlow(action: suspend (T) -> Unit) { - this.flowOn(Dispatchers.IO).onEach { action(it) }.catch { - toast(it.bestMessage) - }.launch() - } - - fun Flow.safeCollectFlowAtPost(action: (T) -> Unit) { - this.safeCollectFlow { - post { action(it) } - } - } - fun detachHolder() { holderRef?.clear() holderRef = null @@ -103,33 +89,15 @@ abstract class BaseWalletVM( } } - fun post(action: () -> Unit) { - uiHandler.post(action) - } - - fun postDelayed(delay: Long, runnable: Runnable) { - uiHandler.postDelayed(runnable, delay) - } - - fun cancelPost(runnable: Runnable) { - uiHandler.removeCallbacks(runnable) - } - - fun toast(@StringRes resId: Int) { - post { - context.showToast(resId) - } + suspend fun toast(@StringRes resId: Int) = withContext(Dispatchers.Main) { + context.showToast(resId) } - fun toast(text: String) { - post { - context.showToast(text) - } + suspend fun toast(text: String) = withContext(Dispatchers.Main) { + context.showToast(text) } - fun openScreen(screen: BaseFragment) { - post { - navigation?.add(screen) - } + suspend fun openScreen(screen: BaseFragment) = withContext(Dispatchers.Main) { + navigation?.add(screen) } } \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/WordEditText.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/WordEditText.kt index ee2ad8f04..06e83e146 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/WordEditText.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/WordEditText.kt @@ -10,6 +10,7 @@ import android.util.Log import android.util.TypedValue import android.view.KeyEvent import android.view.View +import androidx.appcompat.R import androidx.appcompat.widget.AppCompatEditText import androidx.core.content.res.ResourcesCompat import androidx.lifecycle.findViewTreeLifecycleOwner @@ -28,7 +29,7 @@ import uikit.extensions.setStartDrawable class WordEditText @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyle: Int = 0, + defStyle: Int = R.attr.editTextStyle, ) : AppCompatEditText(context, attrs, defStyle) { var doOnTextChanged: ((Editable) -> Unit)? = null diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/browser/dapp/DAppViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/browser/dapp/DAppViewModel.kt index f50a8e002..d79db038e 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/browser/dapp/DAppViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/browser/dapp/DAppViewModel.kt @@ -2,19 +2,17 @@ package com.tonapps.tonkeeper.ui.screen.browser.dapp import android.app.Application import android.net.Uri -import androidx.lifecycle.viewModelScope import com.tonapps.extensions.appVersionName import com.tonapps.extensions.filterList import com.tonapps.tonkeeper.manager.tonconnect.TonConnectManager import com.tonapps.tonkeeper.manager.tonconnect.bridge.JsonBuilder import com.tonapps.tonkeeper.manager.tonconnect.bridge.model.BridgeError import com.tonapps.tonkeeper.ui.base.BaseWalletVM +import com.tonapps.tonkeeper.worker.DAppPushToggleWorker import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.dapps.entities.AppConnectEntity -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch import org.json.JSONObject class DAppViewModel( @@ -29,9 +27,12 @@ class DAppViewModel( }.map { it.firstOrNull() } fun mute() { - viewModelScope.launch(Dispatchers.IO) { - tonConnectManager.setPushEnabled(wallet, url, false) - } + DAppPushToggleWorker.run( + context = context, + wallet = wallet, + appUrl = url, + enable = false + ) } fun disconnect() { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsViewModel.kt index 4b04fe43a..e4c3015da 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsViewModel.kt @@ -15,8 +15,11 @@ import com.tonapps.wallet.data.events.EventsRepository import com.tonapps.wallet.data.settings.SettingsRepository import io.tonapi.models.AccountEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update @@ -35,8 +38,7 @@ class EventsViewModel( private val transactionManager: TransactionManager, ): BaseWalletVM(app) { - private val autoRefreshRunnable = Runnable { checkAutoRefresh() } - + private var autoRefreshJob: Job? = null private var events: Array? = null private val isLoading: AtomicBoolean = AtomicBoolean(true) @@ -58,28 +60,26 @@ class EventsViewModel( updateState() } - transactionManager.eventsFlow(wallet).safeCollectFlowAtPost { event -> + transactionManager.eventsFlow(wallet).collectFlow { event -> if (event.pending) { appendEvent(AccountEventWrap(event.body)) } refresh() } - } - private fun checkAutoRefresh() { - val hasPendingEvents = hasPendingEvents() - if (hasPendingEvents) { - refresh() + autoRefreshJob = viewModelScope.launch(Dispatchers.IO) { + while (true) { + checkAutoRefresh() + delay(25000) + } } } - private fun startAutoRefresh() { - stopAutoRefresh() - postDelayed(25000, autoRefreshRunnable) - } - - private fun stopAutoRefresh() { - cancelPost(autoRefreshRunnable) + private suspend fun checkAutoRefresh() { + if (hasPendingEvents()) { + setLoading() + requestRefresh() + } } fun refresh() { @@ -88,10 +88,14 @@ class EventsViewModel( } setLoading() viewModelScope.launch(Dispatchers.IO) { - submitEvents(load(), false) + requestRefresh() } } + private suspend fun requestRefresh() = withContext(Dispatchers.IO) { + submitEvents(load(), false) + } + fun loadMore() { if (isLoading.get()) { return @@ -156,13 +160,6 @@ class EventsViewModel( events = newEvents.distinctBy { it.eventId } .sortedByDescending { it.timestamp } .toTypedArray() - - if (hasPendingEvents()) { - startAutoRefresh() - } else { - stopAutoRefresh() - } - isLoading.set(loading) updateState() } @@ -176,10 +173,8 @@ class EventsViewModel( submitEvents(list, false) } - private fun appendEvent(event: AccountEventWrap) { - viewModelScope.launch { - appendEvents(listOf(event.copy())) - } + private suspend fun appendEvent(event: AccountEventWrap) { + appendEvents(listOf(event.copy())) } private fun getLastLt(): Long? { @@ -211,6 +206,12 @@ class EventsViewModel( return list ?: emptyList() } + override fun onCleared() { + super.onCleared() + autoRefreshJob?.cancel() + autoRefreshJob = null + } + private companion object { private const val CACHE_NAME = "events" } diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/InitViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/InitViewModel.kt index f541f2111..6ee331551 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/InitViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/InitViewModel.kt @@ -24,6 +24,7 @@ import com.tonapps.tonkeeper.extensions.toast import com.tonapps.tonkeeper.manager.push.PushManager import com.tonapps.tonkeeper.ui.base.BaseWalletVM import com.tonapps.tonkeeper.ui.screen.init.list.AccountItem +import com.tonapps.tonkeeper.worker.PushToggleWorker import com.tonapps.uikit.list.ListCell import com.tonapps.wallet.api.API import com.tonapps.wallet.api.entity.AccountDetailsEntity @@ -453,15 +454,11 @@ class InitViewModel( } if (type == InitArgs.Type.Import || type == InitArgs.Type.Testnet) { - post { - backupRepository.addBackupsAsync(wallets.map { it.id }) - } + backupRepository.addBackups(wallets.map { it.id }) } if (savedState.enablePush) { - post { - pushManager.walletsAsync(wallets, PushManager.State.Enable) - } + PushToggleWorker.run(context, wallets, PushManager.State.Enable) } val selectedWalletId = wallets.minByOrNull { it.version }!!.id diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/step/WordsScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/step/WordsScreen.kt index 18b28fded..df8ea7c6b 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/step/WordsScreen.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/init/step/WordsScreen.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.withContext import org.koin.androidx.viewmodel.ext.android.viewModel import org.ton.mnemonic.Mnemonic import uikit.base.BaseFragment +import uikit.extensions.clear import uikit.extensions.collectFlow import uikit.extensions.doKeyboardAnimation import uikit.extensions.getCurrentFocusEditText @@ -113,13 +114,23 @@ class WordsScreen: BaseFragment(R.layout.fragment_init_words) { private fun onTextChanged(index: Int, editable: Editable) { if (index == 0) { val words = TonMnemonic.parseMnemonic(editable.toString()) - if (words.size > 1) { - editable.clear() - setWords(words) - return + post { + applyWords(words) } + } else { + post { + checkWords() + } + } + } + + private fun applyWords(words: List) { + if (words.size > 1) { + wordInputs.first().clear() + setWords(words) + } else { + checkWords() } - checkWords() } private fun checkWords(delay: Long = 0) { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/NotificationsManageViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/NotificationsManageViewModel.kt index 653f9001e..937445b70 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/NotificationsManageViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/NotificationsManageViewModel.kt @@ -7,6 +7,7 @@ import com.tonapps.tonkeeper.manager.push.PushManager import com.tonapps.tonkeeper.manager.tonconnect.TonConnectManager import com.tonapps.tonkeeper.ui.base.BaseWalletVM import com.tonapps.tonkeeper.ui.screen.notifications.list.Item +import com.tonapps.tonkeeper.worker.DAppPushToggleWorker import com.tonapps.uikit.list.ListCell import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.settings.SettingsRepository @@ -57,8 +58,11 @@ class NotificationsManageViewModel( } fun toggleDAppPush(url: Uri, enabled: Boolean) { - viewModelScope.launch { - tonConnectManager.setPushEnabled(wallet, url, enabled) - } + DAppPushToggleWorker.run( + context = context, + wallet = wallet, + appUrl = url, + enable = enabled + ) } } \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/root/RootViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/root/RootViewModel.kt index 4f1795683..0368686d1 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/root/RootViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/root/RootViewModel.kt @@ -71,6 +71,7 @@ import com.tonapps.wallet.data.settings.SettingsRepository import com.tonapps.wallet.localization.Localization import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow @@ -336,23 +337,17 @@ class RootViewModel( ): Boolean { savedState.returnUri = null val deeplink = DeepLink(uri, fromQR, refSource) - postDelayed(1000) { + accountRepository.selectedStateFlow.take(1).onEach { state -> + delay(1000) if (deeplink.route is DeepLinkRoute.Signer) { processSignerDeepLink(deeplink.route, fromQR) - } else { - processDeepLink(deeplink) + } else if (state is AccountRepository.SelectedState.Wallet) { + processDeepLink(state.wallet, deeplink) } - } + }.launch() return true } - @OptIn(FlowPreview::class) - private fun processDeepLink(deeplink: DeepLink) { - accountRepository.selectedWalletFlow.take(1).timeout(5.seconds).collectFlow { wallet -> - processDeepLink(wallet, deeplink) - } - } - private suspend fun processDeepLink(wallet: WalletEntity, deeplink: DeepLink) { val route = deeplink.route if (route is DeepLinkRoute.TonConnect) { @@ -447,7 +442,7 @@ class RootViewModel( } } - private fun processTransferDeepLink(wallet: WalletEntity, route: DeepLinkRoute.Transfer) { + private suspend fun processTransferDeepLink(wallet: WalletEntity, route: DeepLinkRoute.Transfer) { if (route.isExpired) { toast(Localization.expired_link) return @@ -461,7 +456,7 @@ class RootViewModel( )) } - private fun processSignerDeepLink(route: DeepLinkRoute.Signer, fromQR: Boolean) { + private suspend fun processSignerDeepLink(route: DeepLinkRoute.Signer, fromQR: Boolean) { _eventFlow.tryEmit(RootEvent.Singer( publicKey = route.publicKey, name = route.name, diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/transaction/SendTransactionViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/transaction/SendTransactionViewModel.kt index 9f0fca783..641fb5b12 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/transaction/SendTransactionViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/transaction/SendTransactionViewModel.kt @@ -1,12 +1,9 @@ package com.tonapps.tonkeeper.ui.screen.send.transaction import android.app.Application -import android.util.Log import androidx.lifecycle.viewModelScope -import co.touchlab.stately.concurrency.AtomicBoolean import com.tonapps.blockchain.ton.extensions.base64 import com.tonapps.ledger.ton.Transaction -import com.tonapps.security.base64 import com.tonapps.tonkeeper.core.history.HistoryHelper import com.tonapps.tonkeeper.extensions.getTransfers import com.tonapps.tonkeeper.manager.tx.TransactionManager @@ -31,6 +28,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch +import java.util.concurrent.atomic.AtomicBoolean class SendTransactionViewModel( app: Application, @@ -64,7 +62,7 @@ class SendTransactionViewModel( useBattery = settingsRepository.batteryIsEnabledTx(wallet.accountId, batteryTransactionType), forceRelayer = forceRelayer ) - isBattery.value = emulated.withBattery + isBattery.set(emulated.withBattery) val details = historyHelper.create(wallet, emulated) @@ -104,7 +102,7 @@ class SendTransactionViewModel( } fun send() = flow { - val isBattery = isBattery.value + val isBattery = isBattery.get() val message = messageBody(false) val unsignedBody = message.createUnsignedBody(isBattery) val ledgerTransaction = getLedgerTransaction(message) @@ -126,7 +124,7 @@ class SendTransactionViewModel( private suspend fun messageBody(forEmulation: Boolean): MessageBodyEntity { val compressedTokens = getCompressedTokens() - val excessesAddress = if (!forEmulation && isBattery.value) { + val excessesAddress = if (!forEmulation && isBattery.get()) { batteryRepository.getConfig(wallet.testnet).excessesAddress } else null diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/main/SettingsViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/main/SettingsViewModel.kt index 18a117547..75e792518 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/main/SettingsViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/main/SettingsViewModel.kt @@ -17,6 +17,7 @@ import com.tonapps.tonkeeper.manager.push.PushManager import com.tonapps.tonkeeper.manager.tonconnect.TonConnectManager import com.tonapps.tonkeeper.ui.base.BaseWalletVM import com.tonapps.tonkeeper.ui.screen.settings.main.list.Item +import com.tonapps.tonkeeper.worker.PushToggleWorker import com.tonapps.tonkeeperx.BuildConfig import com.tonapps.uikit.list.ListCell import com.tonapps.wallet.api.API @@ -76,7 +77,7 @@ class SettingsViewModel( fun signOut() { tonConnectManager.clear(wallet) - pushManager.walletAsync(wallet, PushManager.State.Delete) + PushToggleWorker.run(context, wallet, PushManager.State.Delete) viewModelScope.launch(Dispatchers.IO) { AnalyticsHelper.trackEvent("delete_wallet") accountRepository.delete(wallet.id) @@ -191,7 +192,7 @@ class SettingsViewModel( uiItems.add(Item.Support(ListCell.Position.MIDDLE, getSupportUrl())) uiItems.add(Item.News(ListCell.Position.MIDDLE, api.config.tonkeeperNewsUrl)) uiItems.add(Item.Contact(ListCell.Position.MIDDLE, api.config.supportLink)) - if (environment.isGooglePlayServicesAvailable) { + if (environment.isGooglePlayAvailable) { uiItems.add(Item.Rate(ListCell.Position.MIDDLE)) } uiItems.add(Item.Legal(ListCell.Position.LAST)) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/SetupSwitchHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/SetupSwitchHolder.kt index b45baf671..e6eadbd09 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/SetupSwitchHolder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/SetupSwitchHolder.kt @@ -17,6 +17,7 @@ import com.tonapps.tonkeeper.koin.rnLegacy import com.tonapps.tonkeeper.koin.settingsRepository import com.tonapps.tonkeeper.manager.push.PushManager import com.tonapps.tonkeeper.ui.screen.wallet.main.list.Item +import com.tonapps.tonkeeper.worker.PushToggleWorker import com.tonapps.tonkeeperx.R import com.tonapps.uikit.color.accentGreenColor import com.tonapps.uikit.color.stateList @@ -32,7 +33,6 @@ import uikit.widget.SwitchView class SetupSwitchHolder(parent: ViewGroup): Holder(parent, R.layout.view_wallet_setup_switch) { private val settingsRepository = context.settingsRepository - private val pushManager = context.pushManager private val passcodeManager = context.passcodeManager private val rnLegacy = context.rnLegacy @@ -65,12 +65,12 @@ class SetupSwitchHolder(parent: ViewGroup): Holder(parent, R.l private fun togglePush(wallet: WalletEntity, enable: Boolean) { if (!enable) { - pushManager?.walletAsync(wallet, PushManager.State.Disable) + PushToggleWorker.run(context, wallet, PushManager.State.Disable) return } if (context.hasPushPermission()) { - pushManager?.walletAsync(wallet, PushManager.State.Enable) + PushToggleWorker.run(context, wallet, PushManager.State.Enable) } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val activity = context.activity ?: return switchView.setChecked(newChecked = false, byUser = false) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/DAppPushToggleWorker.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/DAppPushToggleWorker.kt new file mode 100644 index 000000000..c9333f193 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/DAppPushToggleWorker.kt @@ -0,0 +1,60 @@ +package com.tonapps.tonkeeper.worker + +import android.content.Context +import android.net.Uri +import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.Operation +import androidx.work.WorkerParameters +import com.tonapps.extensions.toUriOrNull +import com.tonapps.tonkeeper.extensions.workManager +import com.tonapps.tonkeeper.manager.push.PushManager +import com.tonapps.wallet.data.account.AccountRepository +import com.tonapps.wallet.data.account.entities.WalletEntity +import com.tonapps.wallet.data.dapps.DAppsRepository + +class DAppPushToggleWorker( + context: Context, + workParam: WorkerParameters, + private val accountRepository: AccountRepository, + private val dAppsRepository: DAppsRepository, + private val pushManager: PushManager +): CoroutineWorker(context, workParam) { + + override suspend fun doWork(): Result { + val wallet = getWallet() ?: return Result.failure() + val appUrl = getAppUrl() ?: return Result.failure() + val enabled = inputData.getBoolean(ARG_ENABLE, false) + val connections = dAppsRepository.setPushEnabled(wallet.accountId, wallet.testnet, appUrl, enabled) + if (!pushManager.dAppPush(wallet, connections, enabled)) { + dAppsRepository.setPushEnabled(wallet.accountId, wallet.testnet, appUrl, !enabled) + return Result.failure() + } + return Result.success() + } + + private suspend fun getWallet(): WalletEntity? { + val walletId = inputData.getString(ARG_WALLET_ID) ?: return null + return accountRepository.getWalletById(walletId) + } + + private fun getAppUrl(): Uri? { + return inputData.getString(ARG_APP_URL)?.toUriOrNull() + } + + companion object { + + private const val ARG_WALLET_ID = "wallet_id" + private const val ARG_APP_URL = "app_url" + private const val ARG_ENABLE = "enable" + + fun run(context: Context, wallet: WalletEntity, appUrl: Uri, enable: Boolean): Operation { + val inputData = Data.Builder() + .putString(ARG_WALLET_ID, wallet.id) + .putString(ARG_APP_URL, appUrl.toString()) + .putBoolean(ARG_ENABLE, enable) + .build() + return context.workManager.oneTime(inputData) + } + } +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/Extension.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/Extension.kt new file mode 100644 index 000000000..42712586a --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/Extension.kt @@ -0,0 +1,23 @@ +package com.tonapps.tonkeeper.worker + +import androidx.work.Constraints +import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.Operation +import androidx.work.WorkManager +import androidx.work.WorkRequest + +inline fun WorkManager.oneTime( + inputData: Data = Data.EMPTY +): Operation { + val builder = OneTimeWorkRequestBuilder() + builder.setInputData(inputData) + builder.requiredNetwork() + return enqueue(builder.build()) +} + +fun WorkRequest.Builder<*, *>.requiredNetwork(networkType: NetworkType = NetworkType.CONNECTED) { + setConstraints(Constraints.Builder().setRequiredNetworkType(networkType).build()) +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/PushToggleWorker.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/PushToggleWorker.kt new file mode 100644 index 000000000..7c8d108a4 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/worker/PushToggleWorker.kt @@ -0,0 +1,58 @@ +package com.tonapps.tonkeeper.worker + +import android.content.Context +import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.Operation +import androidx.work.WorkerParameters +import com.tonapps.tonkeeper.extensions.workManager +import com.tonapps.tonkeeper.manager.push.PushManager +import com.tonapps.wallet.data.account.AccountRepository +import com.tonapps.wallet.data.account.entities.WalletEntity + +class PushToggleWorker( + context: Context, + workParam: WorkerParameters, + private val accountRepository: AccountRepository, + private val pushManager: PushManager +): CoroutineWorker(context, workParam) { + + private val state: PushManager.State by lazy { + val code = inputData.getInt(ARG_PUSH_STATE, 0) + PushManager.State.of(code) + } + + override suspend fun doWork(): Result { + val wallets = getWallets() + if (pushManager.wallets(wallets, state)) { + return Result.success() + } + return Result.failure() + } + + private suspend fun getWallets(): List { + val walletIds = inputData.getStringArray(ARG_WALLET_IDS) ?: emptyArray() + return accountRepository.getWallets().filter { + it.id in walletIds + } + } + + companion object { + + private const val ARG_WALLET_IDS = "wallet_ids" + private const val ARG_PUSH_STATE = "push_state" + + fun run(context: Context, wallet: WalletEntity, state: PushManager.State): Operation { + return run(context, listOf(wallet), state) + } + + fun run(context: Context, wallets: List, state: PushManager.State): Operation { + val inputData = Data.Builder() + .putStringArray(ARG_WALLET_IDS, wallets.map { it.id }.toTypedArray()) + .putInt(ARG_PUSH_STATE, state.code) + .build() + return context.workManager.oneTime(inputData) + } + } + +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Dependence.kt b/buildSrc/src/main/kotlin/Dependence.kt index ef7b8ffaa..40e6d3f09 100644 --- a/buildSrc/src/main/kotlin/Dependence.kt +++ b/buildSrc/src/main/kotlin/Dependence.kt @@ -13,18 +13,18 @@ object Dependence { object KotlinX { const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0" - const val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2" - const val serializationJSON = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2" - const val serializationCBOR = "org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.7.2" + const val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3" + const val serializationJSON = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3" + const val serializationCBOR = "org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.7.3" const val datetime = "org.jetbrains.kotlinx:kotlinx-datetime:0.6.1" - const val io = "org.jetbrains.kotlinx:kotlinx-io-core:0.5.3" + const val io = "org.jetbrains.kotlinx:kotlinx-io-core:0.5.4" } object GooglePlay { - const val cronet = "com.google.android.gms:play-services-cronet:18.0.1" + const val cronet = "com.google.android.gms:play-services-cronet:18.1.0" const val cronetOkhttp = "com.google.net.cronet:cronet-okhttp:0.1.0" const val review = "com.google.android.play:review-ktx:2.0.1" - const val billing = "com.android.billingclient:billing-ktx:7.0.0" + const val billing = "com.android.billingclient:billing-ktx:7.1.1" } object UI { @@ -33,7 +33,8 @@ object Dependence { } object Koin { - const val core = "io.insert-koin:koin-android:3.5.6" + const val core = "io.insert-koin:koin-android:4.0.0" + const val workmanager = "io.insert-koin:koin-androidx-workmanager:4.0.0" } object ML { @@ -44,24 +45,24 @@ object Dependence { const val core = "androidx.core:core-ktx:1.13.1" const val shortcuts = "androidx.core:core-google-shortcuts:1.1.0" const val appCompat = "androidx.appcompat:appcompat:1.7.0" - const val activity = "androidx.activity:activity-ktx:1.9.1" - const val fragment = "androidx.fragment:fragment-ktx:1.8.2" + const val activity = "androidx.activity:activity-ktx:1.9.2" + const val fragment = "androidx.fragment:fragment-ktx:1.8.4" const val recyclerView = "androidx.recyclerview:recyclerview:1.3.2" const val viewPager2 = "androidx.viewpager2:viewpager2:1.1.0" const val security = "androidx.security:security-crypto:1.0.0" const val workManager = "androidx.work:work-runtime-ktx:2.9.1" const val biometric = "androidx.biometric:biometric:1.1.0" - const val annotation = "androidx.annotation:annotation:1.8.1" + const val annotation = "androidx.annotation:annotation:1.8.2" const val splashscreen = "androidx.core:core-splashscreen:1.0.1" const val constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" const val browser = "androidx.browser:browser:1.8.0" const val swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - const val profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.1" - const val webkit = "androidx.webkit:webkit:1.11.0" + const val profileinstaller = "androidx.profileinstaller:profileinstaller:1.4.1" + const val webkit = "androidx.webkit:webkit:1.12.1" - const val lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.8.4" - const val lifecycleSavedState = "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4" + const val lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.8.6" + const val lifecycleSavedState = "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6" object Camera { private const val version = "1.4.0-alpha04" @@ -73,7 +74,7 @@ object Dependence { } object Emoji { - const val core = "androidx.emoji2:emoji2:1.4.0" + const val core = "androidx.emoji2:emoji2:1.5.0" } } @@ -86,7 +87,7 @@ object Dependence { } object Firebase { - const val bom = "com.google.firebase:firebase-bom:33.2.0" + const val bom = "com.google.firebase:firebase-bom:33.4.0" const val analytics = "com.google.firebase:firebase-analytics-ktx" const val crashlytics = "com.google.firebase:firebase-crashlytics-ktx" const val messaging = "com.google.firebase:firebase-messaging-ktx" diff --git a/lib/extensions/src/main/java/com/tonapps/extensions/BaseDialog.kt b/lib/extensions/src/main/java/com/tonapps/extensions/BaseDialog.kt deleted file mode 100644 index 38d0314e3..000000000 --- a/lib/extensions/src/main/java/com/tonapps/extensions/BaseDialog.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.tonapps.extensions - -import androidx.annotation.MainThread -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelStoreOwner -import androidx.lifecycle.viewmodel.CreationExtras -import org.koin.android.ext.android.getKoinScope -import org.koin.androidx.viewmodel.resolveViewModel -import org.koin.core.annotation.KoinInternalApi -import org.koin.core.parameter.ParametersHolder -import org.koin.core.qualifier.Qualifier -import uikit.base.BaseDialog - -@MainThread -inline fun BaseDialog.viewModel( - qualifier: Qualifier? = null, - noinline ownerProducer: () -> ViewModelStoreOwner = { this }, - noinline extrasProducer: (() -> CreationExtras)? = null, - noinline parameters: (() -> ParametersHolder)? = null, -): Lazy { - return lazy(kotlin.LazyThreadSafetyMode.NONE) { - getViewModel(qualifier, ownerProducer, extrasProducer, parameters) - } -} - -@OptIn(KoinInternalApi::class) -inline fun BaseDialog.getViewModel( - qualifier: Qualifier? = null, - noinline ownerProducer: () -> ViewModelStoreOwner = { this }, - noinline extrasProducer: (() -> CreationExtras)? = null, - noinline parameters: (() -> ParametersHolder)? = null, -): T { - return resolveViewModel( - T::class, - ownerProducer().viewModelStore, - extras = extrasProducer?.invoke() ?: this.getDefaultViewModelCreationExtras(), - qualifier = qualifier, - parameters = parameters, - scope = getKoinScope() - ) -} \ No newline at end of file diff --git a/ui/uikit/core/src/main/java/uikit/extensions/EditText.kt b/ui/uikit/core/src/main/java/uikit/extensions/EditText.kt index ac87f28c7..e77754a7c 100644 --- a/ui/uikit/core/src/main/java/uikit/extensions/EditText.kt +++ b/ui/uikit/core/src/main/java/uikit/extensions/EditText.kt @@ -8,13 +8,16 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.doOnLayout import java.lang.reflect.Field - fun EditText.cursorToEnd() { try { setSelection(text.length) } catch (ignored: Throwable) { } } +fun EditText.clear() { + text?.clear() +} + fun EditText.requestFocusWithSelection() { requestFocus() cursorToEnd()