diff --git a/app/src/main/java/one/mixin/android/extension/UrlExtension.kt b/app/src/main/java/one/mixin/android/extension/UrlExtension.kt index 60430f15dc..4d1f92485b 100644 --- a/app/src/main/java/one/mixin/android/extension/UrlExtension.kt +++ b/app/src/main/java/one/mixin/android/extension/UrlExtension.kt @@ -274,7 +274,7 @@ fun String.checkUserOrApp( val userDao = db.userDao() val appDao = db.appDao() scope.launch { - val isOpenApp = isAppScheme && uri.getQueryParameter("action") == "open" + val isOpenApp = uri.shouldOpenAppHome() if (isOpenApp) { val localApp = appDao.findAppById(userId) if (localApp != null) { @@ -299,6 +299,9 @@ fun String.checkUserOrApp( } } +internal fun Uri.shouldOpenAppHome(): Boolean = + toString().isAppScheme() && (getQueryParameter("action") == "open" || !getQueryParameter("page").isNullOrBlank()) + internal fun App.homeUriWithSchemeParameters(uri: Uri): String = runCatching { homeUri.appendQueryParamsFromOtherUri(uri) diff --git a/app/src/main/java/one/mixin/android/ui/conversation/link/LinkBottomSheetDialogFragment.kt b/app/src/main/java/one/mixin/android/ui/conversation/link/LinkBottomSheetDialogFragment.kt index 9088ec5bac..8d9487fb4e 100644 --- a/app/src/main/java/one/mixin/android/ui/conversation/link/LinkBottomSheetDialogFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/conversation/link/LinkBottomSheetDialogFragment.kt @@ -56,6 +56,7 @@ import one.mixin.android.extension.isNightMode import one.mixin.android.extension.isUUID import one.mixin.android.extension.isValidStartParam import one.mixin.android.extension.putInt +import one.mixin.android.extension.shouldOpenAppHome import one.mixin.android.extension.stripAmountZero import one.mixin.android.extension.toPerpsTradeAction import one.mixin.android.extension.toast @@ -249,7 +250,7 @@ class LinkBottomSheetDialogFragment : SchemeBottomSheet() { dismiss() } else { lifecycleScope.launch(errorHandler) { - val isOpenApp = isAppScheme && uri.getQueryParameter("action") == "open" + val isOpenApp = uri.shouldOpenAppHome() if (isOpenApp) { val localApp = oldLinkViewModel.findAppById(userId) if (localApp != null) { diff --git a/app/src/main/java/one/mixin/android/ui/wallet/WalletHomeAllTokensFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/WalletHomeAllTokensFragment.kt index c60b96d6ad..235aa591eb 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/WalletHomeAllTokensFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/WalletHomeAllTokensFragment.kt @@ -1,7 +1,6 @@ package one.mixin.android.ui.wallet import android.annotation.SuppressLint -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -24,7 +23,6 @@ import one.mixin.android.api.response.perps.PerpsPositionItem import one.mixin.android.databinding.FragmentWalletHomeAllTokensBinding import one.mixin.android.databinding.ViewClassicWalletBottomBinding import one.mixin.android.databinding.ViewPrivacyWalletBottomBinding -import one.mixin.android.db.property.PropertyHelper import one.mixin.android.db.web3.vo.WalletItem import one.mixin.android.db.web3.vo.Web3TokenItem import one.mixin.android.db.web3.vo.Web3TransactionItem @@ -58,7 +56,6 @@ import one.mixin.android.ui.wallet.home.positionMarginUsdTotal import one.mixin.android.ui.wallet.home.toWalletHomePendingIndicator import one.mixin.android.ui.wallet.home.walletHomeImportKeyAction import one.mixin.android.ui.wallet.home.walletHomePendingTransactionIndicator -import one.mixin.android.ui.web.WebActivity import one.mixin.android.util.analytics.AnalyticsTracker import one.mixin.android.util.analytics.AnalyticsTracker.TradeSource import one.mixin.android.util.analytics.AnalyticsTracker.TradeWallet @@ -503,49 +500,6 @@ class WalletHomeAllTokensFragment : BaseFragment() { return true } - private fun showBuyOptionsBottomSheet() { - viewLifecycleOwner.lifecycleScope.launch { - val cashRewardApy = PropertyHelper.findCashAccount()?.rewardApy - WalletBuyOptionsBottomSheetDialogFragment.newInstance( - walletName = getString(R.string.Privacy_Wallet), - walletIconRes = R.drawable.ic_wallet_privacy, - cashRewardApy = cashRewardApy, - ) - .setOnGooglePayOrCard { - WalletActivity.showBuy(requireActivity(), false, null, null, source = TradeSource.TOKEN_LIST) - } - .setOnBankTransfer { openCashHome(addBank = true) } - .showNow(parentFragmentManager, WalletBuyOptionsBottomSheetDialogFragment.TAG) - } - } - - private fun openCashHome(addBank: Boolean = false) { - lifecycleScope.launch { - val app = walletViewModel.findOrSyncApp(Constants.MIXIN_CASH_USER_ID) - val url = cashHomeUrl(app?.homeUri, addBank) - if (app == null) { - WebActivity.show(requireActivity(), url = url, app = null, conversationId = null) - } else { - WebActivity.show(requireActivity(), url = url, app = app, conversationId = null) - } - } - } - - private fun cashHomeUrl( - homeUri: String?, - addBank: Boolean, - ): String { - val url = homeUri.takeUnless { it.isNullOrBlank() } ?: Constants.API.CASH_HOME_URL - return if (addBank) { - Uri.parse(url).buildUpon() - .appendQueryParameter("action", "add-cash-bank") - .build() - .toString() - } else { - url - } - } - private val callbacks = object : WalletHomeCallbacks { override fun onAddWalletClicked() = Unit override fun onBannerClosed() = Unit @@ -566,7 +520,7 @@ class WalletHomeAllTokensFragment : BaseFragment() { source = TradeSource.TOKEN_LIST, ) } else { - showBuyOptionsBottomSheet() + WalletActivity.showBuy(requireActivity(), false, null, null, source = TradeSource.TOKEN_LIST) } } diff --git a/app/src/main/java/one/mixin/android/ui/wallet/WalletHomePrivacyFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/WalletHomePrivacyFragment.kt index 6a46f9012d..c3c8ad5373 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/WalletHomePrivacyFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/WalletHomePrivacyFragment.kt @@ -1,7 +1,6 @@ package one.mixin.android.ui.wallet import android.annotation.SuppressLint -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -237,7 +236,7 @@ class WalletHomePrivacyFragment : BaseFragment(R.layout.fragment_privacy_wallet) sendReceiveView.isVisible = true sendReceiveView.enableBuy() sendReceiveView.buy.setOnClickListener { - showBuyOptionsBottomSheet() + showBuy() } sendReceiveView.send.setOnClickListener { if ( @@ -766,7 +765,7 @@ class WalletHomePrivacyFragment : BaseFragment(R.layout.fragment_privacy_wallet) } override fun onBuyClicked() { - showBuyOptionsBottomSheet() + showBuy() } override fun onReceiveClicked() { @@ -910,38 +909,17 @@ class WalletHomePrivacyFragment : BaseFragment(R.layout.fragment_privacy_wallet) AddWalletBottomSheetDialogFragment.newInstance().showNow(parentFragmentManager, AddWalletBottomSheetDialogFragment.TAG) } - private fun showBuyOptionsBottomSheet() { + private fun showBuy() { defaultSharedPreferences.putBoolean(PREF_HAS_USED_BUY, false) RxBus.publish(BadgeEvent(PREF_HAS_USED_BUY)) _headBinding?.sendReceiveView?.buyBadge?.isVisible = false renderHome() - WalletBuyOptionsBottomSheetDialogFragment.newInstance( - walletName = getString(R.string.Privacy_Wallet), - walletIconRes = R.drawable.ic_wallet_privacy, - cashRewardApy = cashAccount?.rewardApy, - ) - .setOnGooglePayOrCard { - WalletActivity.showBuy(requireActivity(), false, null, null) - } - .setOnBankTransfer { openCashHome(addBank = true) } - .showNow(parentFragmentManager, WalletBuyOptionsBottomSheetDialogFragment.TAG) + WalletActivity.showBuy(requireActivity(), false, null, null) } - private fun openCashHome(addBank: Boolean = false) { - if (!addBank) { - "${Constants.Scheme.APPS}/${Constants.MIXIN_CASH_USER_ID}?action=open" - .openAsUrlOrWeb(requireActivity(), null, parentFragmentManager, lifecycleScope) - return - } - lifecycleScope.launch { - val app = walletViewModel.findOrSyncApp(Constants.MIXIN_CASH_USER_ID) - val url = cashHomeUrl(app?.homeUri, addBank) - if (app == null) { - WebActivity.show(requireActivity(), url = url, app = null, conversationId = null) - } else { - WebActivity.show(requireActivity(), url = url, app = app, conversationId = null) - } - } + private fun openCashHome() { + "${Constants.Scheme.APPS}/${Constants.MIXIN_CASH_USER_ID}?page=add-cash-ban" + .openAsUrlOrWeb(requireActivity(), null, parentFragmentManager, lifecycleScope) } private fun openEarnHome() { @@ -949,21 +927,6 @@ class WalletHomePrivacyFragment : BaseFragment(R.layout.fragment_privacy_wallet) .openAsUrlOrWeb(requireActivity(), null, parentFragmentManager, lifecycleScope) } - private fun cashHomeUrl( - homeUri: String?, - addBank: Boolean, - ): String { - val url = homeUri.takeUnless { it.isNullOrBlank() } ?: Constants.API.CASH_HOME_URL - return if (addBank) { - Uri.parse(url).buildUpon() - .appendQueryParameter("action", "add-cash-bank") - .build() - .toString() - } else { - url - } - } - override fun onResume() { super.onResume() renderHome() diff --git a/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/CalculateFragment.kt b/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/CalculateFragment.kt index 673cf6471b..c0a1cfe756 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/CalculateFragment.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/CalculateFragment.kt @@ -1,6 +1,7 @@ package one.mixin.android.ui.wallet.fiatmoney import android.annotation.SuppressLint +import android.net.Uri import android.os.Bundle import android.util.TypedValue import android.view.View @@ -21,6 +22,7 @@ import one.mixin.android.R import one.mixin.android.api.MixinResponseException import one.mixin.android.api.request.RouteTickerRequest import one.mixin.android.databinding.FragmentCalculateBinding +import one.mixin.android.db.property.PropertyHelper import one.mixin.android.extension.clickVibrate import one.mixin.android.extension.colorFromAttribute import one.mixin.android.extension.defaultSharedPreferences @@ -45,6 +47,8 @@ import one.mixin.android.ui.wallet.AssetListFixedBottomSheetDialogFragment import one.mixin.android.ui.wallet.FiatListBottomSheetDialogFragment import one.mixin.android.ui.wallet.LoadingProgressDialogFragment import one.mixin.android.ui.wallet.WalletActivity +import one.mixin.android.ui.wallet.WalletBuyOptionsBottomSheetDialogFragment +import one.mixin.android.ui.web.WebActivity import one.mixin.android.util.ErrorHandler import one.mixin.android.util.analytics.AnalyticsTracker import one.mixin.android.util.viewBinding @@ -438,7 +442,22 @@ class CalculateFragment : BaseFragment(R.layout.fragment_calculate) { } } } - proceedToBuy() + if (isWeb3) { + proceedToBuy() + } else { + viewLifecycleScope.launch { + val cashRewardApy = PropertyHelper.findCashAccount()?.rewardApy + if (parentFragmentManager.findFragmentByTag(WalletBuyOptionsBottomSheetDialogFragment.TAG) != null) return@launch + WalletBuyOptionsBottomSheetDialogFragment.newInstance( + walletName = getString(R.string.Privacy_Wallet), + walletIconRes = R.drawable.ic_wallet_privacy, + cashRewardApy = cashRewardApy, + ) + .setOnGooglePayOrCard(proceedToBuy) + .setOnBankTransfer { openBankTransfer() } + .showNow(parentFragmentManager, WalletBuyOptionsBottomSheetDialogFragment.TAG) + } + } } switchIv.setOnClickListener { fiatMoneyViewModel.isReverse = !fiatMoneyViewModel.isReverse @@ -455,6 +474,18 @@ class CalculateFragment : BaseFragment(R.layout.fragment_calculate) { } } + private fun openBankTransfer() { + viewLifecycleOwner.lifecycleScope.launch { + val app = fiatMoneyViewModel.findOrSyncApp(Constants.MIXIN_CASH_USER_ID) + val homeUri = app?.homeUri.takeUnless { it.isNullOrBlank() } ?: Constants.API.CASH_HOME_URL + val url = Uri.parse(homeUri).buildUpon() + .appendQueryParameter("page", "add-cash-bank") + .build() + .toString() + WebActivity.show(requireActivity(), url = url, app = app, conversationId = null) + } + } + private fun isTwoDecimal(string: String): Boolean { return string.matches(Regex("\\d+\\.\\d{2}")) } diff --git a/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/FiatMoneyViewModel.kt b/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/FiatMoneyViewModel.kt index ed351b7feb..9c8cf5d625 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/FiatMoneyViewModel.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/fiatmoney/FiatMoneyViewModel.kt @@ -63,6 +63,8 @@ class FiatMoneyViewModel suspend fun findAssetsById(id: String) = tokenRepository.findAssetItemById(id) + suspend fun findOrSyncApp(id: String) = userRepository.findOrSyncApp(id) + suspend fun fetchSessionsSuspend(ids: List) = userRepository.fetchSessionsSuspend(ids) suspend fun ticker(tickerRequest: RouteTickerRequest): MixinResponse = diff --git a/app/src/test/java/one/mixin/android/extension/AppSchemeTest.kt b/app/src/test/java/one/mixin/android/extension/AppSchemeTest.kt new file mode 100644 index 0000000000..80856d53fc --- /dev/null +++ b/app/src/test/java/one/mixin/android/extension/AppSchemeTest.kt @@ -0,0 +1,36 @@ +package one.mixin.android.extension + +import android.app.Application +import android.net.Uri +import one.mixin.android.Constants +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +@RunWith(RobolectricTestRunner::class) +@Config(application = Application::class) +class AppSchemeTest { + @Test + fun appPageLinksOpenHomeAndForwardPage() { + for (scheme in listOf(Constants.Scheme.APPS, Constants.Scheme.HTTPS_APPS)) { + val base = "$scheme/${Constants.MIXIN_CASH_USER_ID}" + val uri = Uri.parse("$base?page=add-cash-ban") + assertTrue(uri.shouldOpenAppHome()) + assertEquals( + "https://example.com?existing=1&page=add-cash-ban", + "https://example.com?existing=1".appendQueryParamsFromOtherUri(uri), + ) + assertTrue(Uri.parse("$base?action=open").shouldOpenAppHome()) + for (query in listOf("", "?page=", "?page=%20", "?action=other")) { + assertFalse(Uri.parse("$base$query").shouldOpenAppHome()) + } + } + for (scheme in listOf(Constants.Scheme.USERS, Constants.Scheme.HTTPS_USERS)) { + assertFalse(Uri.parse("$scheme/${Constants.MIXIN_CASH_USER_ID}?page=add-cash-ban").shouldOpenAppHome()) + } + } +}