diff --git a/app/src/main/java/com/flowfoundation/wallet/manager/LaunchManager.kt b/app/src/main/java/com/flowfoundation/wallet/manager/LaunchManager.kt index 6244d609e..8b515d420 100644 --- a/app/src/main/java/com/flowfoundation/wallet/manager/LaunchManager.kt +++ b/app/src/main/java/com/flowfoundation/wallet/manager/LaunchManager.kt @@ -13,6 +13,7 @@ import com.flowfoundation.wallet.manager.account.DeviceInfoManager import com.flowfoundation.wallet.manager.app.AppLifecycleObserver import com.flowfoundation.wallet.manager.app.PageLifecycleObserver import com.flowfoundation.wallet.manager.app.refreshChainNetwork +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.flowfoundation.wallet.manager.cadence.CadenceApiManager import com.flowfoundation.wallet.manager.coin.CoinRateManager import com.flowfoundation.wallet.manager.coin.CustomTokenManager @@ -88,6 +89,7 @@ object LaunchManager { private fun runWorker() { CadenceApiManager.init() MixpanelManager.identifyUserProfile() + BlockManager.initialize() } /** diff --git a/app/src/main/java/com/flowfoundation/wallet/manager/blocklist/BlockManager.kt b/app/src/main/java/com/flowfoundation/wallet/manager/blocklist/BlockManager.kt new file mode 100644 index 000000000..a549b543c --- /dev/null +++ b/app/src/main/java/com/flowfoundation/wallet/manager/blocklist/BlockManager.kt @@ -0,0 +1,91 @@ +package com.flowfoundation.wallet.manager.blocklist + +import android.net.Uri +import com.flowfoundation.wallet.utils.ioScope +import com.flowfoundation.wallet.utils.loge +import com.google.gson.Gson +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import java.net.URL +import java.util.concurrent.TimeUnit + +object BlockManager { + + private val TAG = BlockManager::class.java.simpleName + private const val BLOCKLIST_URL = "https://flow-blocklist.vercel.app/api/domain" + private const val CACHE_EXPIRE_TIME_HOURS = 2L + + private var blockList: Set = emptySet() + private var lastFetchTime: Long = 0L + + private val mutex = Mutex() + + fun initialize() { + ioScope { + refreshBlockListIfNeeded(forceRefresh = true) + } + } + + suspend fun isBlocked(url: String): Boolean { + refreshBlockListIfNeeded() + + try { + val uri = Uri.parse(url) + val host = uri.host ?: return false + + return mutex.withLock { + blockList.any { blockedDomain -> + host == blockedDomain || host.matches(Regex("^[\\w.-]+\\.$blockedDomain$")) + } + } + } catch (e: Exception) { + loge(e) + return false + } + } + + private suspend fun refreshBlockListIfNeeded(forceRefresh: Boolean = false) { + val needRefresh = mutex.withLock { + val currentTime = System.currentTimeMillis() + val isExpired = currentTime - lastFetchTime > TimeUnit.HOURS.toMillis(CACHE_EXPIRE_TIME_HOURS) + forceRefresh || isExpired || blockList.isEmpty() + } + + if (needRefresh) { + fetchBlockList() + } + } + + private fun fetchBlockList() { + ioScope { + try { + val connection = URL(BLOCKLIST_URL).openConnection() + connection.connectTimeout = 10000 + connection.readTimeout = 15000 + val text = connection.getInputStream().bufferedReader().use { it.readText() } + val response = Gson().fromJson(text, BlockListResponse::class.java) + val mergedList = mutableSetOf() + + response.flow?.let { flowList -> + mergedList.addAll(flowList) + } + + response.evm?.let { evmList -> + mergedList.addAll(evmList) + } + mutex.withLock { + blockList = mergedList + lastFetchTime = System.currentTimeMillis() + loge(TAG, "Block list updated, total domains: ${blockList.size}") + } + } catch (e: Exception) { + loge(TAG, "Failed to fetch block list: ${e.message}") + } + } + } +} + +data class BlockListResponse( + val flow: List?, + val evm: List? +) \ No newline at end of file diff --git a/app/src/main/java/com/flowfoundation/wallet/page/browser/widgets/LilicoWebView.kt b/app/src/main/java/com/flowfoundation/wallet/page/browser/widgets/LilicoWebView.kt index 413fc0cf0..e7e1ba63e 100644 --- a/app/src/main/java/com/flowfoundation/wallet/page/browser/widgets/LilicoWebView.kt +++ b/app/src/main/java/com/flowfoundation/wallet/page/browser/widgets/LilicoWebView.kt @@ -5,7 +5,12 @@ import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.net.Uri +import android.text.Html +import android.text.SpannableString +import android.text.method.LinkMovementMethod +import android.text.style.UnderlineSpan import android.util.AttributeSet +import android.view.LayoutInflater import android.view.ViewGroup import android.view.View import android.webkit.CookieManager @@ -13,8 +18,12 @@ import android.webkit.ValueCallback import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebView +import android.widget.FrameLayout +import android.widget.TextView import androidx.annotation.ColorInt import com.flowfoundation.wallet.BuildConfig +import com.flowfoundation.wallet.R +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.flowfoundation.wallet.manager.evm.loadInitJS import com.flowfoundation.wallet.manager.evm.loadProviderJS import com.flowfoundation.wallet.manager.walletconnect.WalletConnect @@ -38,6 +47,13 @@ class LilicoWebView : WebView { private var callback: WebviewCallback? = null var isLoading = false + private lateinit var blockedViewLayout: View + private lateinit var tvBlockedUrl: TextView + private lateinit var tvBlockedInfo: TextView + private lateinit var tvIgnoreWarning: TextView + + private var blockedUrl: String? = null + constructor(context: Context) : super(context) { initWebView() } @@ -57,6 +73,7 @@ class LilicoWebView : WebView { // Disable hardware acceleration for this WebView to prevent some layout issues setLayerType(View.LAYER_TYPE_SOFTWARE, null) + initBlockedViewLayout() with(settings) { loadsImagesAutomatically = true @@ -88,6 +105,77 @@ class LilicoWebView : WebView { } } + private fun initBlockedViewLayout() { + post { + if (parent is ViewGroup) { + val parent = parent as ViewGroup + + for (i in 0 until parent.childCount) { + val child = parent.getChildAt(i) + if (child.id == R.id.cl_blocked_view) { + blockedViewLayout = child + setupBlockedViewLayout() + return@post + } + } + + blockedViewLayout = LayoutInflater.from(context).inflate(R.layout.layout_blocked_view, parent, false) + + val layoutParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + blockedViewLayout.layoutParams = layoutParams + + blockedViewLayout.visibility = View.GONE + + parent.addView(blockedViewLayout) + + setupBlockedViewLayout() + } + } + } + + private fun setupBlockedViewLayout() { + tvBlockedUrl = blockedViewLayout.findViewById(R.id.tv_blocked_url) + tvBlockedInfo = blockedViewLayout.findViewById(R.id.tv_blocked_info) + tvIgnoreWarning = blockedViewLayout.findViewById(R.id.tv_ignore_warning) + + tvBlockedInfo.text = Html.fromHtml(context.getString(R.string.blocked_info), Html.FROM_HTML_MODE_LEGACY) + tvBlockedInfo.setOnClickListener { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/Outblock/flow-blocklist")) + context.startActivity(intent) + } + + val content = SpannableString(context.getString(R.string.ignore_warning) ) + content.setSpan(UnderlineSpan(), 0, content.length, 0) + tvIgnoreWarning.text = content + + tvIgnoreWarning.setOnClickListener { + hideBlockedViewLayout() + blockedUrl?.let { url -> + blockedUrl = null + loadUrl(url) + } + } + } + + private fun showBlockedViewLayout(url: String) { + blockedUrl = url + + val uri = Uri.parse(url) + val host = uri.host ?: url + + val blockedUrlText = context.getString(R.string.blocked_url, host) + tvBlockedUrl.text = blockedUrlText + + blockedViewLayout.visibility = View.VISIBLE + } + + private fun hideBlockedViewLayout() { + blockedViewLayout.visibility = View.GONE + } + fun setWebViewCallback(callback: WebviewCallback?) { this.callback = callback } @@ -191,6 +279,15 @@ class LilicoWebView : WebView { } else if (it.toString() == "about:blank#blocked") { return true } + uiScope { + if (BlockManager.isBlocked(it.toString())) { + logd(TAG, "URL blocked: $url") + showBlockedViewLayout(it.toString()) + loadUrl("about:blank#blocked") + isLoading = false + return@uiScope + } + } } return super.shouldOverrideUrlLoading(view, request) } diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/SendButton.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/SendButton.kt index ed89d4202..42b9eac5b 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/SendButton.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/SendButton.kt @@ -12,6 +12,7 @@ import com.google.android.material.progressindicator.CircularProgressIndicator import com.flowfoundation.wallet.R import com.flowfoundation.wallet.databinding.WidgetSendButtonBinding import com.flowfoundation.wallet.page.security.securityVerification +import com.flowfoundation.wallet.utils.extensions.res2color import com.flowfoundation.wallet.utils.extensions.setVisible import com.flowfoundation.wallet.utils.findActivity import com.flowfoundation.wallet.utils.logd @@ -74,6 +75,14 @@ class SendButton : TouchScaleCardView { return true } + fun setWarningButton(isWarning: Boolean) { + with(binding) { + setCardBackgroundColor(if (isWarning) R.color.info_error_red.res2color() else R.color.button_color.res2color()) + holdToSend.setTextColor(if (isWarning) R.color.white.res2color() else R.color.brightest_text.res2color()) + progressBar.setIndicatorColor(if (isWarning) R.color.white_80.res2color() else R.color.primary80.res2color()) + } + } + fun updateDefaultText(textId: Int) { defaultTextId = textId if (textId != 0) { diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignMessageDialog.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignMessageDialog.kt index c86b70af7..a8ad5795d 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignMessageDialog.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignMessageDialog.kt @@ -11,13 +11,17 @@ import androidx.transition.* import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.nftco.flow.sdk.hexToBytes import com.flowfoundation.wallet.databinding.DialogFclSignMessageBinding +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.flowfoundation.wallet.manager.evm.COALinkCheckManager import com.flowfoundation.wallet.page.browser.loadFavicon import com.flowfoundation.wallet.page.browser.toFavIcon import com.flowfoundation.wallet.utils.extensions.isVisible import com.flowfoundation.wallet.utils.extensions.res2String +import com.flowfoundation.wallet.utils.extensions.res2color import com.flowfoundation.wallet.utils.extensions.setVisible +import com.flowfoundation.wallet.utils.extensions.visible import com.flowfoundation.wallet.utils.ioScope +import com.flowfoundation.wallet.utils.uiScope import com.flowfoundation.wallet.widgets.webview.fcl.model.FclDialogModel @@ -62,6 +66,15 @@ class EVMSignMessageDialog : BottomSheetDialogFragment() { } } scriptHeaderWrapper.setOnClickListener { toggleScriptVisible() } + + uiScope { + if (data.url.isNullOrEmpty()) { + return@uiScope + } + val isBlockedUrl = BlockManager.isBlocked(data.url) + flBlockedTip.setVisible(isBlockedUrl) + actionButton.setWarningButton(isBlockedUrl) + } } } diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignTypedDataDialog.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignTypedDataDialog.kt index 90e107d6d..760301139 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignTypedDataDialog.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EVMSignTypedDataDialog.kt @@ -3,6 +3,7 @@ package com.flowfoundation.wallet.widgets.webview.evm.dialog import android.annotation.SuppressLint import android.app.Dialog import android.content.DialogInterface +import android.content.res.ColorStateList import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -12,6 +13,7 @@ import androidx.appcompat.widget.LinearLayoutCompat import androidx.fragment.app.FragmentManager import com.flowfoundation.wallet.R import com.flowfoundation.wallet.databinding.DialogEvmSignTypedDataBinding +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.flowfoundation.wallet.manager.evm.COALinkCheckManager import com.flowfoundation.wallet.page.browser.loadFavicon @@ -19,9 +21,12 @@ import com.flowfoundation.wallet.page.browser.toFavIcon import com.flowfoundation.wallet.utils.ScreenUtils import com.flowfoundation.wallet.utils.extensions.gone import com.flowfoundation.wallet.utils.extensions.res2String +import com.flowfoundation.wallet.utils.extensions.res2color +import com.flowfoundation.wallet.utils.extensions.setVisible import com.flowfoundation.wallet.utils.extensions.visible import com.flowfoundation.wallet.utils.ioScope import com.flowfoundation.wallet.utils.shortenEVMString +import com.flowfoundation.wallet.utils.uiScope import com.flowfoundation.wallet.widgets.webview.evm.model.EVMTypedMessage import com.flowfoundation.wallet.widgets.webview.fcl.model.FclDialogModel import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -161,6 +166,14 @@ class EVMSignTypedDataDialog : BottomSheetDialogFragment() { } } } + uiScope { + if (data.url.isNullOrEmpty()) { + return@uiScope + } + val isBlockedUrl = BlockManager.isBlocked(data.url) + flBlockedTip.setVisible(isBlockedUrl) + actionButton.setWarningButton(isBlockedUrl) + } } } diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EvmRequestAccountDialog.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EvmRequestAccountDialog.kt index 42a6431f9..7b7e52f1a 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EvmRequestAccountDialog.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/evm/dialog/EvmRequestAccountDialog.kt @@ -9,13 +9,16 @@ import android.view.ViewGroup import androidx.fragment.app.FragmentManager import com.flowfoundation.wallet.databinding.DialogEvmAccountBinding import com.flowfoundation.wallet.manager.app.chainNetWorkString +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.flowfoundation.wallet.manager.emoji.AccountEmojiManager import com.flowfoundation.wallet.manager.emoji.model.Emoji import com.flowfoundation.wallet.manager.evm.EVMWalletManager import com.flowfoundation.wallet.page.browser.loadFavicon import com.flowfoundation.wallet.page.browser.toFavIcon import com.flowfoundation.wallet.utils.extensions.capitalizeV2 +import com.flowfoundation.wallet.utils.extensions.setVisible import com.flowfoundation.wallet.utils.extensions.urlHost +import com.flowfoundation.wallet.utils.uiScope import com.flowfoundation.wallet.widgets.webview.evm.model.EVMDialogModel import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlin.coroutines.Continuation @@ -61,6 +64,20 @@ class EvmRequestAccountDialog : BottomSheetDialogFragment() { result?.resume(true) dismiss() } + + uiScope { + if (data.url.isNullOrEmpty()) { + return@uiScope + } + val isBlockedUrl = BlockManager.isBlocked(data.url) + flBlockedTip.setVisible(isBlockedUrl) + btnConnect.setVisible(isBlockedUrl.not()) + flBlockedConnect.setVisible(isBlockedUrl) + flBlockedConnect.setOnClickListener { + result?.resume(true) + dismiss() + } + } } } diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclAuthnDialog.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclAuthnDialog.kt index 2d8ad3e17..9b3a95b3d 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclAuthnDialog.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclAuthnDialog.kt @@ -1,6 +1,7 @@ package com.flowfoundation.wallet.widgets.webview.fcl.dialog import android.content.DialogInterface +import android.content.res.ColorStateList import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -8,9 +9,18 @@ import android.view.ViewGroup import androidx.fragment.app.FragmentManager import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.flowfoundation.wallet.databinding.DialogFclAuthnBinding +import com.flowfoundation.wallet.manager.app.chainNetWorkString +import com.flowfoundation.wallet.manager.blocklist.BlockManager +import com.flowfoundation.wallet.manager.emoji.AccountEmojiManager +import com.flowfoundation.wallet.manager.emoji.model.Emoji +import com.flowfoundation.wallet.manager.evm.EVMWalletManager +import com.flowfoundation.wallet.manager.wallet.WalletManager import com.flowfoundation.wallet.page.browser.loadFavicon import com.flowfoundation.wallet.page.browser.toFavIcon +import com.flowfoundation.wallet.utils.extensions.capitalizeV2 +import com.flowfoundation.wallet.utils.extensions.setVisible import com.flowfoundation.wallet.utils.extensions.urlHost +import com.flowfoundation.wallet.utils.uiScope import com.flowfoundation.wallet.widgets.webview.fcl.model.FclDialogModel import kotlin.coroutines.Continuation import kotlin.coroutines.resume @@ -31,10 +41,16 @@ class FclAuthnDialog : BottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { result ?: return val data = data ?: return + val address = WalletManager.selectedWalletAddress() + val emojiInfo = AccountEmojiManager.getEmojiByAddress(address) with(binding) { iconView.loadFavicon(data.logo ?: data.url?.toFavIcon()) nameView.text = data.title urlView.text = data.url?.urlHost() + tvWalletAddress.text = address + tvWalletIcon.text = Emoji.getEmojiById(emojiInfo.emojiId) + tvWalletIcon.backgroundTintList = ColorStateList.valueOf(Emoji.getEmojiColorRes(emojiInfo.emojiId)) + tvNetwork.text = chainNetWorkString().capitalizeV2() cancelButton.setOnClickListener { result?.resume(false) dismiss() @@ -43,6 +59,20 @@ class FclAuthnDialog : BottomSheetDialogFragment() { result?.resume(true) dismiss() } + + uiScope { + if (data.url.isNullOrEmpty()) { + return@uiScope + } + val isBlockedUrl = BlockManager.isBlocked(data.url) + flBlockedTip.setVisible(isBlockedUrl) + approveButton.setVisible(isBlockedUrl.not()) + flBlockedConnect.setVisible(isBlockedUrl) + flBlockedConnect.setOnClickListener { + result?.resume(true) + dismiss() + } + } } } diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclSignMessageDialog.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclSignMessageDialog.kt index a0b5dbe5b..5588565d3 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclSignMessageDialog.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/FclSignMessageDialog.kt @@ -12,10 +12,12 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.nftco.flow.sdk.hexToBytes import com.flowfoundation.wallet.databinding.DialogFclSignMessageBinding import com.flowfoundation.wallet.manager.account.AccountInfoManager +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.flowfoundation.wallet.page.browser.loadFavicon import com.flowfoundation.wallet.page.browser.toFavIcon import com.flowfoundation.wallet.utils.extensions.isVisible import com.flowfoundation.wallet.utils.extensions.res2String +import com.flowfoundation.wallet.utils.extensions.res2color import com.flowfoundation.wallet.utils.extensions.setVisible import com.flowfoundation.wallet.utils.uiScope import com.flowfoundation.wallet.widgets.webview.fcl.model.FclDialogModel @@ -49,9 +51,15 @@ class FclSignMessageDialog : BottomSheetDialogFragment() { } scriptHeaderWrapper.setOnClickListener { toggleScriptVisible() } uiScope { - binding.storageTip.setInsufficientTip( + storageTip.setInsufficientTip( AccountInfoManager.validateOtherTransaction(false) ) + if (data.url.isNullOrEmpty()) { + return@uiScope + } + val isBlockedUrl = BlockManager.isBlocked(data.url) + flBlockedTip.setVisible(isBlockedUrl) + actionButton.setWarningButton(isBlockedUrl) } } } diff --git a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/authz/FclAuthzView.kt b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/authz/FclAuthzView.kt index f3ea9c107..bd53a4424 100644 --- a/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/authz/FclAuthzView.kt +++ b/app/src/main/java/com/flowfoundation/wallet/widgets/webview/fcl/dialog/authz/FclAuthzView.kt @@ -11,6 +11,7 @@ import androidx.transition.TransitionManager import com.flowfoundation.wallet.R import com.flowfoundation.wallet.databinding.DialogFclAuthzBinding import com.flowfoundation.wallet.manager.app.chainNetWorkString +import com.flowfoundation.wallet.manager.blocklist.BlockManager import com.flowfoundation.wallet.manager.config.isGasFree import com.flowfoundation.wallet.network.ApiService import com.flowfoundation.wallet.network.model.CadenceSecurityCheck @@ -18,8 +19,11 @@ import com.flowfoundation.wallet.network.model.CadenceSecurityCheckResponse import com.flowfoundation.wallet.network.retrofitWithHost import com.flowfoundation.wallet.page.browser.loadFavicon import com.flowfoundation.wallet.page.browser.toFavIcon +import com.flowfoundation.wallet.utils.extensions.gone import com.flowfoundation.wallet.utils.extensions.isVisible +import com.flowfoundation.wallet.utils.extensions.res2color import com.flowfoundation.wallet.utils.extensions.setVisible +import com.flowfoundation.wallet.utils.extensions.visible import com.flowfoundation.wallet.utils.ioScope import com.flowfoundation.wallet.utils.uiScope import com.flowfoundation.wallet.widgets.webview.fcl.model.FclDialogModel @@ -47,6 +51,14 @@ class FclAuthzView : FrameLayout { scriptTextView.text = data.cadence?.trimIndent() actionButton.setOnProcessing { approveCallback.invoke(true) } scriptHeaderWrapper.setOnClickListener { toggleScriptVisible() } + uiScope { + if (data.url.isNullOrEmpty()) { + return@uiScope + } + val isBlockedUrl = BlockManager.isBlocked(data.url) + binding.flBlockedTip.setVisible(isBlockedUrl) + binding.actionButton.setWarningButton(isBlockedUrl) + } } ioScope { diff --git a/app/src/main/res/drawable/bg_blocked_connect_layout.xml b/app/src/main/res/drawable/bg_blocked_connect_layout.xml new file mode 100644 index 000000000..bdd999012 --- /dev/null +++ b/app/src/main/res/drawable/bg_blocked_connect_layout.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_blocked_layout.xml b/app/src/main/res/drawable/bg_blocked_layout.xml new file mode 100644 index 000000000..7985c9f36 --- /dev/null +++ b/app/src/main/res/drawable/bg_blocked_layout.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_blocked.xml b/app/src/main/res/drawable/ic_blocked.xml new file mode 100644 index 000000000..d0cca3d1d --- /dev/null +++ b/app/src/main/res/drawable/ic_blocked.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/app/src/main/res/layout/dialog_evm_account.xml b/app/src/main/res/layout/dialog_evm_account.xml index 240e5a3cd..de0136200 100644 --- a/app/src/main/res/layout/dialog_evm_account.xml +++ b/app/src/main/res/layout/dialog_evm_account.xml @@ -48,6 +48,18 @@ app:layout_constraintTop_toBottomOf="@id/tv_title" tools:text="NBA Top Shot Marketplace"/> + + + + + + + app:layout_constraintTop_toBottomOf="@id/fl_blocked_tip"> + app:layout_constraintTop_toTopOf="@id/cl_wallet_address" + app:layout_constraintBottom_toBottomOf="@id/cl_wallet_address"> + + + + + app:layout_constraintTop_toBottomOf="@id/fl_blocked_connect"/> diff --git a/app/src/main/res/layout/dialog_evm_sign_typed_data.xml b/app/src/main/res/layout/dialog_evm_sign_typed_data.xml index ba48a9604..71d93d38c 100644 --- a/app/src/main/res/layout/dialog_evm_sign_typed_data.xml +++ b/app/src/main/res/layout/dialog_evm_sign_typed_data.xml @@ -71,6 +71,18 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"/> + + + + + + + + + + + + + android:paddingVertical="16dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -157,21 +290,24 @@ android:layout_width="0dp" android:layout_height="58dp" android:layout_weight="1" - android:backgroundTint="@color/neutrals10" + android:fontFamily="@font/inter_semi_bold" + android:backgroundTint="@color/button_bg_secondary" android:text="@string/cancel" android:textAllCaps="false" - android:textColor="@color/text" + android:textColor="@color/button_text" app:cornerRadius="16dp"/> diff --git a/app/src/main/res/layout/dialog_fcl_authz.xml b/app/src/main/res/layout/dialog_fcl_authz.xml index 9f4604ec6..e666ae0b6 100644 --- a/app/src/main/res/layout/dialog_fcl_authz.xml +++ b/app/src/main/res/layout/dialog_fcl_authz.xml @@ -81,6 +81,17 @@ tools:visibility="visible"/> + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/fl_blocked_tip"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_blocked_tip.xml b/app/src/main/res/layout/layout_blocked_tip.xml new file mode 100644 index 000000000..e16cc046b --- /dev/null +++ b/app/src/main/res/layout/layout_blocked_tip.xml @@ -0,0 +1,36 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_blocked_view.xml b/app/src/main/res/layout/layout_blocked_view.xml new file mode 100644 index 000000000..5a5f52b83 --- /dev/null +++ b/app/src/main/res/layout/layout_blocked_view.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 68091b8da..823b7def0 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -184,6 +184,8 @@ Token hinzufügen Token hinzufügen fehlgeschlagen Token suchen + Suche Tokens + Token List Konfirmation Initialisierung Entwickler-Modus @@ -700,8 +702,6 @@ #onFlow Swap-Anbieter auswählen Willkommen bei Flow Wallet! Erstellen Sie ein Konto um loszulegen - Token suchen - Token-Listen Scannen Ergebnisse Suche nach NFT @@ -715,4 +715,9 @@ Funktion Parameter Anrufdaten + "reichen Sie bitte ein Problem ein.]]>" + %1$s ist gesperrt! + Warnung ignorieren, trotzdem anzeigen + Warnung ignorieren, trotzdem verbinden + Diese App wurde als gefährlich gekennzeichnet. diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index eff9da7a0..f4bc8df84 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -1,6 +1,5 @@ - Flow Wallet Next List View as @@ -147,7 +146,7 @@ Invalid address Can\'t find address in chain Validated address - No results. Please check your input and try again. + Sorry, We did not find any related account, please check your enter and search it again. Search the ID: %1$s Do not ask me again. Move your assets between your Cadence address on Flow, so @@ -185,6 +184,8 @@ Add Token Add token failed Search Token + Search tokens + Token List Confirmation Initializing Developer Mode @@ -239,7 +240,7 @@ Allow Flow Wallet to pay the gas fee for all my transactions . Select File - Transaction fee + Transaction Fee Hold to Confirm Hold to sign Enable @@ -670,14 +671,14 @@ Local Account Keys Reload Config Move Fee - Charged when moving between accounts on Cadence and EVM on Flow. + It appears when moving between VM accounts No fee between your Flow accounts 🤟 Please wait until the website is fully loaded Add Custom Token Add Token Success Invalid ERC20 address Token Contract Address - Enter the token contract address + Enter your flow token contract address Please enter valid EVM contract address Contracts Token Name @@ -714,17 +715,6 @@ Choose Swap Provider Welcome to Flow Wallet! Create an account to get started Scan - Punch Swap - swap.kittypunch.xyz - trado.one - Trado - Increment Finance - increment.fi - JSON - " *" - Cadence Script Version: %1$s - Search tokens - Token List Results Search NFT Loading NFTs... @@ -737,4 +727,10 @@ Function Parameters Call Data + "please file an issue.]]>" + %1$s is blocked! + Ignore warning, show anyway + Ignore warning, connect anyway + This app has been flagged as dangerous. diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 0e6e48850..68027a985 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -184,6 +184,8 @@ Añadir ficha Error al añadir token Fichero de búsqueda + Buscar fichas + Lista de tokens Confirmación Inicialización de Modo Desarrollador @@ -238,7 +240,7 @@ Permitir que Flow Wallet pague la tasa de gas para todas mis transacciones . Seleccionar archivo - Tasa de transacción + Gastos de Transacción Mantener pulsado para confirmar Mantén para firmar Activar @@ -700,8 +702,6 @@ #onFlow Elegir proveedor de intercambio ¡Bienvenido a Flow Wallet! Crea una cuenta para empezar - Buscar tokens - Lista de tokens Escanear Resultados Buscar NFT @@ -715,4 +715,9 @@ Función Parámetros Datos de llamada + "por favor reporte el problema.]]>" + %1$s está bloqueado! + Ignorar advertencia, mostrar de todos modos + Ignorar advertencia, conectar de todos modos + Esta app ha sido marcada como peligrosa. diff --git a/app/src/main/res/values-es-rUS/strings.xml b/app/src/main/res/values-es-rUS/strings.xml index 2e7986e0c..f97e204e3 100644 --- a/app/src/main/res/values-es-rUS/strings.xml +++ b/app/src/main/res/values-es-rUS/strings.xml @@ -184,6 +184,8 @@ Añadir ficha Error al añadir token Fichero de búsqueda + Buscar fichas + Lista de tokens Confirmación Inicialización de Modo Desarrollador @@ -238,7 +240,7 @@ Permitir que Flow Wallet pague la tasa de gas para todas mis transacciones . Seleccionar archivo - Tasa de transacción + Tarifa de transacción Mantener pulsado para confirmar Mantén para firmar Activar @@ -701,8 +703,6 @@ Elegir proveedor de intercambio ¡Bienvenido a Flow Wallet! Crea una cuenta para empezar Escanear - Buscar tokens - Lista de tokens Resultados Buscar NFT Cargando NFT... @@ -715,4 +715,9 @@ Función Parámetros Datos de llamada + "por favor reporte el problema.]]>" + %1$s está bloqueado! + Ignorar advertencia, mostrar de todos modos + Ignorar advertencia, conectar de todos modos + Esta app ha sido marcada como peligrosa. diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 455d51961..2c3d448c4 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -184,6 +184,8 @@ Ajouter un jeton Échec de l\'ajout d\'un jeton Jeton de recherche + Rechercher des jetons + Liste des tokens Confirmation Initialisation Mode développeur @@ -238,7 +240,7 @@ Permettre à Flow Wallet de payer les frais d\'essence pour toutes mes transactions . Sélectionner un fichier - Frais de transaction + Frais de Transaction Maintenir pour confirmer Maintenir pour signer Activer @@ -697,8 +699,6 @@ #onFlow Choisir le fournisseur de swap Bienvenue sur Flow Wallet ! Créez un compte pour commencer - Rechercher des tokens - Liste des tokens Scanner Résultats Rechercher des NFT @@ -712,4 +712,9 @@ Fonction Paramètres Données d\'appel + "veuillez signaler un problème.]]>" + %1$s est bloqué ! + Ignorer l\'avertissement, montrer quand même + Ignorer l\'avertissement, se connecter quand même + Cette application a été signalée comme dangereuse. diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 3c132f091..6a337b7bd 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -1,6 +1,5 @@ - Flow Wallet Next List View as @@ -147,10 +146,10 @@ Invalid address Can\'t find address in chain Validated address - No results. Please check your input and try again. + Sorry, We did not find any related account, please check your enter and search it again. Search the ID: %1$s Do not ask me again. - Move your assets between your Cadence address on Flow, so + Move your assets between your cadence address on Flow, so %1$s can view your assets Send to Username, address(0x), Find or Flowns @@ -185,6 +184,8 @@ Add Token Add token failed Search Token + Search tokens + Token List Confirmation Initializing Developer Mode @@ -217,7 +218,7 @@ Clear Cache Pending Transaction Welcome to Flow Wallet ! - + Favourite Cancel Favourite Contact us @@ -230,7 +231,7 @@ View your wallet balance and activity Request approval for transactions Script - Apps + dApps Process of Enabling Coin Wrong selection Restore with Recovery Phrase @@ -239,15 +240,15 @@ Allow Flow Wallet to pay the gas fee for all my transactions . Select File - Transaction fee + Transaction Fee Hold to Confirm Hold to sign Enable Sign Message - Transaction History + Transaction history Exec Transaction Transactions - Reset Profile + Reset Wallet Are you sure you want to reset your wallet? Removing the wallet from Flow Wallet does not remove the wallet from Flow blockchain. You can import your wallet again using your Recovery Phrase or Google Drive Backup. @@ -520,8 +521,8 @@ Revoke Device Switch Network You can only create backup on Mainnet. - You can only restore wallet on Mainnet. - You can only perform this operation on Mainnet. + You can only restore wallet on mainnet. + You can only create backup on mainnet. You can only create account on mainnet or testnet. Switch to Mainnet Connect @@ -534,7 +535,7 @@ FlowEVM EVM Move - Current Network + Current VM Cadence Share QR Code Move Token @@ -566,7 +567,7 @@ Select Collection Import Profile Notification - Your \nFlow account \nis ready, \nlet\'s back it up! + Your Flow account is ready, let\'s back it up! Backing up your account ensures your access is secure and always in your control Creating your Profile Create Backup @@ -593,10 +594,10 @@ Multi-sign Can not Revoke Current Device Key Login Failure - Move NFT Failed - Move NFT Success - Send NFT Success - Send NFT Failed + NFT स्थानांतरण असफल + NFT स्थानांतरण सफल + NFT भेजना सफल + NFT भेजना विफल Sync Account Info Failure Add Public Key Failure Send Response Failure @@ -612,7 +613,7 @@ Please try again later. Debug View Export Log - View Recovery Phrase + रिकवरी वाक्यांश देखें Clear Send Success Send Failed @@ -665,7 +666,7 @@ Add Token Success Invalid ERC20 address Token Contract Address - Enter the token contract address + Enter your flow token contract address Please enter valid EVM contract address Contracts Token Name @@ -702,17 +703,6 @@ Choose Swap Provider Welcome to Flow Wallet! Create an account to get started Scan - Punch Swap - swap.kittypunch.xyz - trado.one - Trado - Increment Finance - increment.fi - JSON - " *" - Cadence Script Version: %1$s - Search tokens - Token List Results Search NFT Loading NFTs... @@ -725,4 +715,10 @@ Function Parameters Call Data + "please file an issue.]]>" + %1$s is blocked! + Ignore warning, show anyway + Ignore warning, connect anyway + This app has been flagged as dangerous. diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 6171819ca..0ee854fcb 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -184,6 +184,8 @@ Aggiungi gettone Aggiunta di token non riuscita Gettone di ricerca + Cerca token + Elenco dei Token Conferma Inizializzazione Modalità sviluppatore @@ -238,7 +240,7 @@ Consentire a Flow Wallet di pagare la tariffa del gas per tutte le mie transazioni . Selezionare il file - Tassa di transazione + Costo della Transazione Tenere premuto per confermare Tieni premuto per firmare Abilitazione @@ -701,8 +703,6 @@ Scegli Provider Di Swap Benvenuto in Flow Wallet! Crea un account per iniziare Scansione - Cerca token - Elenco dei Token Risultati Cerca NFT Caricamento NFT... @@ -715,4 +715,9 @@ Funzione Parametri Dati d\'Invocazione + "per favore segnala un problema.]]>" + %1$s è bloccato! + Ignora avviso, mostra comunque + Ignora avviso, connetti comunque + Questa app è stata contrassegnata come pericolosa. diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index fb5e5448c..bbe4b5040 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -183,6 +183,8 @@ トークンの追加 トークンの追加に失敗 検索トークン + トークンを検索 + トークンリスト 確認 初期化 開発者モード @@ -237,7 +239,7 @@ Flow Walletが私のすべての取引のガス料金を支払うことを許可する 。 ファイルを選択 - 取引手数料 + トランザクション料金 ホールドして確認 長押しで署名 有効にする @@ -701,8 +703,6 @@ Secure Enclave は、デバイスのハードウェア レベルのセキュリ スワッププロバイダを選択 Flow Walletへようこそ!アカウントを作成して始めましょう スキャン - トークンを検索 - トークンリスト 検索結果 検索NFT NFTを読み込み中... @@ -715,4 +715,9 @@ Secure Enclave は、デバイスのハードウェア レベルのセキュリ 機能 引数 コールデータ + "問題を報告してください。]]>" + %1$s はブロックされています! + 警告を無視して、とにかく表示 + 警告を無視して、とにかく接続してください + このアプリは危険としてフラグ付けられています。 diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 04a912ad4..d6bc7696f 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -184,6 +184,8 @@ 토큰 추가 토큰 추가에 실패했습니다. 토큰 검색 + 토큰 검색 + 토큰 목록 확인 초기화 개발자 모드 @@ -695,8 +697,6 @@ 스왑 제공자 선택 Flow Wallet에 오신 것을 환영합니다! 시작하려면 계정을 만드세요 스캔 - 토큰 검색 - 토큰 목록 결과 NFT 검색 NFT 로딩중 @@ -709,4 +709,9 @@ 함수 매개변수 호출 데이터 + "문제를 제출해 주세요.]]>" + %1$s 가 차단되었습니다! + 경고 무시, 여전히 표시 + 경고 무시, 여전히 연결 + 이 앱은 위험하다고 표시되었습니다. diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 381b8e8e5..3e597f1a5 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -115,5 +115,6 @@ #28282A #40FFFFFF #E5E5E6 + #0A0A0B diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 3944b9987..759763384 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -184,6 +184,8 @@ Добавить токен Добавить маркер не удалось Токен поиска + Поиск токенов + Список Токенов Подтверждение Инициализация Режим разработчика @@ -697,9 +699,7 @@ #onFlow Выберите поставщика обмена Добро пожаловать в Flow Wallet! Создайте аккаунт, чтобы начать - Сканировать - Поиск токенов - Список Токенов + Сканирование Результаты Поиск NFT Загрузка NFT... @@ -712,4 +712,9 @@ Функция Параметры Данные звонка + "пожалуйста, сообщите о проблеме.]]>" + %1$s заблокирован! + Игнорировать предупреждение, все равно показывать + Игнорировать предупреждение, все равно подключаться + Это приложение было помечено как опасное. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index be3ce7b47..b8d48e26e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -33,6 +33,7 @@ 保护 致您的钱包 PIN 码 + 网格 创建 PIN 密码 PIN 请再次输入\n您的 PIN 码 @@ -181,6 +182,8 @@ 添加代币 添加代币失败 搜索代币 + 搜索代币 + 代币列表 确认 初始化 开发者模式 @@ -235,7 +238,7 @@ 让 Flow Wallet 为我的所有交易支付加密货币手续费 。 选择文件 - 交易费 + 交易手续费 按住确认 按住以签名 启用 @@ -699,9 +702,6 @@ 选择交换提供商 欢迎使用 Flow Wallet !创建一个帐户以开始 扫描 - 网格 - 搜索代币 - 代币列表 结果 搜索 NFT 正在加载 NFT... @@ -714,4 +714,9 @@ 函数 参数 调用数据 + "请提交问题。]]>" + %1$s 已被封禁! + 忽略警告,继续显示 + 忽略警告,继续连接 + 此应用已被标记为危险。 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2872f5732..d2d83a85c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -199,6 +199,8 @@ #290AC26C #0F71F2 #E93C3C + #1AE93C3C + #1CE93C3C #F9AD29 #29F9AD29 #2A2A2A @@ -208,4 +210,5 @@ #40000000 #F29E0D #1E1E1F + #F0F0F0 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9b9b67fa3..e6db2b619 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -737,4 +737,10 @@ Function Parameters Call Data + "please file an issue.]]>" + %1$s is blocked! + Ignore warning, show anyway + Ignore warning, connect anyway + This app has been flagged as dangerous.