From f67e19401c3eae26a2062b9be3fb717a38570272 Mon Sep 17 00:00:00 2001 From: polstianka Date: Fri, 18 Oct 2024 04:02:31 -0700 Subject: [PATCH] dapp push in history --- .../data/core/entity/RawMessageEntity.kt | 1 + .../wallet/data/dapps/DAppsRepository.kt | 19 ++ .../wallet/data/dapps/entities/AppEntity.kt | 3 + .../data/dapps/entities/AppPushEntity.kt | 49 +++++ .../data/dapps/source/DatabaseSource.kt | 2 +- .../wallet/data/events/EventsRepository.kt | 3 +- .../com/tonapps/tonkeeper/api/Extensions.kt | 19 ++ .../entities/WalletPurchaseMethodEntity.kt | 4 - .../tonkeeper/core/history/HistoryHelper.kt | 6 +- .../history/list/HistoryItemDecoration.kt | 8 +- .../core/history/list/item/HistoryItem.kt | 23 +- .../tonapps/tonkeeper/helper/BrowserHelper.kt | 7 + .../tonkeeper/koin/viewModelWalletModule.kt | 3 +- .../manager/tonconnect/bridge/Bridge.kt | 3 - .../tonconnect/bridge/BridgeConnectHelper.kt | 4 - .../ui/component/MainRecyclerView.kt | 22 +- .../screen/collectibles/CollectiblesScreen.kt | 4 +- .../ui/screen/events/EventsScreen.kt | 42 ++-- .../ui/screen/events/EventsViewModel.kt | 208 +++++++++++++++++- .../ui/screen/events/filters/FilterItem.kt | 38 ++++ .../screen/events/filters/FiltersAdapter.kt | 20 ++ .../ui/screen/events/filters/Item.kt | 4 - .../screen/events/filters/holder/AppHolder.kt | 39 ++++ .../events/filters/holder/FilterHolder.kt | 32 +++ .../ui/screen/events/filters/holder/Holder.kt | 22 ++ .../tonkeeper/ui/screen/main/MainScreen.kt | 4 +- .../{main => }/PurchaseConfirmDialog.kt | 2 +- .../purchase/{main => }/PurchaseScreen.kt | 22 +- .../purchase/{main => }/PurchaseViewModel.kt | 7 +- .../purchase/{main => }/list/Adapter.kt | 8 +- .../screen/purchase/{main => }/list/Item.kt | 2 +- .../purchase/{main => }/list/holder/Holder.kt | 4 +- .../{main => }/list/holder/MethodHolder.kt | 4 +- .../{main => }/list/holder/SpaceHolder.kt | 4 +- .../{main => }/list/holder/TitleHolder.kt | 4 +- .../screen/purchase/web/PurchaseWebScreen.kt | 107 --------- .../tonkeeper/ui/screen/root/RootViewModel.kt | 7 +- .../ui/screen/send/InsufficientFundsDialog.kt | 2 +- .../contacts/main/SendContactsViewModel.kt | 40 +++- .../screen/send/contacts/main/list/Adapter.kt | 2 + .../ui/screen/send/contacts/main/list/Item.kt | 3 + .../contacts/main/list/holder/LoaderHolder.kt | 10 + .../tonkeeper/ui/screen/wallet/main/State.kt | 11 +- .../ui/screen/wallet/main/WalletScreen.kt | 4 +- .../ui/screen/wallet/main/WalletViewModel.kt | 30 ++- .../ui/screen/wallet/main/list/Item.kt | 21 +- .../wallet/main/list/holder/ActionsHolder.kt | 2 +- .../wallet/main/list/holder/PushHolder.kt | 2 +- .../res/layout/fragment_main_events_list.xml | 49 +++-- .../main/res/layout/fragment_main_list.xml | 2 +- .../main/res/layout/fragment_purchase_web.xml | 33 --- .../src/main/res/layout/fragment_security.xml | 3 + .../src/main/res/layout/fragment_wallet.xml | 2 +- .../src/main/res/layout/view_filter_chip.xml | 26 +++ .../app/src/main/res/values/styleable.xml | 6 + .../tonapps/blockchain/ton/extensions/Cell.kt | 19 +- .../java/com/tonapps/extensions/JSONArray.kt | 9 + .../java/com/tonapps/security/RootUtils.kt | 57 ----- .../java/com/tonapps/security/Security.kt | 2 +- 59 files changed, 732 insertions(+), 363 deletions(-) create mode 100644 apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppPushEntity.kt delete mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/BridgeConnectHelper.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FilterItem.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FiltersAdapter.kt delete mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/Item.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/AppHolder.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/FilterHolder.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/Holder.kt rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/PurchaseConfirmDialog.kt (98%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/PurchaseScreen.kt (82%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/PurchaseViewModel.kt (90%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/list/Adapter.kt (76%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/list/Item.kt (93%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/list/holder/Holder.kt (64%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/list/holder/MethodHolder.kt (87%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/list/holder/SpaceHolder.kt (62%) rename apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/{main => }/list/holder/TitleHolder.kt (74%) delete mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/web/PurchaseWebScreen.kt create mode 100644 apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/holder/LoaderHolder.kt delete mode 100644 apps/wallet/instance/app/src/main/res/layout/fragment_purchase_web.xml create mode 100644 apps/wallet/instance/app/src/main/res/layout/view_filter_chip.xml delete mode 100644 lib/security/src/main/java/com/tonapps/security/RootUtils.kt diff --git a/apps/wallet/data/core/src/main/java/com/tonapps/wallet/data/core/entity/RawMessageEntity.kt b/apps/wallet/data/core/src/main/java/com/tonapps/wallet/data/core/entity/RawMessageEntity.kt index 7ef80e5a1..ce94e2cbc 100644 --- a/apps/wallet/data/core/src/main/java/com/tonapps/wallet/data/core/entity/RawMessageEntity.kt +++ b/apps/wallet/data/core/src/main/java/com/tonapps/wallet/data/core/entity/RawMessageEntity.kt @@ -4,6 +4,7 @@ import android.os.Parcelable import android.util.Log import com.tonapps.blockchain.ton.TONOpCode import com.tonapps.blockchain.ton.extensions.loadOpCode +import com.tonapps.blockchain.ton.extensions.parseCell import com.tonapps.blockchain.ton.extensions.safeParseCell import com.tonapps.blockchain.ton.extensions.storeOpCode import com.tonapps.blockchain.ton.extensions.toTlb 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 f13700297..13aeb451c 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 @@ -7,10 +7,12 @@ import androidx.collection.ArrayMap import androidx.core.net.toUri import com.tonapps.blockchain.ton.extensions.toRawAddress import com.tonapps.blockchain.ton.extensions.toUserFriendly +import com.tonapps.extensions.map import com.tonapps.extensions.withoutQuery import com.tonapps.wallet.api.API import com.tonapps.wallet.data.dapps.entities.AppConnectEntity import com.tonapps.wallet.data.dapps.entities.AppEntity +import com.tonapps.wallet.data.dapps.entities.AppPushEntity import com.tonapps.wallet.data.dapps.source.DatabaseSource import com.tonapps.wallet.data.rn.RNLegacy import com.tonapps.wallet.data.rn.data.RNTC @@ -37,6 +39,7 @@ class DAppsRepository( context: Context, private val scope: CoroutineScope, private val rnLegacy: RNLegacy, + private val api: API, ) { private val _connectionsFlow = MutableStateFlow?>(null) @@ -73,6 +76,22 @@ class DAppsRepository( }.flowOn(Dispatchers.IO).launchIn(scope) } + suspend fun getPushes(tonProof: String, accountId: String): List { + val pushes = api.getPushFromApps(tonProof, accountId).map { AppPushEntity.Body(it) } + if (pushes.isEmpty()) { + return emptyList() + } + val apps = getApps(pushes.map { it.dappUrl }) + + val list = mutableListOf() + for (push in pushes) { + val app = apps.firstOrNull { it.url == push.dappUrl } ?: continue + list.add(AppPushEntity(app, push)) + } + + return list.toList() + } + suspend fun getConnections( accountId: String, testnet: Boolean diff --git a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppEntity.kt b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppEntity.kt index ff6cdd2b0..3246fdac5 100644 --- a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppEntity.kt +++ b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppEntity.kt @@ -14,6 +14,9 @@ data class AppEntity( val empty: Boolean ): Parcelable { + val id: String + get() = url.toString() + val host: String get() = url.host ?: "unknown" diff --git a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppPushEntity.kt b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppPushEntity.kt new file mode 100644 index 000000000..9637e0ed6 --- /dev/null +++ b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/entities/AppPushEntity.kt @@ -0,0 +1,49 @@ +package com.tonapps.wallet.data.dapps.entities + +import android.net.Uri +import androidx.core.net.toUri +import com.tonapps.extensions.getLongCompat +import org.json.JSONObject + +data class AppPushEntity( + val from: AppEntity, + val body: Body +) { + + val timestamp: Long + get() = body.dateCreate + + val iconUrl: String + get() = from.iconUrl + + val title: String + get() = body.title + + val message: String + get() = body.message + + val url: Uri + get() = body.dappUrl + + val deeplink: String + get() = body.link + + data class Body( + val dappUrl: Uri, + val title: String, + val message: String, + val link: String, + val account: String, + val dateCreate: Long + ) { + + constructor(json: JSONObject) : this( + dappUrl = json.getString("dapp_url").toUri(), + title = json.getString("title"), + message = json.getString("message"), + link = json.getString("link"), + account = json.getString("account"), + dateCreate = json.getLongCompat("date_create") + ) + } +} \ No newline at end of file diff --git a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/source/DatabaseSource.kt b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/source/DatabaseSource.kt index 3e0af7128..8a141e56b 100644 --- a/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/source/DatabaseSource.kt +++ b/apps/wallet/data/dapps/src/main/java/com/tonapps/wallet/data/dapps/source/DatabaseSource.kt @@ -124,7 +124,7 @@ internal class DatabaseSource( val notFoundApps = urls.filter { url -> apps.none { it.url == url } } if (notFoundApps.isNotEmpty()) { for (url in notFoundApps) { - val domain = url.host ?: "test.ton" + val domain = url.host ?: "unknown" apps.add(AppEntity( url = url, name = domain.split(".").firstOrNull() ?: domain, diff --git a/apps/wallet/data/events/src/main/java/com/tonapps/wallet/data/events/EventsRepository.kt b/apps/wallet/data/events/src/main/java/com/tonapps/wallet/data/events/EventsRepository.kt index 07e8cf9be..6f84c8b24 100644 --- a/apps/wallet/data/events/src/main/java/com/tonapps/wallet/data/events/EventsRepository.kt +++ b/apps/wallet/data/events/src/main/java/com/tonapps/wallet/data/events/EventsRepository.kt @@ -97,10 +97,11 @@ class EventsRepository( accountId: String, testnet: Boolean, beforeLt: Long? = null, + limit: Int = 12 ): AccountEvents? = withContext(Dispatchers.IO) { try { if (beforeLt != null) { - remoteDataSource.get(accountId, testnet, beforeLt) + remoteDataSource.get(accountId, testnet, beforeLt, limit) } else { val events = remoteDataSource.get(accountId, testnet)?.also { localDataSource.setCache(cacheKey(accountId, testnet), it) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/api/Extensions.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/api/Extensions.kt index 0390cf2d4..6ef164403 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/api/Extensions.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/api/Extensions.kt @@ -2,6 +2,7 @@ package com.tonapps.tonkeeper.api import android.util.Log import com.squareup.moshi.adapter +import com.tonapps.blockchain.ton.extensions.equalsAddress import com.tonapps.icu.Coins import com.tonapps.blockchain.ton.extensions.toUserFriendly import com.tonapps.extensions.ifPunycodeToUnicode @@ -12,6 +13,7 @@ import com.tonapps.extensions.short12 import com.tonapps.extensions.short6 import com.tonapps.extensions.short8 import com.tonapps.tonkeeperx.R +import com.tonapps.wallet.data.account.entities.WalletEntity import io.tonapi.infrastructure.Serializer import io.tonapi.models.AccountAddress import io.tonapi.models.AccountEvent @@ -38,6 +40,23 @@ fun TokenRates.to(toCurrency: String, value: Float): Float { return price.toFloat() * value } +fun AccountEvent.isOutTransfer(wallet: WalletEntity): Boolean { + return actions.any { it.isOutTransfer(wallet) } +} + +val Action.isTransfer: Boolean + get() { + return type == Action.Type.tonTransfer || type == Action.Type.jettonTransfer || type == Action.Type.nftItemTransfer + } + +fun Action.isOutTransfer(wallet: WalletEntity): Boolean { + if (!isTransfer) { + return false + } + val sender = tonTransfer?.sender ?: jettonTransfer?.sender ?: nftItemTransfer?.sender ?: return false + return sender.address.equalsAddress(wallet.accountId) +} + /*val MessageConsequences.totalFees: Long get() { // = event.extra // trace.transaction.totalFees diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/entities/WalletPurchaseMethodEntity.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/entities/WalletPurchaseMethodEntity.kt index 44298a84e..bbf84f017 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/entities/WalletPurchaseMethodEntity.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/entities/WalletPurchaseMethodEntity.kt @@ -20,10 +20,6 @@ data class WalletPurchaseMethodEntity( val config: ConfigEntity, ): Parcelable { - @IgnoredOnParcel - val useCustomTabs: Boolean - get() = true // method.useCustomTabs - @IgnoredOnParcel val successUrlPattern: SuccessUrlPattern? get() = method.successUrlPattern diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/HistoryHelper.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/HistoryHelper.kt index 2c861f4a0..6f9f4f3d5 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/HistoryHelper.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/HistoryHelper.kt @@ -95,7 +95,7 @@ class HistoryHelper( private data class ActionDateSection( val date: Long, val dateFormat: String, - val events: MutableList + val events: MutableList ) { fun get(): List { @@ -116,9 +116,9 @@ class HistoryHelper( return "UQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJKZ".equalsAddress(account.address) } - private fun sort(list: List): List { + private fun sort(list: List): List { return list - .filterIsInstance() + .filter { it is HistoryItem.Event || it is HistoryItem.App } .distinctBy { it.uniqueId } .sortedWith { a, b -> (b.timestampForSort - a.timestampForSort).toInt() diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/HistoryItemDecoration.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/HistoryItemDecoration.kt index e91bdd677..d5963be4c 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/HistoryItemDecoration.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/HistoryItemDecoration.kt @@ -19,15 +19,17 @@ class HistoryItemDecoration: RecyclerView.ItemDecoration() { ) { super.getItemOffsets(outRect, view, parent, state) val position = parent.getChildAdapterPosition(view) + if (position == 0) { + return + } + if (parent.isLayoutRequested) { parent.doOnLayout { getItemOffsets(outRect, view, parent, state) } return } - /*if (position == 0) { - return - }*/ + val holder = parent.findViewHolderForAdapterPosition(position) ?: return val item = (holder as? BaseListHolder<*>)?.item ?: return diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/item/HistoryItem.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/item/HistoryItem.kt index b29331e2f..bac31a5a3 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/item/HistoryItem.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/core/history/list/item/HistoryItem.kt @@ -1,10 +1,13 @@ package com.tonapps.tonkeeper.core.history.list.item +import android.content.Context import android.net.Uri import android.os.Parcel import android.os.Parcelable +import androidx.core.net.toUri import com.tonapps.blockchain.ton.extensions.toUserFriendly import com.tonapps.extensions.ifPunycodeToUnicode +import com.tonapps.extensions.locale import com.tonapps.extensions.readBooleanCompat import com.tonapps.extensions.readCharSequenceCompat import com.tonapps.extensions.readEnum @@ -15,10 +18,12 @@ import com.tonapps.extensions.writeEnum import com.tonapps.tonkeeper.core.history.ActionType import com.tonapps.tonkeeper.core.history.recipient import com.tonapps.tonkeeper.core.history.sender +import com.tonapps.tonkeeper.helper.DateHelper import com.tonapps.uikit.list.BaseListItem import com.tonapps.uikit.list.ListCell import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.collectibles.entities.NftEntity +import com.tonapps.wallet.data.dapps.entities.AppPushEntity import io.tonapi.models.AccountAddress import io.tonapi.models.EncryptedComment import kotlinx.parcelize.IgnoredOnParcel @@ -127,18 +132,30 @@ sealed class HistoryItem( val title: String, val body: String, val date: String, - val host: String, + val url: Uri, val timestamp: Long, val deepLink: String, val wallet: WalletEntity, ): HistoryItem(TYPE_APP) { + + constructor(context: Context, wallet: WalletEntity, push: AppPushEntity) : this( + iconUri = push.iconUrl.toUri(), + title = push.title, + body = push.message, + date = DateHelper.formattedDate(push.timestamp, context.locale), + url = push.url, + timestamp = push.timestamp, + deepLink = push.deeplink, + wallet = wallet + ) + constructor(parcel: Parcel) : this( iconUri = parcel.readParcelableCompat()!!, title = parcel.readString()!!, body = parcel.readString()!!, date = parcel.readString()!!, - host = parcel.readString()!!, + url = parcel.readParcelableCompat()!!, timestamp = parcel.readLong(), deepLink = parcel.readString()!!, wallet = parcel.readParcelableCompat()!! @@ -149,7 +166,7 @@ sealed class HistoryItem( dest.writeString(title) dest.writeString(body) dest.writeString(date) - dest.writeString(host) + dest.writeParcelable(url, flags) dest.writeLong(timestamp) dest.writeString(deepLink) dest.writeParcelable(wallet, flags) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/helper/BrowserHelper.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/helper/BrowserHelper.kt index 939161017..bb6c70fa5 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/helper/BrowserHelper.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/helper/BrowserHelper.kt @@ -8,6 +8,7 @@ import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsIntent import com.tonapps.extensions.activity import com.tonapps.extensions.locale +import com.tonapps.tonkeeper.core.entities.WalletPurchaseMethodEntity import com.tonapps.tonkeeper.extensions.showToast import com.tonapps.uikit.color.backgroundPageColor import com.tonapps.uikit.color.textPrimaryColor @@ -15,6 +16,12 @@ import com.tonapps.wallet.localization.Localization object BrowserHelper { + fun openPurchase(context: Context, method: WalletPurchaseMethodEntity) { + context.activity?.let { + open(it, method.uri) + } + } + fun open(context: Context, url: String) { context.activity?.let { open(it, url) 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 27cc38941..c1182d428 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 @@ -1,6 +1,5 @@ package com.tonapps.tonkeeper.koin -import androidx.lifecycle.viewmodel.viewModelFactory import org.koin.dsl.module import com.tonapps.tonkeeper.ui.screen.wallet.main.WalletViewModel import com.tonapps.tonkeeper.ui.screen.settings.main.SettingsViewModel @@ -21,7 +20,7 @@ import com.tonapps.tonkeeper.ui.screen.battery.settings.BatterySettingsViewModel import com.tonapps.tonkeeper.ui.screen.battery.refill.BatteryRefillViewModel import com.tonapps.tonkeeper.ui.screen.battery.recharge.BatteryRechargeViewModel import com.tonapps.tonkeeper.ui.screen.send.contacts.main.SendContactsViewModel -import com.tonapps.tonkeeper.ui.screen.purchase.main.PurchaseViewModel +import com.tonapps.tonkeeper.ui.screen.purchase.PurchaseViewModel import com.tonapps.tonkeeper.ui.screen.nft.NftViewModel import com.tonapps.tonkeeper.ui.screen.send.contacts.add.AddContactViewModel import com.tonapps.tonkeeper.ui.screen.send.contacts.edit.EditContactViewModel 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 b6abe07e6..17c241c42 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,8 +1,6 @@ package com.tonapps.tonkeeper.manager.tonconnect.bridge -import android.util.Log import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.tonapps.blockchain.ton.proof.TONProof import com.tonapps.extensions.base64 import com.tonapps.extensions.optStringCompat import com.tonapps.security.CryptoBox @@ -10,7 +8,6 @@ import com.tonapps.security.hex import com.tonapps.tonkeeper.manager.tonconnect.bridge.model.BridgeError import com.tonapps.tonkeeper.manager.tonconnect.bridge.model.BridgeEvent import com.tonapps.wallet.api.API -import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.dapps.entities.AppConnectEntity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/BridgeConnectHelper.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/BridgeConnectHelper.kt deleted file mode 100644 index 6620c95ec..000000000 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/manager/tonconnect/bridge/BridgeConnectHelper.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.tonapps.tonkeeper.manager.tonconnect.bridge - -internal object BridgeConnectHelper { -} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/MainRecyclerView.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/MainRecyclerView.kt index 87cfc6368..d2bef83fd 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/MainRecyclerView.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/component/MainRecyclerView.kt @@ -10,7 +10,9 @@ import androidx.core.view.updatePadding import blur.BlurCompat import com.tonapps.tonkeeper.isBlurDisabled import com.tonapps.tonkeeper.isLowDevice +import com.tonapps.tonkeeperx.R import uikit.extensions.getDimensionPixelSize +import uikit.extensions.useAttributes import uikit.widget.SimpleRecyclerView class MainRecyclerView @JvmOverloads constructor( @@ -19,17 +21,20 @@ class MainRecyclerView @JvmOverloads constructor( defStyle: Int = 0, ) : SimpleRecyclerView(context, attrs, defStyle) { - private val paddingVertical = context.getDimensionPixelSize(uikit.R.dimen.offsetMedium) - private val barSize = context.getDimensionPixelSize(uikit.R.dimen.barHeight) + private val initialPadding: Int by lazy { paddingTop } + private val initialPaddingBottom: Int by lazy { paddingBottom } + private val defaultBarSize = context.getDimensionPixelSize(uikit.R.dimen.barHeight) + private var topBarSize = defaultBarSize + private var bottomBarSize = defaultBarSize private var topOffset = 0 private var bottomOffset = 0 val topPadding: Int - get() = topOffset + barSize + get() = topOffset + topBarSize private val bottomPadding: Int - get() = bottomOffset + barSize + get() = bottomOffset + bottomBarSize private val blurDisabled = context.isBlurDisabled private val topBlur: BlurCompat? = if (!blurDisabled) BlurCompat(context) else null @@ -39,6 +44,11 @@ class MainRecyclerView @JvmOverloads constructor( if (bottomBlur?.hasBlur == true) { overScrollMode = OVER_SCROLL_NEVER } + + context.useAttributes(attrs, R.styleable.MainRecyclerView) { + topBarSize = it.getDimensionPixelSize(R.styleable.MainRecyclerView_android_topOffset, defaultBarSize) + bottomBarSize = it.getDimensionPixelSize(R.styleable.MainRecyclerView_android_bottomOffset, defaultBarSize) + } } override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { @@ -48,8 +58,8 @@ class MainRecyclerView @JvmOverloads constructor( topOffset = statusInsets.top bottomOffset = navigationInsets.bottom updatePadding( - top = paddingVertical + topPadding, - bottom = paddingVertical + bottomPadding + top = initialPadding + topPadding, + bottom = initialPaddingBottom + bottomPadding ) applyBlurBounds() return super.onApplyWindowInsets(insets) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/collectibles/CollectiblesScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/collectibles/CollectiblesScreen.kt index 7949cd4da..12b2cb0fa 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/collectibles/CollectiblesScreen.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/collectibles/CollectiblesScreen.kt @@ -101,9 +101,9 @@ class CollectiblesScreen(wallet: WalletEntity): MainScreen.Child(R.layout.fragme return null } - override fun getHeaderDividerOwner(): BarDrawable.BarDrawableOwner? { + override fun getTopBarDrawable(): BarDrawable? { if (this::headerView.isInitialized) { - return headerView + return headerView.background as? BarDrawable } return null } diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsScreen.kt index e59676483..cb5623f4c 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsScreen.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/EventsScreen.kt @@ -1,30 +1,29 @@ package com.tonapps.tonkeeper.ui.screen.events import android.os.Bundle -import android.util.Log import android.view.View import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.tonapps.tonkeeper.core.history.list.HistoryAdapter import com.tonapps.tonkeeper.core.history.list.HistoryItemDecoration -import com.tonapps.tonkeeper.core.history.list.item.HistoryItem import com.tonapps.tonkeeper.koin.walletViewModel +import com.tonapps.tonkeeper.ui.screen.events.filters.FiltersAdapter import com.tonapps.tonkeeper.ui.screen.main.MainScreen -import com.tonapps.tonkeeper.ui.screen.purchase.main.PurchaseScreen +import com.tonapps.tonkeeper.ui.screen.purchase.PurchaseScreen import com.tonapps.tonkeeper.ui.screen.qr.QRScreen import com.tonapps.tonkeeperx.R import com.tonapps.uikit.color.backgroundTransparentColor +import com.tonapps.uikit.list.LinearLayoutManager import com.tonapps.uikit.list.ListPaginationListener import com.tonapps.wallet.api.entity.TokenEntity import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.localization.Localization import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.parameter.parametersOf import uikit.drawable.BarDrawable +import uikit.drawable.HeaderDrawable import uikit.extensions.collectFlow -import uikit.navigation.Navigation.Companion.navigation +import uikit.extensions.dp import uikit.widget.EmptyLayout import uikit.widget.HeaderView @@ -33,6 +32,10 @@ class EventsScreen(wallet: WalletEntity) : MainScreen.Child(R.layout.fragment_ma override val viewModel: EventsViewModel by walletViewModel() private val legacyAdapter = HistoryAdapter() + private val filtersAdapter = FiltersAdapter { + viewModel.clickFilter(it) + } + private val paginationListener = object : ListPaginationListener() { override fun onLoadMore() { viewModel.loadMore() @@ -40,7 +43,7 @@ class EventsScreen(wallet: WalletEntity) : MainScreen.Child(R.layout.fragment_ma } private lateinit var headerView: HeaderView - private lateinit var containerView: View + private lateinit var headerDrawable: HeaderDrawable private lateinit var refreshView: SwipeRefreshLayout private lateinit var listView: RecyclerView private lateinit var filtersView: RecyclerView @@ -53,13 +56,23 @@ class EventsScreen(wallet: WalletEntity) : MainScreen.Child(R.layout.fragment_ma headerView.setSubtitle(Localization.updating) headerView.setColor(requireContext().backgroundTransparentColor) - containerView = view.findViewById(R.id.container) refreshView = view.findViewById(R.id.refresh) refreshView.setOnRefreshListener { viewModel.refresh() } + headerDrawable = HeaderDrawable(requireContext()) + headerDrawable.setColor(requireContext().backgroundTransparentColor) + filtersView = view.findViewById(R.id.filters) + filtersView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false) + filtersView.adapter = filtersAdapter + filtersView.background = headerDrawable + filtersView.addItemDecoration(object : RecyclerView.ItemDecoration() { + override fun getItemOffsets(outRect: android.graphics.Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + outRect.right = 8.dp + } + }) listView = view.findViewById(R.id.list) listView.adapter = legacyAdapter @@ -76,6 +89,7 @@ class EventsScreen(wallet: WalletEntity) : MainScreen.Child(R.layout.fragment_ma } collectFlow(viewModel.uiStateFlow, ::applyState) + collectFlow(viewModel.uiFilterItemsFlow, filtersAdapter::submitList) } private suspend fun applyState(state: EventsUiState) = withContext(Dispatchers.Main) { @@ -122,15 +136,15 @@ class EventsScreen(wallet: WalletEntity) : MainScreen.Child(R.layout.fragment_ma } headerView.setSubtitle(null) emptyView.visibility = View.VISIBLE - containerView.visibility = View.GONE + refreshView.visibility = View.GONE } private fun setListState() { - if (containerView.visibility == View.VISIBLE) { + if (refreshView.visibility == View.VISIBLE) { return } emptyView.visibility = View.GONE - containerView.visibility = View.VISIBLE + refreshView.visibility = View.VISIBLE } override fun getRecyclerView(): RecyclerView? { @@ -140,9 +154,9 @@ class EventsScreen(wallet: WalletEntity) : MainScreen.Child(R.layout.fragment_ma return null } - override fun getHeaderDividerOwner(): BarDrawable.BarDrawableOwner? { - if (this::headerView.isInitialized) { - return headerView + override fun getTopBarDrawable(): BarDrawable? { + if (this::headerDrawable.isInitialized) { + return headerDrawable } return null } 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 4b6b5abca..aa822332f 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 @@ -4,45 +4,82 @@ import android.app.Application import android.util.Log import androidx.lifecycle.viewModelScope import com.tonapps.tonkeeper.api.AccountEventWrap -import com.tonapps.tonkeeper.core.entities.AssetsExtendedEntity +import com.tonapps.tonkeeper.api.isOutTransfer import com.tonapps.tonkeeper.core.history.HistoryHelper import com.tonapps.tonkeeper.core.history.list.item.HistoryItem import com.tonapps.tonkeeper.manager.tx.TransactionManager import com.tonapps.tonkeeper.ui.base.BaseWalletVM +import com.tonapps.tonkeeper.ui.screen.events.filters.FilterItem +import com.tonapps.wallet.api.API +import com.tonapps.wallet.data.account.AccountRepository import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.core.ScreenCacheSource +import com.tonapps.wallet.data.dapps.DAppsRepository +import com.tonapps.wallet.data.dapps.entities.AppEntity +import com.tonapps.wallet.data.dapps.entities.AppPushEntity 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.async import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger import kotlin.time.Duration.Companion.seconds // TODO: Refactor this class class EventsViewModel( app: Application, private val wallet: WalletEntity, + private val accountsRepository: AccountRepository, private val eventsRepository: EventsRepository, private val historyHelper: HistoryHelper, private val screenCacheSource: ScreenCacheSource, private val settingsRepository: SettingsRepository, private val transactionManager: TransactionManager, + private val dAppsRepository: DAppsRepository, ): BaseWalletVM(app) { private var autoRefreshJob: Job? = null private var events: Array? = null + private var pushes: Array? = null private val isLoading: AtomicBoolean = AtomicBoolean(true) + private val txFilter = AtomicInteger(TX_FILTER_NONE) + + private val _selectedFilter = MutableStateFlow(null) + private val selectedFilter = _selectedFilter.asStateFlow() + + private val _filterAppsFlow = MutableStateFlow>(emptyList()) + private val filterAppsFlow = _filterAppsFlow.asStateFlow() + + val uiFilterItemsFlow: Flow> = combine( + selectedFilter, + filterAppsFlow, + ) { selected, apps -> + val uiFilterItems = mutableListOf() + apps.forEach { app -> + uiFilterItems.add(FilterItem.App(selected?.id == app.id, app)) + } + uiFilterItems.add(FilterItem.Send(selected?.type == FilterItem.TYPE_SEND)) + uiFilterItems.add(FilterItem.Receive(selected?.type == FilterItem.TYPE_RECEIVE)) + uiFilterItems.toList() + } + private val _uiStateFlow = MutableStateFlow(EventsUiState()) val uiStateFlow = _uiStateFlow.stateIn(viewModelScope, SharingStarted.Eagerly, EventsUiState()) @@ -51,7 +88,13 @@ class EventsViewModel( viewModelScope.launch(Dispatchers.IO) { setUiItems(getCached()) submitEvents(cache(), true) - submitEvents(load(), false) + + val eventsDeferred = async { load() } + val dappEventsDeferred = async { loadDAppEvents() } + + submitEvents(eventsDeferred.await(), loading = false, updateState = false) + submitPushes(dappEventsDeferred.await(), updateState = false) + updateState() } eventsRepository.decryptedCommentFlow.collectFlow { @@ -75,6 +118,44 @@ class EventsViewModel( delay(35.seconds) } } + + selectedFilter.collectFlow { filter -> + val txFilterValue = if (filter == null) { + TX_FILTER_NONE + } else { + when (filter.id) { + FilterItem.SEND_ID -> TX_FILTER_SENT + FilterItem.RECEIVE_ID -> TX_FILTER_RECEIVED + else -> TX_FILTER_APP + } + } + + txFilter.set(txFilterValue) + + if (txFilterValue == TX_FILTER_APP) { + submitEvents(emptyList(), false) + } else { + submitEvents(emptyList(), true) + submitEvents(load(), false) + } + } + } + + fun clickFilter(filter: FilterItem) { + if (_selectedFilter.value?.id == filter.id) { + _selectedFilter.value = null + } else { + _selectedFilter.value = filter + } + } + + private suspend fun loadDAppEvents(): List { + if (!wallet.isTonConnectSupported) { + return emptyList() + } + + val tonProof = accountsRepository.requestTonProofToken(wallet) ?: return emptyList() + return dAppsRepository.getPushes(tonProof, wallet.accountId) } private suspend fun checkAutoRefresh() { @@ -95,6 +176,7 @@ class EventsViewModel( } private suspend fun requestRefresh() = withContext(Dispatchers.IO) { + submitPushes(loadDAppEvents()) submitEvents(load(), false) } @@ -135,14 +217,39 @@ class EventsViewModel( ) } - private suspend fun mapping(events: List): List { - val items = historyHelper.mapping( + private suspend fun mapping(events: List, pushes: List): List { + val txFilterValue = txFilter.get() + + if (txFilterValue == TX_FILTER_APP) { + val selectedFilter = selectedFilter.value as? FilterItem.App ?: return emptyList() + + val pushItems = pushes.map { + HistoryItem.App(context, wallet, it) + }.filter { it.url == selectedFilter.url } + return historyHelper.groupByDate(pushItems) + } + + val eventItems = historyHelper.mapping( wallet = wallet, events = events.map { it.copy() }, removeDate = false, hiddenBalances = settingsRepository.hiddenBalances ) - return historyHelper.groupByDate(items) + + if (txFilterValue == TX_FILTER_SENT || txFilterValue == TX_FILTER_RECEIVED) { + return historyHelper.groupByDate(eventItems) + } + + val firstTimestamp = events.firstOrNull()?.timestamp ?: 0 + val lastTimestamp = events.lastOrNull()?.timestamp ?: 0 + val eventsTimestampRange = firstTimestamp..lastTimestamp + + val pushItems = pushes.map { + HistoryItem.App(context, wallet, it) + }.filter { it.timestamp in eventsTimestampRange } + + + return historyHelper.groupByDate(eventItems + pushItems) } private fun getCached(): List { @@ -153,17 +260,37 @@ class EventsViewModel( private suspend fun updateState() = withContext(Dispatchers.IO) { val events = getEvents() - val uiItems = mapping(events.map { it.event }) + val uiItems = mapping(events.map { it.event }, pushes?.toList() ?: emptyList()) setUiItems(uiItems) - screenCacheSource.set(CACHE_NAME, wallet.id, uiItems) + if (txFilter.get() == TX_FILTER_NONE) { + screenCacheSource.set(CACHE_NAME, wallet.id, uiItems) + } + } + + private suspend fun submitPushes( + newPushes: List, + updateState: Boolean = true + ) { + pushes = newPushes.sortedByDescending { it.timestamp }.toTypedArray() + _filterAppsFlow.value = newPushes.map { it.from }.distinctBy { it.id } + if (updateState) { + updateState() + } } - private suspend fun submitEvents(newEvents: List, loading: Boolean) = withContext(Dispatchers.IO) { + private suspend fun submitEvents( + newEvents: List, + loading: Boolean, + updateState: Boolean = true + ) = withContext(Dispatchers.IO) { events = newEvents.distinctBy { it.eventId } .sortedByDescending { it.timestamp } .toTypedArray() + isLoading.set(loading) - updateState() + if (updateState) { + updateState() + } } private suspend fun getEvents(): MutableList = withContext(Dispatchers.IO) { @@ -191,7 +318,55 @@ class EventsViewModel( return events?.firstOrNull { it.inProgress } != null } + private suspend fun loadWithFilters(onlySent: Boolean, beforeLt: Long? = null): List { + return loadUntil(onlySent = onlySent, beforeLt = beforeLt).map(::AccountEventWrap) + } + + private suspend fun loadUntil( + max: Int = 25, + onlySent: Boolean, + beforeLt: Long? = null + ): List { + val list = mutableListOf() + var nextBeforeLt = beforeLt + do { + val events = loadEvents(beforeLt = nextBeforeLt) ?: break + list.addAll(events.filter { event -> + event.isOutTransfer(wallet) == onlySent + }) + if (list.size >= max) break + nextBeforeLt = events.last().lt + } while (true) + return list.toList() + } + + private suspend fun loadEvents(limit: Int = 50, beforeLt: Long? = null): List? { + val events = eventsRepository.getRemote( + accountId = wallet.accountId, + testnet = wallet.testnet, + limit = limit, + beforeLt = beforeLt + )?.events + if (events.isNullOrEmpty()) { + return null + } + return events + } + private suspend fun load(beforeLt: Long? = null): List { + val txFilterValue = txFilter.get() + if (txFilterValue == TX_FILTER_SENT) { + return loadSent(beforeLt) + } else if (txFilterValue == TX_FILTER_RECEIVED) { + return loadReceived(beforeLt) + } else if (txFilterValue == TX_FILTER_APP) { + return emptyList() + } + return loadDefault(beforeLt) + } + + + private suspend fun loadDefault(beforeLt: Long?): List { val list = eventsRepository.getRemote( accountId = wallet.accountId, testnet = wallet.testnet, @@ -200,6 +375,14 @@ class EventsViewModel( return list ?: emptyList() } + private suspend fun loadSent(beforeLt: Long?): List { + return loadWithFilters(true, beforeLt) + } + + private suspend fun loadReceived(beforeLt: Long?): List { + return loadWithFilters(false, beforeLt) + } + private suspend fun cache(): List { val list = eventsRepository.getLocal( accountId = wallet.accountId, @@ -216,5 +399,10 @@ class EventsViewModel( private companion object { private const val CACHE_NAME = "events" + + private const val TX_FILTER_NONE = 0 + private const val TX_FILTER_SENT = 1 + private const val TX_FILTER_RECEIVED = 2 + private const val TX_FILTER_APP = 3 } } \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FilterItem.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FilterItem.kt new file mode 100644 index 000000000..0917ad531 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FilterItem.kt @@ -0,0 +1,38 @@ +package com.tonapps.tonkeeper.ui.screen.events.filters + +import android.net.Uri +import androidx.core.net.toUri +import com.tonapps.uikit.list.BaseListItem +import com.tonapps.wallet.data.dapps.entities.AppEntity + +sealed class FilterItem(type: Int, open val selected: Boolean, open val id: String): BaseListItem(type) { + + companion object { + const val TYPE_SEND = 1 + const val TYPE_RECEIVE = 2 + const val TYPE_APP = 3 + + const val SEND_ID = "send" + const val RECEIVE_ID = "receive" + } + + data class Send(override val selected: Boolean) : FilterItem(TYPE_SEND, selected, SEND_ID) + + data class Receive(override val selected: Boolean) : FilterItem(TYPE_RECEIVE, selected, RECEIVE_ID) + + data class App( + override val selected: Boolean, + val app: AppEntity, + ): FilterItem(TYPE_APP, selected, app.id) { + + val name: String + get() = app.name + + val iconUrl: Uri + get() = app.iconUrl.toUri() + + val url: Uri + get() = app.url + } + +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FiltersAdapter.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FiltersAdapter.kt new file mode 100644 index 000000000..1442af395 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/FiltersAdapter.kt @@ -0,0 +1,20 @@ +package com.tonapps.tonkeeper.ui.screen.events.filters + +import android.view.ViewGroup +import com.tonapps.tonkeeper.ui.screen.events.filters.holder.AppHolder +import com.tonapps.tonkeeper.ui.screen.events.filters.holder.FilterHolder +import com.tonapps.uikit.list.BaseListAdapter +import com.tonapps.uikit.list.BaseListHolder +import com.tonapps.uikit.list.BaseListItem + +class FiltersAdapter(private val onClick: (item: FilterItem) -> Unit): BaseListAdapter() { + + override fun createHolder(parent: ViewGroup, viewType: Int): BaseListHolder { + return when(viewType) { + FilterItem.TYPE_SEND, FilterItem.TYPE_RECEIVE -> FilterHolder(parent, onClick) + FilterItem.TYPE_APP -> AppHolder(parent, onClick) + else -> throw IllegalArgumentException("Unknown viewType: $viewType") + } + } + +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/Item.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/Item.kt deleted file mode 100644 index f639ebb75..000000000 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/Item.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.tonapps.tonkeeper.ui.screen.events.filters - -class Item { -} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/AppHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/AppHolder.kt new file mode 100644 index 000000000..7e1f992a2 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/AppHolder.kt @@ -0,0 +1,39 @@ +package com.tonapps.tonkeeper.ui.screen.events.filters.holder + +import android.view.View +import android.view.ViewGroup +import androidx.core.net.toUri +import androidx.core.view.updatePadding +import com.tonapps.tonkeeper.ui.screen.events.filters.FilterItem +import com.tonapps.tonkeeperx.R +import uikit.extensions.dp +import uikit.extensions.setPaddingHorizontal +import uikit.widget.FrescoView + +class AppHolder( + parent: ViewGroup, + private val onClick: (item: FilterItem) -> Unit +): Holder(parent) { + + private val iconView = findViewById(R.id.icon) + + init { + itemView.updatePadding( + left = 6.dp, + right = 14.dp + ) + iconView.visibility = View.VISIBLE + } + + override fun onBind(item: FilterItem.App) { + itemView.setOnClickListener { onClick(item) } + titleView.text = item.name + iconView.setImageURI(item.iconUrl, null) + updateSelected(item) + } + + fun updateSelected(item: FilterItem) { + setSelected(item.selected) + } + +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/FilterHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/FilterHolder.kt new file mode 100644 index 000000000..120ad7129 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/FilterHolder.kt @@ -0,0 +1,32 @@ +package com.tonapps.tonkeeper.ui.screen.events.filters.holder + +import android.view.ViewGroup +import com.tonapps.tonkeeper.ui.screen.events.filters.FilterItem +import com.tonapps.wallet.localization.Localization +import uikit.extensions.dp +import uikit.extensions.setPaddingHorizontal + +class FilterHolder( + parent: ViewGroup, + private val onClick: (item: FilterItem) -> Unit +): Holder(parent) { + + init { + itemView.setPaddingHorizontal(14.dp) + } + + override fun onBind(item: FilterItem) { + itemView.setOnClickListener { onClick(item) } + if (item.type == FilterItem.TYPE_SEND) { + titleView.setText(Localization.sent) + } else if (item.type == FilterItem.TYPE_RECEIVE) { + titleView.setText(Localization.received) + } + updateSelected(item) + } + + fun updateSelected(item: FilterItem) { + setSelected(item.selected) + } + +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/Holder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/Holder.kt new file mode 100644 index 000000000..b4b661519 --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/events/filters/holder/Holder.kt @@ -0,0 +1,22 @@ +package com.tonapps.tonkeeper.ui.screen.events.filters.holder + +import android.view.ViewGroup +import androidx.appcompat.widget.AppCompatTextView +import com.tonapps.tonkeeper.ui.screen.events.filters.FilterItem +import com.tonapps.tonkeeperx.R +import com.tonapps.uikit.color.buttonPrimaryBackgroundColor +import com.tonapps.uikit.color.buttonSecondaryBackgroundColor +import com.tonapps.uikit.color.stateList +import com.tonapps.uikit.list.BaseListHolder + +abstract class Holder( + parent: ViewGroup, +): BaseListHolder(parent, R.layout.view_filter_chip) { + + val titleView = itemView.findViewById(R.id.title) + + fun setSelected(selected: Boolean) { + val color = if (selected) context.buttonPrimaryBackgroundColor else context.buttonSecondaryBackgroundColor + itemView.backgroundTintList = color.stateList + } +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/main/MainScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/main/MainScreen.kt index d3fafec5d..0b01fb330 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/main/MainScreen.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/main/MainScreen.kt @@ -50,14 +50,14 @@ class MainScreen: BaseWalletScreen(R.layout.fragment_main, S private val scrollListener = object : RecyclerVerticalScrollListener() { override fun onScrolled(recyclerView: RecyclerView, verticalScrollOffset: Int) { - getHeaderDividerOwner()?.setDivider(verticalScrollOffset > 0) + getTopBarDrawable()?.setDivider(verticalScrollOffset > 0) mainViewModel.setBottomScrolled(!recyclerView.isMaxScrollReached) } } abstract fun getRecyclerView(): RecyclerView? - abstract fun getHeaderDividerOwner(): BarDrawable.BarDrawableOwner? + abstract fun getTopBarDrawable(): BarDrawable? open fun scrollUp() { getRecyclerView()?.scrollToPosition(0) diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseConfirmDialog.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseConfirmDialog.kt similarity index 98% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseConfirmDialog.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseConfirmDialog.kt index 07af66f79..feb530e14 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseConfirmDialog.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseConfirmDialog.kt @@ -1,4 +1,4 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main +package com.tonapps.tonkeeper.ui.screen.purchase import android.content.Context import android.view.View diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseScreen.kt similarity index 82% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseScreen.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseScreen.kt index f9cbd2183..46a5c89b0 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseScreen.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseScreen.kt @@ -1,39 +1,27 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main +package com.tonapps.tonkeeper.ui.screen.purchase import android.os.Bundle import android.util.Log import android.view.View import androidx.appcompat.widget.AppCompatTextView -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView import com.tonapps.tonkeeper.core.entities.WalletPurchaseMethodEntity import com.tonapps.tonkeeper.extensions.countryEmoji +import com.tonapps.tonkeeper.helper.BrowserHelper import com.tonapps.tonkeeper.koin.walletViewModel -import com.tonapps.tonkeeper.ui.base.BaseWalletScreen -import com.tonapps.tonkeeper.ui.base.ScreenContext import com.tonapps.tonkeeper.ui.base.WalletContextScreen import com.tonapps.tonkeeper.ui.screen.country.CountryPickerScreen -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.Adapter -import com.tonapps.tonkeeper.ui.screen.purchase.web.PurchaseWebScreen +import com.tonapps.tonkeeper.ui.screen.purchase.list.Adapter import com.tonapps.tonkeeperx.R import com.tonapps.wallet.api.API import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.purchase.entity.PurchaseMethodEntity import com.tonapps.wallet.data.settings.SettingsRepository -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.suspendCancellableCoroutine import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.parameter.parametersOf import uikit.base.BaseFragment import uikit.extensions.applyNavBottomPadding import uikit.extensions.collectFlow -import uikit.navigation.Navigation.Companion.navigation import uikit.navigation.NavigationActivity -import kotlin.coroutines.resume class PurchaseScreen(wallet: WalletEntity): WalletContextScreen(R.layout.fragment_purchase, wallet), BaseFragment.BottomSheet { @@ -106,10 +94,10 @@ class PurchaseScreen(wallet: WalletEntity): WalletContextScreen(R.layout.fragmen if (!showAgain) { viewModel.disableConfirmDialog(screenContext.wallet, method) } - PurchaseWebScreen.open(activity, methodWrapped) + BrowserHelper.openPurchase(activity, methodWrapped) } } else { - PurchaseWebScreen.open(activity, methodWrapped) + BrowserHelper.openPurchase(activity, methodWrapped) } } diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseViewModel.kt similarity index 90% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseViewModel.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseViewModel.kt index 68c4b3b47..25343913e 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/PurchaseViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/PurchaseViewModel.kt @@ -1,11 +1,9 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main +package com.tonapps.tonkeeper.ui.screen.purchase import android.app.Application -import androidx.lifecycle.ViewModel import com.tonapps.tonkeeper.ui.base.BaseWalletVM -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.Item +import com.tonapps.tonkeeper.ui.screen.purchase.list.Item import com.tonapps.uikit.list.ListCell -import com.tonapps.wallet.data.account.AccountRepository import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.purchase.PurchaseRepository import com.tonapps.wallet.data.purchase.entity.PurchaseMethodEntity @@ -17,7 +15,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.take class PurchaseViewModel( app: Application, diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/Adapter.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/Adapter.kt similarity index 76% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/Adapter.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/Adapter.kt index dbf7cbbb9..8c64792fb 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/Adapter.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/Adapter.kt @@ -1,10 +1,10 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main.list +package com.tonapps.tonkeeper.ui.screen.purchase.list import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder.MethodHolder -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder.SpaceHolder -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder.TitleHolder +import com.tonapps.tonkeeper.ui.screen.purchase.list.holder.MethodHolder +import com.tonapps.tonkeeper.ui.screen.purchase.list.holder.SpaceHolder +import com.tonapps.tonkeeper.ui.screen.purchase.list.holder.TitleHolder import com.tonapps.uikit.list.BaseListAdapter import com.tonapps.uikit.list.BaseListHolder import com.tonapps.uikit.list.BaseListItem diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/Item.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/Item.kt similarity index 93% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/Item.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/Item.kt index 48c5cd40d..5db086ddd 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/Item.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/Item.kt @@ -1,4 +1,4 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main.list +package com.tonapps.tonkeeper.ui.screen.purchase.list import android.net.Uri import com.tonapps.uikit.list.BaseListItem diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/Holder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/Holder.kt similarity index 64% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/Holder.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/Holder.kt index 7923a7ff1..fc48bacc9 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/Holder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/Holder.kt @@ -1,8 +1,8 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder +package com.tonapps.tonkeeper.ui.screen.purchase.list.holder import android.view.ViewGroup import androidx.annotation.LayoutRes -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.Item +import com.tonapps.tonkeeper.ui.screen.purchase.list.Item import com.tonapps.uikit.list.BaseListHolder abstract class Holder( diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/MethodHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/MethodHolder.kt similarity index 87% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/MethodHolder.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/MethodHolder.kt index 49ddb7f57..6fb5332a3 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/MethodHolder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/MethodHolder.kt @@ -1,8 +1,8 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder +package com.tonapps.tonkeeper.ui.screen.purchase.list.holder import android.view.ViewGroup import androidx.appcompat.widget.AppCompatTextView -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.Item +import com.tonapps.tonkeeper.ui.screen.purchase.list.Item import com.tonapps.tonkeeperx.R import com.tonapps.wallet.data.purchase.entity.PurchaseMethodEntity import uikit.extensions.drawable diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/SpaceHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/SpaceHolder.kt similarity index 62% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/SpaceHolder.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/SpaceHolder.kt index 73684bf11..55cc8be91 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/SpaceHolder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/SpaceHolder.kt @@ -1,7 +1,7 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder +package com.tonapps.tonkeeper.ui.screen.purchase.list.holder import android.view.ViewGroup -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.Item +import com.tonapps.tonkeeper.ui.screen.purchase.list.Item import com.tonapps.tonkeeperx.R class SpaceHolder(parent: ViewGroup): Holder(parent, R.layout.view_item_space_medium) { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/TitleHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/TitleHolder.kt similarity index 74% rename from apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/TitleHolder.kt rename to apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/TitleHolder.kt index 7db6f929e..54fbcd0bf 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/main/list/holder/TitleHolder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/list/holder/TitleHolder.kt @@ -1,8 +1,8 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.main.list.holder +package com.tonapps.tonkeeper.ui.screen.purchase.list.holder import android.view.ViewGroup import androidx.appcompat.widget.AppCompatTextView -import com.tonapps.tonkeeper.ui.screen.purchase.main.list.Item +import com.tonapps.tonkeeper.ui.screen.purchase.list.Item import com.tonapps.tonkeeperx.R class TitleHolder(parent: ViewGroup): Holder(parent, R.layout.view_purchase_title) { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/web/PurchaseWebScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/web/PurchaseWebScreen.kt deleted file mode 100644 index b47be961f..000000000 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/purchase/web/PurchaseWebScreen.kt +++ /dev/null @@ -1,107 +0,0 @@ -package com.tonapps.tonkeeper.ui.screen.purchase.web - -import android.content.Context -import android.graphics.Bitmap -import android.os.Bundle -import android.view.View -import com.tonapps.extensions.activity -import com.tonapps.extensions.getParcelableCompat -import com.tonapps.tonkeeper.core.AnalyticsHelper -import com.tonapps.tonkeeper.helper.BrowserHelper -import com.tonapps.tonkeeper.core.entities.WalletPurchaseMethodEntity -import com.tonapps.tonkeeper.ui.base.BaseWalletVM -import com.tonapps.tonkeeper.ui.base.WalletContextScreen -import com.tonapps.tonkeeper.ui.screen.purchase.main.PurchaseScreen -import com.tonapps.tonkeeperx.R -import com.tonapps.wallet.data.account.entities.WalletEntity -import org.koin.androidx.viewmodel.ext.android.viewModel -import uikit.navigation.NavigationActivity -import uikit.widget.HeaderView -import uikit.widget.LoaderView -import uikit.widget.webview.WebViewFixed - - -class PurchaseWebScreen(wallet: WalletEntity): WalletContextScreen(R.layout.fragment_purchase_web, wallet) { - - override val viewModel: BaseWalletVM.EmptyViewViewModel by viewModel() - - private val method: WalletPurchaseMethodEntity by lazy { - requireArguments().getParcelableCompat(METHOD_KEY)!! - } - - private lateinit var headerView: HeaderView - private lateinit var loaderView: LoaderView - private lateinit var webView: WebViewFixed - - private val webViewCallback = object : WebViewFixed.Callback() { - - override fun onPageFinished(url: String) { - super.onPageFinished(url) - webView.visibility = View.VISIBLE - loaderView.visibility = View.GONE - } - - override fun onPageStarted(url: String, favicon: Bitmap?) { - super.onPageStarted(url, favicon) - if (url.matches(".*#endsession".toRegex())) { - finish() - return - } - - val successUrlPattern = method.successUrlPattern?.pattern ?: return - val regexp = Regex(successUrlPattern, RegexOption.IGNORE_CASE) - - regexp.find(url)?.groupValues ?: return - AnalyticsHelper.trackEvent("buy_crypto") - finish() - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - headerView = view.findViewById(R.id.header) - headerView.doOnActionClick = { finish() } - - loaderView = view.findViewById(R.id.loader) - - webView = view.findViewById(R.id.web) - webView.addCallback(webViewCallback) - webView.loadUrl(method.uri) - } - - override fun onPause() { - super.onPause() - webView.onPause() - } - - override fun onResume() { - super.onResume() - webView.onResume() - } - - override fun onDestroyView() { - super.onDestroyView() - navigation?.add(PurchaseScreen.newInstance(screenContext.wallet)) - webView.removeCallback(webViewCallback) - webView.destroy() - } - - companion object { - private const val METHOD_KEY = "method" - - fun open(context: Context, method: WalletPurchaseMethodEntity) { - val activity = context.activity ?: throw IllegalStateException("Activity not found") - open(activity, method) - } - - fun open(activity: NavigationActivity, method: WalletPurchaseMethodEntity) { - if (method.useCustomTabs) { - BrowserHelper.open(activity, method.uri) - } else { - val fragment = PurchaseWebScreen(method.wallet) - fragment.putParcelableArg(METHOD_KEY, method) - activity.add(fragment) - } - } - } -} \ 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 e6e1b43df..992380227 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 @@ -3,7 +3,6 @@ package com.tonapps.tonkeeper.ui.screen.root import android.app.Application import android.net.Uri import android.os.Bundle -import android.util.Log import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.net.toUri @@ -37,6 +36,7 @@ import com.tonapps.tonkeeper.core.history.list.item.HistoryItem import com.tonapps.tonkeeper.deeplink.DeepLink import com.tonapps.tonkeeper.deeplink.DeepLinkRoute import com.tonapps.tonkeeper.extensions.safeExternalOpenUri +import com.tonapps.tonkeeper.helper.BrowserHelper import com.tonapps.tonkeeper.helper.ShortcutHelper import com.tonapps.tonkeeper.manager.push.FirebasePush import com.tonapps.tonkeeper.manager.push.PushManager @@ -49,8 +49,7 @@ import com.tonapps.tonkeeper.ui.screen.browser.dapp.DAppScreen import com.tonapps.tonkeeper.ui.screen.camera.CameraScreen import com.tonapps.tonkeeper.ui.screen.init.list.AccountItem import com.tonapps.tonkeeper.ui.screen.name.edit.EditNameScreen -import com.tonapps.tonkeeper.ui.screen.purchase.main.PurchaseScreen -import com.tonapps.tonkeeper.ui.screen.purchase.web.PurchaseWebScreen +import com.tonapps.tonkeeper.ui.screen.purchase.PurchaseScreen import com.tonapps.tonkeeper.ui.screen.qr.QRScreen import com.tonapps.tonkeeper.ui.screen.send.main.SendScreen import com.tonapps.tonkeeper.ui.screen.send.transaction.SendTransactionScreen @@ -448,7 +447,7 @@ class RootViewModel( if (method == null) { toast(Localization.payment_method_not_found) } else { - PurchaseWebScreen.open(context, WalletPurchaseMethodEntity( + BrowserHelper.openPurchase(context, WalletPurchaseMethodEntity( method = method, wallet = wallet, currency = settingsRepository.currency.code, diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/InsufficientFundsDialog.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/InsufficientFundsDialog.kt index 57e54fc7f..c0a2a91ab 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/InsufficientFundsDialog.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/InsufficientFundsDialog.kt @@ -9,7 +9,7 @@ import com.tonapps.icu.CurrencyFormatter import com.tonapps.icu.CurrencyFormatter.withCustomSymbol import com.tonapps.tonkeeper.extensions.getTitle import com.tonapps.tonkeeper.ui.screen.battery.BatteryScreen -import com.tonapps.tonkeeper.ui.screen.purchase.main.PurchaseScreen +import com.tonapps.tonkeeper.ui.screen.purchase.PurchaseScreen import com.tonapps.tonkeeperx.R import com.tonapps.wallet.data.account.Wallet import com.tonapps.wallet.data.account.entities.WalletEntity diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/SendContactsViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/SendContactsViewModel.kt index 982640401..8a7358c35 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/SendContactsViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/SendContactsViewModel.kt @@ -4,11 +4,14 @@ import android.app.Application import androidx.lifecycle.viewModelScope import com.tonapps.blockchain.ton.extensions.equalsAddress import com.tonapps.blockchain.ton.extensions.toRawAddress +import com.tonapps.tonkeeper.api.isOutTransfer +import com.tonapps.tonkeeper.api.isTransfer import com.tonapps.tonkeeper.core.entities.WalletExtendedEntity import com.tonapps.tonkeeper.core.history.recipient import com.tonapps.tonkeeper.ui.base.BaseWalletVM import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.Item import com.tonapps.uikit.list.ListCell +import com.tonapps.wallet.api.API import com.tonapps.wallet.data.account.AccountRepository import com.tonapps.wallet.data.account.Wallet import com.tonapps.wallet.data.account.entities.WalletEntity @@ -16,6 +19,8 @@ import com.tonapps.wallet.data.contacts.ContactsRepository import com.tonapps.wallet.data.contacts.entities.ContactEntity import com.tonapps.wallet.data.events.EventsRepository import com.tonapps.wallet.data.settings.SettingsRepository +import io.tonapi.models.AccountAddress +import io.tonapi.models.AccountEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -29,13 +34,14 @@ class SendContactsViewModel( private val accountRepository: AccountRepository, private val eventsRepository: EventsRepository, private val settingsRepository: SettingsRepository, - private val contactsRepository: ContactsRepository + private val contactsRepository: ContactsRepository, + private val api: API ): BaseWalletVM(app) { private val _myWalletsFlow = MutableStateFlow>(emptyList()) private val myWalletsFlow = _myWalletsFlow.asStateFlow() - private val _latestContactsFlow = MutableStateFlow>(emptyList()) + private val _latestContactsFlow = MutableStateFlow>(listOf(Item.Loading)) private val latestContactsFlow = _latestContactsFlow.asStateFlow() private val savedContactsFlow = contactsRepository.contactsFlow.map { @@ -82,7 +88,10 @@ class SendContactsViewModel( fun hideContact(address: String) { viewModelScope.launch(Dispatchers.IO) { contactsRepository.hide(address.toRawAddress(), wallet.testnet) - val newLatestContactsFlow = _latestContactsFlow.value.filter { !it.account.address.equalsAddress(address) } + val newLatestContactsFlow = _latestContactsFlow.value.filter { + it is Item.LatestContact && !it.account.address.equalsAddress(address) + }.map { it as Item.LatestContact } + _latestContactsFlow.value = newLatestContactsFlow.mapIndexed { index, latestContact -> latestContact.copy(position = ListCell.getPosition(newLatestContactsFlow.size, index)) } @@ -108,18 +117,25 @@ class SendContactsViewModel( } } - private suspend fun getLatestContacts(): List { - val accountEvents = eventsRepository.get(wallet.accountId, wallet.testnet) ?: return emptyList() - val actions = accountEvents.events.map { it.actions }.flatten() - val accounts = actions.mapNotNull { it.recipient } - .filter { it.isWallet && !it.address.equalsAddress(wallet.address) && !contactsRepository.isHidden(it.address.toRawAddress(), wallet.testnet) } - .distinctBy { it.address } - .take(6) - - + private fun getLatestContacts(): List { + val accounts = loadLatestRecipients() return accounts.mapIndexed { index, account -> val position = ListCell.getPosition(accounts.size, index) Item.LatestContact(position, account, wallet.testnet) } } + + private fun loadLatestRecipients(): List { + val actions = api.getEvents( + accountId = wallet.accountId, + testnet = wallet.testnet, + limit = 100 + )?.events?.map { it.actions }?.flatten() ?: return emptyList() + + val recipients = actions.filter { it.isOutTransfer(wallet) }.mapNotNull { it.recipient } + return recipients.filter { + !it.address.equalsAddress(wallet.address) && !it.isWallet && !contactsRepository.isHidden(it.address.toRawAddress(), wallet.testnet) + }.distinctBy { it.address } + } + } \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Adapter.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Adapter.kt index 0cdc3e47d..2b7c72425 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Adapter.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Adapter.kt @@ -3,6 +3,7 @@ package com.tonapps.tonkeeper.ui.screen.send.contacts.main.list import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.holder.LatestHolder +import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.holder.LoaderHolder import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.holder.MyWalletHolder import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.holder.SavedHolder import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.holder.SpaceHolder @@ -21,6 +22,7 @@ class Adapter( Item.TYPE_SPACE -> SpaceHolder(parent) Item.TYPE_LATEST_CONTACT -> LatestHolder(parent, onClick, onAction) Item.TYPE_SAVED_CONTACT -> SavedHolder(parent, onClick, onAction) + Item.TYPE_LOADING -> LoaderHolder(parent) else -> throw IllegalArgumentException("Unknown view type: $viewType") } } diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Item.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Item.kt index b9f1699ca..a2ec0fd2c 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Item.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/Item.kt @@ -15,6 +15,7 @@ sealed class Item(type: Int): BaseListItem(type) { const val TYPE_SPACE = 2 const val TYPE_LATEST_CONTACT = 3 const val TYPE_SAVED_CONTACT = 4 + const val TYPE_LOADING = 5 } data object Space: Item(TYPE_SPACE) @@ -57,4 +58,6 @@ sealed class Item(type: Int): BaseListItem(type) { val userFriendlyAddress: String = contact.address.toUserFriendly(testnet = testnet) } + data object Loading: Item(TYPE_LOADING) + } \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/holder/LoaderHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/holder/LoaderHolder.kt new file mode 100644 index 000000000..7f84120ec --- /dev/null +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/send/contacts/main/list/holder/LoaderHolder.kt @@ -0,0 +1,10 @@ +package com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.holder + +import android.view.ViewGroup +import com.tonapps.tonkeeper.ui.screen.send.contacts.main.list.Item + +class LoaderHolder(parent: ViewGroup): Holder(parent, uikit.R.layout.view_item_loader) { + + override fun onBind(item: Item.Loading) { + } +} \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/State.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/State.kt index 7fd81a04d..bc1c7e814 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/State.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/State.kt @@ -17,6 +17,7 @@ import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.core.WalletCurrency import com.tonapps.wallet.data.core.isAvailableBiometric import com.tonapps.wallet.data.dapps.entities.AppEntity +import com.tonapps.wallet.data.dapps.entities.AppPushEntity import com.tonapps.wallet.data.rates.entity.RatesEntity import com.tonapps.wallet.localization.Localization @@ -258,9 +259,9 @@ sealed class State { } uiItems.add(uiItemBalance(hiddenBalance, status, lastUpdatedFormat)) uiItems.add(uiItemActions(config)) - /*if (!dAppNotifications.isEmpty) { - uiItems.add(Item.Push(dAppNotifications.notifications, dAppNotifications.apps)) - }*/ + if (!dAppNotifications.isEmpty) { + uiItems.add(Item.Push(dAppNotifications.pushes)) + } setup?.let { val setupTypes = createSetupTypes(it) @@ -275,11 +276,11 @@ sealed class State { } data class DAppNotifications( - val apps: List = emptyList(), + val pushes: List = emptyList(), ): State() { val isEmpty: Boolean - get() = apps.isEmpty() + get() = pushes.isEmpty() } data class Settings( diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletScreen.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletScreen.kt index 1574a77b1..6a2c99b8d 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletScreen.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletScreen.kt @@ -70,9 +70,9 @@ class WalletScreen(wallet: WalletEntity): MainScreen.Child(R.layout.fragment_wal return null } - override fun getHeaderDividerOwner(): BarDrawable.BarDrawableOwner? { + override fun getTopBarDrawable(): BarDrawable? { if (this::headerView.isInitialized) { - return headerView + return headerView.background as? BarDrawable } return null } diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletViewModel.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletViewModel.kt index 64e4616d8..36febc927 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletViewModel.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/WalletViewModel.kt @@ -1,6 +1,7 @@ package com.tonapps.tonkeeper.ui.screen.wallet.main import android.app.Application +import android.util.Log import androidx.lifecycle.viewModelScope import com.tonapps.icu.Coins import com.tonapps.network.NetworkMonitor @@ -21,6 +22,8 @@ import com.tonapps.wallet.data.backup.BackupRepository import com.tonapps.wallet.data.battery.BatteryRepository import com.tonapps.wallet.data.core.ScreenCacheSource import com.tonapps.wallet.data.core.WalletCurrency +import com.tonapps.wallet.data.dapps.DAppsRepository +import com.tonapps.wallet.data.dapps.entities.AppPushEntity import com.tonapps.wallet.data.rates.RatesRepository import com.tonapps.wallet.data.settings.SettingsRepository import kotlinx.coroutines.Dispatchers @@ -52,11 +55,15 @@ class WalletViewModel( private val batteryRepository: BatteryRepository, private val transactionManager: TransactionManager, private val assetsManager: AssetsManager, + private val dAppsRepository: DAppsRepository, ): BaseWalletVM(app) { private var autoRefreshJob: Job? = null private val alertNotificationsFlow = MutableStateFlow>(emptyList()) + private val _dAppPushesFlow = MutableStateFlow>(emptyList()) + private val dAppPushesFlow = _dAppPushesFlow.asStateFlow() + private val _uiLabelFlow = MutableStateFlow(null) val uiLabelFlow = _uiLabelFlow.asStateFlow() @@ -187,10 +194,10 @@ class WalletViewModel( combine( stateMainFlow, alertNotificationsFlow, - // pushManager.dAppPushFlow, + dAppPushesFlow, _stateSettingsFlow, updateWalletSettings, - ) { state, alerts, settings, _ -> + ) { state, alerts, pushes, settings, _ -> val status = settings.status /* if (settings.status == Status.NoInternet) { settings.status } else if (settings.status != Status.SendingTransaction && settings.status != Status.TransactionConfirmed) { @@ -218,7 +225,7 @@ class WalletViewModel( status = status, config = settings.config, alerts = alerts, - dAppNotifications = State.DAppNotifications(emptyList()), + dAppNotifications = State.DAppNotifications(pushes), setup = uiSetup, lastUpdatedFormat = DateHelper.formattedDate(lastUpdated, settingsRepository.getLocale()) ) @@ -236,11 +243,28 @@ class WalletViewModel( delay(2.minutes) } } + + loadDAppPushes() + } + + private fun loadDAppPushes() { + viewModelScope.launch(Dispatchers.IO) { requestDAppPushes() } + } + + private suspend fun requestDAppPushes() { + if (!wallet.isTonConnectSupported) { + return + } + val tonProof = accountRepository.requestTonProofToken(wallet) ?: return + val p = dAppsRepository.getPushes(tonProof, wallet.accountId) + _dAppPushesFlow.value = p } fun refresh() { _statusFlow.value = Status.Updating _lastLtFlow.value += 1 + + loadDAppPushes() } private suspend fun checkAutoRefresh() { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/Item.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/Item.kt index 996679259..f4140d989 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/Item.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/Item.kt @@ -25,6 +25,7 @@ import com.tonapps.wallet.api.entity.TokenEntity import com.tonapps.wallet.data.account.Wallet import com.tonapps.wallet.data.account.entities.WalletEntity import com.tonapps.wallet.data.dapps.entities.AppEntity +import com.tonapps.wallet.data.dapps.entities.AppPushEntity import com.tonapps.wallet.data.staking.StakingPool import com.tonapps.wallet.data.token.entities.AccountTokenEntity @@ -411,21 +412,23 @@ sealed class Item(type: Int): BaseListItem(type), Parcelable { } data class Push( - val apps: List + val textLine: String, + val iconUris: List, ): Item(TYPE_PUSH) { - constructor(parcel: Parcel) : this( - parcel.readArrayCompat(AppEntity::class.java)?.toList()!! + constructor(pushes: List) : this( + pushes.map { it.body.message }.first(), + pushes.map { Uri.parse(it.iconUrl) } ) - val text = "line" - - val iconUris: List by lazy { - apps.map { Uri.parse(it.iconUrl) } - } + constructor(parcel: Parcel) : this( + parcel.readString()!!, + parcel.readArrayCompat(Uri::class.java)?.toList() ?: emptyList() + ) override fun marshall(dest: Parcel, flags: Int) { - dest.writeArrayCompat(apps.toTypedArray()) + dest.writeString(textLine) + dest.writeArrayCompat(iconUris.toTypedArray()) } companion object CREATOR : Parcelable.Creator { diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/ActionsHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/ActionsHolder.kt index 4b690fb1a..d19b519ad 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/ActionsHolder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/ActionsHolder.kt @@ -3,7 +3,7 @@ package com.tonapps.tonkeeper.ui.screen.wallet.main.list.holder import android.view.View import android.view.ViewGroup import com.tonapps.tonkeeper.ui.screen.camera.CameraScreen -import com.tonapps.tonkeeper.ui.screen.purchase.main.PurchaseScreen +import com.tonapps.tonkeeper.ui.screen.purchase.PurchaseScreen import com.tonapps.tonkeeper.ui.screen.qr.QRScreen import com.tonapps.tonkeeper.ui.screen.send.main.SendScreen import com.tonapps.tonkeeper.ui.screen.staking.stake.StakingScreen diff --git a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/PushHolder.kt b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/PushHolder.kt index 5b212389e..45fafef89 100644 --- a/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/PushHolder.kt +++ b/apps/wallet/instance/app/src/main/java/com/tonapps/tonkeeper/ui/screen/wallet/main/list/holder/PushHolder.kt @@ -25,7 +25,7 @@ class PushHolder(parent: ViewGroup): Holder(parent, R.layout.view_wal } override fun onBind(item: Item.Push) { - textView.text = item.text + textView.text = item.textLine setIcons(item.iconUris) } diff --git a/apps/wallet/instance/app/src/main/res/layout/fragment_main_events_list.xml b/apps/wallet/instance/app/src/main/res/layout/fragment_main_events_list.xml index 9282b7ad1..898f335a4 100644 --- a/apps/wallet/instance/app/src/main/res/layout/fragment_main_events_list.xml +++ b/apps/wallet/instance/app/src/main/res/layout/fragment_main_events_list.xml @@ -3,32 +3,20 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - + android:layout_height="match_parent" + android:paddingHorizontal="@dimen/offsetMedium" + android:topOffset="112dp" + android:clipToPadding="false"/> - - - - - + - + android:layout_height="wrap_content"> + + + + + + diff --git a/apps/wallet/instance/app/src/main/res/layout/fragment_main_list.xml b/apps/wallet/instance/app/src/main/res/layout/fragment_main_list.xml index 6e1349a4d..be5896a5e 100644 --- a/apps/wallet/instance/app/src/main/res/layout/fragment_main_list.xml +++ b/apps/wallet/instance/app/src/main/res/layout/fragment_main_list.xml @@ -12,7 +12,7 @@ android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingHorizontal="@dimen/offsetMedium" + android:padding="@dimen/offsetMedium" android:clipToPadding="false"/> diff --git a/apps/wallet/instance/app/src/main/res/layout/fragment_purchase_web.xml b/apps/wallet/instance/app/src/main/res/layout/fragment_purchase_web.xml deleted file mode 100644 index 3cb78b1ee..000000000 --- a/apps/wallet/instance/app/src/main/res/layout/fragment_purchase_web.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/res/layout/fragment_security.xml b/apps/wallet/instance/app/src/main/res/layout/fragment_security.xml index db0631ee2..bbd6f1b8e 100644 --- a/apps/wallet/instance/app/src/main/res/layout/fragment_security.xml +++ b/apps/wallet/instance/app/src/main/res/layout/fragment_security.xml @@ -70,6 +70,7 @@ android:layout_width="match_parent" android:layout_height="52dp" android:layout_marginTop="8dp" + android:visibility="gone" android:text="@string/content_security" android:textAppearance="@style/TextAppearance.Label1" android:textColor="?attr/textPrimaryColor" @@ -79,6 +80,7 @@ android:id="@+id/verified_nfts" android:layout_width="match_parent" android:layout_height="wrap_content" + android:visibility="gone" app:position="first" android:text="@string/content_security_nft" android:subtitle="@string/content_security_nft_subtitle"/> @@ -87,6 +89,7 @@ android:id="@+id/verified_token" android:layout_width="match_parent" android:layout_height="wrap_content" + android:visibility="gone" app:position="last" android:text="@string/content_security_token" android:subtitle="@string/content_security_token_subtitle"/> diff --git a/apps/wallet/instance/app/src/main/res/layout/fragment_wallet.xml b/apps/wallet/instance/app/src/main/res/layout/fragment_wallet.xml index 19d71e11d..15db50a45 100644 --- a/apps/wallet/instance/app/src/main/res/layout/fragment_wallet.xml +++ b/apps/wallet/instance/app/src/main/res/layout/fragment_wallet.xml @@ -13,7 +13,7 @@ android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingHorizontal="@dimen/offsetMedium" + android:padding="@dimen/offsetMedium" android:clipToPadding="false"/> diff --git a/apps/wallet/instance/app/src/main/res/layout/view_filter_chip.xml b/apps/wallet/instance/app/src/main/res/layout/view_filter_chip.xml new file mode 100644 index 000000000..55440adb5 --- /dev/null +++ b/apps/wallet/instance/app/src/main/res/layout/view_filter_chip.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/apps/wallet/instance/app/src/main/res/values/styleable.xml b/apps/wallet/instance/app/src/main/res/values/styleable.xml index 47388581c..76f831000 100644 --- a/apps/wallet/instance/app/src/main/res/values/styleable.xml +++ b/apps/wallet/instance/app/src/main/res/values/styleable.xml @@ -27,4 +27,10 @@ + + + + + + \ No newline at end of file diff --git a/lib/blockchain/src/main/java/com/tonapps/blockchain/ton/extensions/Cell.kt b/lib/blockchain/src/main/java/com/tonapps/blockchain/ton/extensions/Cell.kt index fddd26d3a..d4e8249d9 100644 --- a/lib/blockchain/src/main/java/com/tonapps/blockchain/ton/extensions/Cell.kt +++ b/lib/blockchain/src/main/java/com/tonapps/blockchain/ton/extensions/Cell.kt @@ -1,7 +1,7 @@ package com.tonapps.blockchain.ton.extensions -import android.util.Log import io.ktor.util.encodeBase64 +import org.json.JSONObject import org.ton.bitstring.BitString import org.ton.boc.BagOfCells import org.ton.cell.Cell @@ -9,11 +9,24 @@ import org.ton.cell.CellSlice import org.ton.crypto.hex fun String.toBoc(): BagOfCells { + if (startsWith("{")) { // oh fuck.... + return toBocFromJSBuffer() + } return try { - BagOfCells(hex(this)) - } catch (e: Throwable) { BagOfCells(base64()) + } catch (e: Throwable) { + BagOfCells(hex(this)) + } +} + +private fun String.toBocFromJSBuffer(): BagOfCells { + val json = JSONObject(this) + val data = json.getJSONArray("data") + val byteArray = ByteArray(data.length()) + for (i in 0 until data.length()) { + byteArray[i] = data.getInt(i).toByte() } + return BagOfCells(byteArray) } fun String.parseCell(): Cell { diff --git a/lib/extensions/src/main/java/com/tonapps/extensions/JSONArray.kt b/lib/extensions/src/main/java/com/tonapps/extensions/JSONArray.kt index dfd31345c..8e97f522a 100644 --- a/lib/extensions/src/main/java/com/tonapps/extensions/JSONArray.kt +++ b/lib/extensions/src/main/java/com/tonapps/extensions/JSONArray.kt @@ -1,5 +1,6 @@ package com.tonapps.extensions +import android.os.Parcelable import org.json.JSONArray import org.json.JSONObject @@ -13,4 +14,12 @@ fun JSONArray.toStringList(): List { } } return list +} + +fun JSONArray.map(transform: (JSONObject) -> T): List { + val list = mutableListOf() + for (i in 0 until length()) { + list.add(transform(getJSONObject(i))) + } + return list } \ No newline at end of file diff --git a/lib/security/src/main/java/com/tonapps/security/RootUtils.kt b/lib/security/src/main/java/com/tonapps/security/RootUtils.kt deleted file mode 100644 index 0dc2f507f..000000000 --- a/lib/security/src/main/java/com/tonapps/security/RootUtils.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.tonapps.security - -import android.os.Build -import java.io.BufferedReader -import java.io.File -import java.io.InputStream -import java.io.InputStreamReader - -object RootUtils { - - private val paths = arrayOf( - "/system/app/Superuser.apk", - "/sbin/su", - "/system/bin/su", - "/system/xbin/su", - "/data/local/xbin/su", - "/data/local/bin/su", - "/system/sd/xbin/su", - "/system/bin/failsafe/su", - "/data/local/su", - "/su/bin/su" - ) - - fun isDeviceRooted(): Boolean { - return checkRootMethod1() || checkRootMethod2() || checkRootMethod3() - } - - private fun checkRootMethod1(): Boolean { - val buildTags = Build.TAGS - return buildTags != null && buildTags.contains("test-keys") - } - - private fun checkRootMethod2(): Boolean { - for (path in paths) { - if (File(path).exists()) { - return true - } - } - return false - } - - private fun checkRootMethod3(): Boolean { - var process: Process? = null - var inputStream: InputStream? = null - val rooted = try { - process = Runtime.getRuntime().exec(arrayOf("/system/xbin/which", "su")) - inputStream = process.inputStream - val input = BufferedReader(InputStreamReader(inputStream)) - input.readLine() != null - } catch (ignored: Throwable) { - false - } - process?.destroy() - inputStream?.close() - return rooted - } -} \ No newline at end of file diff --git a/lib/security/src/main/java/com/tonapps/security/Security.kt b/lib/security/src/main/java/com/tonapps/security/Security.kt index c086cfa84..1feae5e1a 100644 --- a/lib/security/src/main/java/com/tonapps/security/Security.kt +++ b/lib/security/src/main/java/com/tonapps/security/Security.kt @@ -124,7 +124,7 @@ object Security { } fun isDeviceRooted(): Boolean { - return RootUtils.isDeviceRooted() + return false } fun isDebuggable(context: Context): Boolean {