Updated on 2026-08-14
This commit is contained in:
parent
1b706b20a7
commit
72c9e20396
19 changed files with 934 additions and 127 deletions
|
|
@ -91,6 +91,7 @@
|
|||
<string name="add_custom_token_title">Add custom token</string>
|
||||
<string name="add_tokens_title">Manage tokens</string>
|
||||
<string name="addfunds_buy_row_description">Credit card or bank account</string>
|
||||
<string name="addfunds_fund_token">Fund token</string>
|
||||
<string name="addfunds_receive_row_description">Share your address or QR-code</string>
|
||||
<string name="addfunds_swap_row_description">Between your portfolios</string>
|
||||
<string name="addfunds_you_receive_title">You receive</string>
|
||||
|
|
@ -1213,9 +1214,7 @@
|
|||
<string name="organize_tokens_title">Organize tokens</string>
|
||||
<string name="organize_tokens_ungroup">Ungroup</string>
|
||||
<string name="provider_name_support">%s support</string>
|
||||
<string name="push_notification_settings_banner_button_grant_permission">Grant permission</string>
|
||||
<string name="push_notification_settings_banner_description">Push Notifications are enabled but won\'t work until you allow notifications in your device settings</string>
|
||||
<string name="push_notification_settings_banner_description_grant_permission">Push Notifications are enabled but won\'t work until you grant permission</string>
|
||||
<string name="push_notification_settings_banner_description">Push Notifications are enabled but won\'t work until you allow them</string>
|
||||
<string name="push_notification_settings_banner_title">Allow notifications</string>
|
||||
<string name="push_notification_settings_offers_updates_subtitle">Product news, exclusive offers, and activity reminders.</string>
|
||||
<string name="push_notification_settings_offers_updates_title">Offers & Updates</string>
|
||||
|
|
@ -1687,11 +1686,13 @@
|
|||
<string name="tangem_pay_freeze_card_failed">Failed to freeze the card. Try again later.</string>
|
||||
<string name="tangem_pay_freeze_card_freeze">Freeze</string>
|
||||
<string name="tangem_pay_freeze_card_success">Your card is frozen.</string>
|
||||
<string name="tangem_pay_freeze_card_unfreeze">Unfreeze</string>
|
||||
<string name="tangem_pay_get_help">Get Help</string>
|
||||
<string name="tangem_pay_history_item_spend_mc_declined_reason">Reason: %s</string>
|
||||
<string name="tangem_pay_history_item_spend_mc_title_format" formatted="false">%s · %s</string>
|
||||
<string name="tangem_pay_history_item_spend_mcc">MCC %s</string>
|
||||
<string name="tangem_pay_other">Other</string>
|
||||
<string name="tangem_pay_pin_code_title">PIN-code</string>
|
||||
<string name="tangem_pay_rooted_device_subtitle">Unable to use on rooted devices</string>
|
||||
<string name="tangem_pay_status_completed">Completed</string>
|
||||
<string name="tangem_pay_status_declined">Declined</string>
|
||||
|
|
@ -1742,7 +1743,6 @@
|
|||
<string name="tangempay_card_details_open_wallet_title">Add card to Google Pay</string>
|
||||
<string name="tangempay_card_details_open_wallet_title_apple">Add card to Apple Pay</string>
|
||||
<string name="tangempay_card_details_pin_code">PIN code</string>
|
||||
<string name="tangempay_card_details_receive_description">Share your address or show QR-code</string>
|
||||
<string name="tangempay_card_details_receive_error_description">Technical issues detected. Please try again later or contact support.</string>
|
||||
<string name="tangempay_card_details_receive_error_title">Receive unavailable now</string>
|
||||
<string name="tangempay_card_details_reissue_card">Replace card</string>
|
||||
|
|
@ -1751,7 +1751,6 @@
|
|||
<string name="tangempay_card_details_rename_card_placeholder">Card name</string>
|
||||
<string name="tangempay_card_details_reveal_text">Reveal</string>
|
||||
<string name="tangempay_card_details_show_details">Show details</string>
|
||||
<string name="tangempay_card_details_swap_description">Swap any asset in your portfolio for card</string>
|
||||
<string name="tangempay_card_details_title">Card details</string>
|
||||
<string name="tangempay_card_details_unable_to_rename_card_description">Please try again later</string>
|
||||
<string name="tangempay_card_details_unfreeze_card">Unfreeze Card</string>
|
||||
|
|
@ -1769,6 +1768,7 @@
|
|||
<string name="tangempay_card_page_daily_limit_change">Change</string>
|
||||
<string name="tangempay_card_page_daily_limit_current_limit">Current limit</string>
|
||||
<string name="tangempay_card_page_daily_limit_error_description">We couldn\'t load your daily limit. Please try again.</string>
|
||||
<string name="tangempay_card_page_daily_limit_error_subtitle">Reload to try again</string>
|
||||
<string name="tangempay_card_page_daily_limit_error_title">Daily limit unavailable</string>
|
||||
<string name="tangempay_card_page_daily_limit_success_description">You can change it again anytime you like</string>
|
||||
<string name="tangempay_card_page_daily_limit_success_title">Daily limit is set</string>
|
||||
|
|
@ -1854,7 +1854,6 @@
|
|||
<string name="tangempay_sync_needed">Use your card or ring to renew session</string>
|
||||
<string name="tangempay_sync_needed_body">Use your card or ring to renew session</string>
|
||||
<string name="tangempay_sync_needed_button">Renew session</string>
|
||||
<string name="tangempay_sync_needed_restore_access">Renew session</string>
|
||||
<string name="tangempay_sync_needed_title">Payment account session expired</string>
|
||||
<string name="tangempay_tangem_visa_card">Use USDC for everyday payments</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay is temporarily unreachable</string>
|
||||
|
|
@ -1864,7 +1863,6 @@
|
|||
<string name="tangempay_topup_swap_body">Use crypto from your wallet to top up your payment account</string>
|
||||
<string name="tangempay_topup_swap_title">Swap from Tangem Wallet</string>
|
||||
<string name="tangempay_usdc_on_polygon_network">USDC on Polygon network</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Click the button below to restore access</string>
|
||||
<string name="tangempay_withdrawal_note_description">Funds from refunded purchases won’t be returned your on-chain Polygon balance or be available for withdrawal, but will stay on your card balance for purchases</string>
|
||||
<string name="tangempay_withdrawal_note_title">Please note</string>
|
||||
<string name="tangempay_your_pin_code">Your PIN code</string>
|
||||
|
|
|
|||
33
core/ui/src/main/res/drawable/ic_card_pin_24.xml
Normal file
33
core/ui/src/main/res/drawable/ic_card_pin_24.xml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M16.002,8.499C16.554,8.499 17.002,8.947 17.002,9.499V14.501C17.002,15.053 16.554,15.501 16.002,15.501C15.45,15.501 15.002,15.053 15.002,14.501V9.499C15.002,8.947 15.45,8.499 16.002,8.499Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M6.715,10.933C7.255,10.493 8.05,10.525 8.554,11.027C8.947,11.42 9.065,12.012 8.853,12.526C8.64,13.04 8.138,13.375 7.582,13.375C7.026,13.375 6.524,13.04 6.312,12.526C6.099,12.012 6.217,11.42 6.61,11.027L6.715,10.933Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M11.133,10.933C11.673,10.493 12.468,10.525 12.972,11.027C13.365,11.42 13.483,12.012 13.271,12.526C13.058,13.04 12.556,13.375 12,13.375C11.444,13.375 10.942,13.04 10.729,12.526C10.517,12.012 10.635,11.42 11.028,11.027L11.133,10.933Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M12,2C17.523,2 22,6.477 22,12C22,17.523 17.523,22 12,22C6.477,22 2,17.523 2,12C2,6.477 6.477,2 12,2ZM12,4C7.582,4 4,7.582 4,12C4,16.418 7.582,20 12,20C16.418,20 20,16.418 20,12C20,7.582 16.418,4 12,4Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
24
core/ui/src/main/res/drawable/ic_close_20.xml
Normal file
24
core/ui/src/main/res/drawable/ic_close_20.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M3.72,3.719C4.012,3.427 4.487,3.427 4.78,3.719L10,8.942L15.219,3.723C15.512,3.431 15.987,3.43 16.28,3.723C16.573,4.016 16.572,4.491 16.28,4.784L11.061,10.002L16.28,15.219C16.573,15.512 16.572,15.987 16.28,16.28C15.987,16.573 15.512,16.573 15.219,16.281L10,11.063L4.78,16.284C4.487,16.576 4.012,16.576 3.72,16.284C3.427,15.991 3.427,15.516 3.72,15.223L8.939,10.002L3.72,4.78C3.427,4.487 3.427,4.012 3.72,3.719Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
27
core/ui/src/main/res/drawable/ic_edit_card_20.xml
Normal file
27
core/ui/src/main/res/drawable/ic_edit_card_20.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M10,3C10.414,3 10.75,3.336 10.75,3.75C10.75,4.164 10.414,4.5 10,4.5H7.222C5.719,4.5 4.5,5.719 4.5,7.222V12.777C4.5,14.281 5.719,15.499 7.222,15.499H12.777C14.281,15.499 15.499,14.281 15.499,12.777V10C15.499,9.586 15.835,9.25 16.249,9.25C16.663,9.25 16.999,9.586 16.999,10V12.777C16.999,15.109 15.109,16.999 12.777,16.999H7.222C4.89,16.999 3,15.109 3,12.777V7.222C3,4.89 4.89,3 7.222,3H10Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M14.704,3C15.313,3.001 15.896,3.243 16.326,3.674C16.757,4.105 16.999,4.689 16.999,5.298C16.999,5.907 16.757,6.491 16.326,6.922C16.319,6.929 16.31,6.935 16.303,6.942H16.305C16.308,6.939 16.313,6.935 16.315,6.933L15.834,7.414C15.532,7.716 15.118,8.129 14.672,8.575C13.779,9.468 12.755,10.492 12.229,11.019C11.881,11.366 11.427,11.587 10.939,11.646L9.861,11.78C9.406,11.836 8.951,11.677 8.63,11.35C8.309,11.022 8.158,10.564 8.223,10.11L8.382,8.993C8.448,8.522 8.666,8.085 9.003,7.748C9.74,7.011 11.541,5.21 13.079,3.672C13.51,3.241 14.095,2.999 14.704,3ZM15.266,4.733C15.117,4.584 14.913,4.5 14.702,4.5C14.518,4.5 14.34,4.564 14.198,4.68L14.14,4.732C12.601,6.27 10.801,8.071 10.064,8.809C9.958,8.915 9.888,9.054 9.867,9.203V9.206L9.713,10.286L10.755,10.158H10.757C10.912,10.139 11.057,10.069 11.168,9.958L15.269,5.857C15.416,5.708 15.499,5.507 15.499,5.298C15.499,5.087 15.415,4.883 15.266,4.733Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
24
core/ui/src/main/res/drawable/ic_freeze_24.xml
Normal file
24
core/ui/src/main/res/drawable/ic_freeze_24.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,2C12.552,2 13,2.448 13,3V4.175L13.461,3.714C13.851,3.324 14.485,3.324 14.875,3.714C15.266,4.104 15.266,4.737 14.875,5.128L13,7.003V10.267L15.828,8.633L16.514,6.074C16.657,5.541 17.205,5.224 17.739,5.367C18.272,5.51 18.588,6.058 18.445,6.592L18.277,7.22L19.5,6.514C19.978,6.238 20.59,6.402 20.866,6.88C21.142,7.358 20.978,7.97 20.5,8.246L19.276,8.952L19.906,9.122C20.44,9.265 20.756,9.813 20.614,10.347C20.471,10.88 19.922,11.196 19.389,11.054L16.826,10.367L13.999,11.999L16.826,13.632L19.389,12.946C19.922,12.804 20.471,13.12 20.614,13.653C20.756,14.187 20.44,14.735 19.906,14.878L19.276,15.046L20.5,15.754C20.978,16.03 21.142,16.642 20.866,17.12C20.59,17.598 19.978,17.762 19.5,17.486L18.277,16.779L18.445,17.408C18.588,17.941 18.272,18.49 17.739,18.633C17.205,18.776 16.657,18.459 16.514,17.926L15.828,15.365L13,13.732V16.996L14.875,18.872C15.266,19.263 15.266,19.896 14.875,20.286C14.485,20.676 13.851,20.677 13.461,20.286L13,19.824V21C13,21.552 12.552,22 12,22C11.448,22 11,21.552 11,21V19.824L10.539,20.286C10.149,20.676 9.516,20.676 9.125,20.286C8.735,19.896 8.735,19.263 9.125,18.872L11,16.996V13.732L8.172,15.364L7.487,17.926C7.345,18.459 6.796,18.775 6.263,18.633C5.73,18.49 5.413,17.942 5.556,17.408L5.724,16.779L4.5,17.486C4.022,17.762 3.41,17.598 3.134,17.12C2.858,16.642 3.022,16.03 3.5,15.754L4.724,15.046L4.095,14.878C3.562,14.735 3.245,14.187 3.388,13.653C3.531,13.12 4.079,12.803 4.612,12.946L7.173,13.632L9.999,11.999L7.174,10.367L4.612,11.054C4.079,11.197 3.531,10.88 3.388,10.347C3.245,9.813 3.561,9.265 4.095,9.122L4.724,8.953L3.5,8.246C3.022,7.97 2.858,7.358 3.134,6.88C3.41,6.402 4.022,6.238 4.5,6.514L5.724,7.22L5.556,6.592C5.413,6.058 5.73,5.51 6.263,5.367C6.796,5.225 7.345,5.541 7.487,6.074L8.172,8.634L11,10.267V7.003L9.125,5.128C8.735,4.737 8.735,4.104 9.125,3.714C9.516,3.324 10.149,3.324 10.539,3.714L11,4.175V3C11,2.448 11.448,2 12,2Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
27
core/ui/src/main/res/drawable/ic_limit_new_20.xml
Normal file
27
core/ui/src/main/res/drawable/ic_limit_new_20.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M4.34,4.367C7.465,1.211 12.535,1.211 15.66,4.367C18.779,7.519 18.779,12.627 15.66,15.78C15.368,16.074 14.892,16.077 14.598,15.786C14.304,15.495 14.302,15.02 14.593,14.725C17.135,12.157 17.135,7.99 14.593,5.422C12.055,2.858 7.943,2.858 5.406,5.422C2.864,7.99 2.864,12.157 5.406,14.725C5.697,15.02 5.695,15.495 5.401,15.786C5.106,16.077 4.632,16.074 4.34,15.78C1.22,12.627 1.22,7.52 4.34,4.367Z"
|
||||
android:fillColor="#0090F9"/>
|
||||
<path
|
||||
android:pathData="M12.121,6.724C12.413,6.431 12.888,6.428 13.182,6.719C13.476,7.01 13.479,7.485 13.188,7.779L10.463,10.531C10.172,10.825 9.697,10.827 9.403,10.536C9.108,10.245 9.106,9.77 9.397,9.475L12.121,6.724Z"
|
||||
android:fillColor="#0090F9"/>
|
||||
</vector>
|
||||
27
core/ui/src/main/res/drawable/ic_visa_card_details_24.xml
Normal file
27
core/ui/src/main/res/drawable/ic_visa_card_details_24.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M9.57,14C10.123,14 10.57,14.448 10.57,15C10.57,15.552 10.123,16 9.57,16H7C6.448,16 6,15.552 6,15C6,14.448 6.448,14 7,14H9.57Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M18,4C20.209,4 22,5.791 22,8V16C22,18.209 20.209,20 18,20H6C3.791,20 2,18.209 2,16V8C2,5.791 3.791,4 6,4H18ZM4,16C4,17.105 4.895,18 6,18H18C19.105,18 20,17.105 20,16V10H4V16ZM6,6C4.895,6 4,6.895 4,8H20C20,6.895 19.105,6 18,6H6Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
30
core/ui/src/main/res/drawable/ic_warning_20.xml
Normal file
30
core/ui/src/main/res/drawable/ic_warning_20.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M10.096,12.376C10.571,12.424 10.945,12.825 10.945,13.315C10.945,13.837 10.522,14.26 10,14.261C9.478,14.26 9.056,13.837 9.056,13.315C9.055,12.791 9.481,12.371 10,12.371L10.096,12.376Z"
|
||||
android:fillColor="#E68A03"/>
|
||||
<path
|
||||
android:pathData="M10,5.739C10.414,5.74 10.75,6.075 10.75,6.489V10.39C10.75,10.804 10.414,11.139 10,11.14C9.586,11.139 9.25,10.804 9.25,10.39V6.489C9.25,6.075 9.586,5.739 10,5.739Z"
|
||||
android:fillColor="#E68A03"/>
|
||||
<path
|
||||
android:pathData="M12.554,2.002C13.179,2.002 13.78,2.251 14.223,2.693L17.305,5.775C17.749,6.218 17.998,6.819 17.998,7.445V12.554C17.998,13.179 17.749,13.78 17.307,14.223L13.752,17.778C13.611,17.919 13.42,17.998 13.221,17.998H7.445C6.82,17.998 6.219,17.749 5.776,17.307L2.693,14.224C2.251,13.781 2.002,13.181 2.002,12.555V7.445C2.002,6.819 2.251,6.219 2.693,5.776L5.776,2.693C6.219,2.251 6.819,2.002 7.445,2.002H12.554ZM7.445,3.502C7.218,3.502 6.998,3.593 6.837,3.754L3.754,6.837C3.593,6.998 3.502,7.218 3.502,7.445V12.555C3.502,12.782 3.593,13.002 3.754,13.163L6.837,16.245C6.998,16.407 7.218,16.498 7.445,16.498H12.91L16.245,13.162C16.407,13.001 16.498,12.781 16.498,12.554V7.445C16.498,7.218 16.407,6.999 16.245,6.838L13.162,3.754C13.001,3.593 12.781,3.502 12.554,3.502H7.445Z"
|
||||
android:fillColor="#E68A03"/>
|
||||
</vector>
|
||||
|
|
@ -1,13 +1,18 @@
|
|||
package com.tangem.features.tangempay.entity
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
@Immutable
|
||||
internal data class TangemPayCardPageUM(
|
||||
val settings: ImmutableList<TangemPayCardPageSetting>,
|
||||
val settingsV2: ImmutableList<TangemPayCardPageSettingV2>,
|
||||
val onBackClick: () -> Unit,
|
||||
val dailyLimitState: TangemPayDailyLimitBlockState,
|
||||
val addToWalletBlockState: AddToWalletBlockState? = null,
|
||||
|
|
@ -15,7 +20,11 @@ internal data class TangemPayCardPageUM(
|
|||
) {
|
||||
companion object {
|
||||
fun stub(
|
||||
addToWalletBlockState: AddToWalletBlockState? = AddToWalletBlockState(onClick = {}, onClickClose = {}),
|
||||
addToWalletBlockState: AddToWalletBlockState? = AddToWalletBlockState(
|
||||
onClick = {},
|
||||
onClickClose = {},
|
||||
shouldUseMagicEffect = false,
|
||||
),
|
||||
settings: ImmutableList<TangemPayCardPageSetting> = persistentListOf(
|
||||
TangemPayCardPageSetting(TextReference.Str("Pin Code")) {},
|
||||
TangemPayCardPageSetting(TextReference.Str("Freeze Card")) {},
|
||||
|
|
@ -23,9 +32,11 @@ internal data class TangemPayCardPageUM(
|
|||
),
|
||||
isReissueInProgress: Boolean = false,
|
||||
dailyLimitState: TangemPayDailyLimitBlockState = TangemPayDailyLimitBlockState.Content.stub(),
|
||||
settingsV2: ImmutableList<TangemPayCardPageSettingV2> = TangemPayCardPageSettingV2.stubList(),
|
||||
) = TangemPayCardPageUM(
|
||||
addToWalletBlockState = addToWalletBlockState,
|
||||
settings = settings,
|
||||
settingsV2 = settingsV2,
|
||||
onBackClick = {},
|
||||
isReissueInProgress = isReissueInProgress,
|
||||
dailyLimitState = dailyLimitState,
|
||||
|
|
@ -38,4 +49,49 @@ internal data class TangemPayCardPageSetting(
|
|||
val title: TextReference,
|
||||
val testTag: String? = null,
|
||||
val onSettingClick: () -> Unit,
|
||||
)
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal data class TangemPayCardPageSettingV2(
|
||||
val id: Id,
|
||||
val title: TextReference,
|
||||
val isLoading: Boolean = false,
|
||||
val isEnabled: Boolean = true,
|
||||
val testTag: String? = null,
|
||||
val onClick: () -> Unit,
|
||||
@param:DrawableRes val iconRes: Int,
|
||||
) {
|
||||
|
||||
enum class Id {
|
||||
Details, Freeze, ChangePin
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun stubList(isFrozen: Boolean = false): ImmutableList<TangemPayCardPageSettingV2> = persistentListOf(
|
||||
TangemPayCardPageSettingV2(
|
||||
id = Id.Details,
|
||||
title = resourceReference(R.string.details_title),
|
||||
onClick = {},
|
||||
iconRes = CoreUiR.drawable.ic_visa_card_details_24,
|
||||
),
|
||||
TangemPayCardPageSettingV2(
|
||||
id = Id.Freeze,
|
||||
title = resourceReference(
|
||||
if (isFrozen) {
|
||||
R.string.tangem_pay_freeze_card_unfreeze
|
||||
} else {
|
||||
R.string.tangem_pay_freeze_card_freeze
|
||||
},
|
||||
),
|
||||
onClick = {},
|
||||
iconRes = CoreUiR.drawable.ic_freeze_24,
|
||||
),
|
||||
TangemPayCardPageSettingV2(
|
||||
id = Id.ChangePin,
|
||||
title = resourceReference(R.string.tangem_pay_pin_code_title),
|
||||
onClick = {},
|
||||
iconRes = CoreUiR.drawable.ic_card_pin_24,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.tangempay.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
|
|
@ -34,6 +35,7 @@ internal data class TangemPayCardDetailsUM(
|
|||
val isActionsAvailable: Boolean = false,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal sealed interface DisplayNameState {
|
||||
|
||||
val displayName: String
|
||||
|
|
@ -61,6 +63,7 @@ internal sealed interface DisplayNameState {
|
|||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal sealed class TangemPayDetailsBalanceBlockState {
|
||||
|
||||
abstract val actionButtons: ImmutableList<ActionButtonConfig>
|
||||
|
|
@ -94,4 +97,5 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
|||
internal data class AddToWalletBlockState(
|
||||
val onClick: () -> Unit,
|
||||
val onClickClose: () -> Unit,
|
||||
val shouldUseMagicEffect: Boolean,
|
||||
)
|
||||
|
|
@ -66,7 +66,7 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor(
|
|||
displayName = card.displayName,
|
||||
isEditingNameEnabled = params.isEditingNameEnabled,
|
||||
onEditNameClick = ::startEditingDisplayName,
|
||||
onReveal = ::revealCardDetails,
|
||||
onReveal = ::requestReveal,
|
||||
onCopy = ::copyData,
|
||||
)
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor(
|
|||
) {
|
||||
val card = status.requireCardWithId(cardId)
|
||||
if (card.isReissuing) {
|
||||
hideCardDetails()
|
||||
requestHide()
|
||||
}
|
||||
card.displayName?.let { uiState.update(TangemPayCardDetailsUpdateNameTransformer(it)) }
|
||||
uiState.update { uiState ->
|
||||
|
|
@ -124,18 +124,26 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun requestReveal() {
|
||||
modelScope.launch { cardDetailsEventListener.send(CardDetailsEvent.Show) }
|
||||
}
|
||||
|
||||
private fun requestHide() {
|
||||
modelScope.launch { cardDetailsEventListener.send(CardDetailsEvent.Hide) }
|
||||
}
|
||||
|
||||
private fun revealCardDetails() {
|
||||
analytics.send(TangemPayAnalyticsEvents.ViewCardDetailsClicked())
|
||||
modelScope.launch {
|
||||
uiState.transformerUpdate(
|
||||
transformer = DetailsRevealProgressStateTransformer(onClickHide = ::hideCardDetails),
|
||||
transformer = DetailsRevealProgressStateTransformer(onClickHide = ::requestHide),
|
||||
)
|
||||
cardDetailsRepository.revealCardDetails(params.userWalletId)
|
||||
.onRight { cardDetails ->
|
||||
uiState.transformerUpdate(
|
||||
transformer = DetailsRevealedStateTransformer(
|
||||
details = cardDetails,
|
||||
onClickHide = ::hideCardDetails,
|
||||
onClickHide = ::requestHide,
|
||||
),
|
||||
)
|
||||
launchShowDetailsTimer()
|
||||
|
|
@ -150,11 +158,11 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor(
|
|||
private fun launchShowDetailsTimer() {
|
||||
modelScope.launch {
|
||||
delay(SHOW_DETAILS_TIME)
|
||||
hideCardDetails()
|
||||
requestHide()
|
||||
}.saveIn(showCardDetailsTimerJobHolder)
|
||||
}
|
||||
|
||||
fun hideCardDetails() {
|
||||
private fun hideCardDetails() {
|
||||
revealCardDetailsJobHolder.cancel()
|
||||
uiState.transformerUpdate(transformer = DetailsHiddenStateTransformer(stateFactory))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
|
|
@ -39,6 +40,8 @@ import com.tangem.features.tangempay.components.TangemPayCardPageComponent
|
|||
import com.tangem.features.tangempay.components.ViewPinListener
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.*
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEvent
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
|
||||
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
|
||||
import com.tangem.features.tangempay.utils.TangemPayMessagesFactory
|
||||
import com.tangem.features.tangempay.utils.cryptoCurrency
|
||||
|
|
@ -49,9 +52,11 @@ import com.tangem.utils.coroutines.JobHolder
|
|||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Stable
|
||||
|
|
@ -65,6 +70,8 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val changeCardFrozenStateUseCase: ChangeCardFrozenStateUseCase,
|
||||
private val designFeatureToggles: DesignFeatureToggles,
|
||||
private val cardDetailsEventListener: CardDetailsEventListener,
|
||||
) : Model(), ViewPinListener, ReissueCardListener, AddFundsListener {
|
||||
|
||||
private val params: TangemPayCardPageComponent.Params = paramsContainer.require()
|
||||
|
|
@ -82,6 +89,7 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
onBackClick = router::pop,
|
||||
dailyLimitState = TangemPayDailyLimitBlockState.Loading,
|
||||
settings = persistentListOf(),
|
||||
settingsV2 = persistentListOf(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -90,6 +98,7 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
init {
|
||||
analytics.send(TangemPayAnalyticsEvents.CardManagementScreenOpened())
|
||||
fetchAddToWalletBanner()
|
||||
modelScope.launch { subscribeOnDetailsState() }
|
||||
|
||||
paymentAccountStatusSupplier.invoke(userWalletId)
|
||||
.onEach { state ->
|
||||
|
|
@ -115,6 +124,7 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
uiState.copy(
|
||||
dailyLimitState = dailyLimitState,
|
||||
settings = buildSettings(card),
|
||||
settingsV2 = buildSettingsV2(card),
|
||||
isReissueInProgress = card.isReissuing,
|
||||
)
|
||||
}
|
||||
|
|
@ -126,6 +136,7 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun buildSettings(card: TangemPayCard): ImmutableList<TangemPayCardPageSetting> {
|
||||
if (designFeatureToggles.isRedesignEnabled) return persistentListOf()
|
||||
return persistentListOf(
|
||||
TangemPayCardPageSetting(
|
||||
title = TextReference.Res(R.string.tangempay_card_details_change_pin),
|
||||
|
|
@ -150,6 +161,64 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun subscribeOnDetailsState() {
|
||||
if (!designFeatureToggles.isRedesignEnabled) return
|
||||
cardDetailsEventListener.event.collect { event ->
|
||||
val isDetailsShown = event == CardDetailsEvent.Show
|
||||
uiState.update { state ->
|
||||
state.copy(
|
||||
settingsV2 = state.settingsV2
|
||||
.map { setting ->
|
||||
if (setting.id == TangemPayCardPageSettingV2.Id.Details) {
|
||||
setting.copy(isEnabled = !isDetailsShown)
|
||||
} else {
|
||||
setting
|
||||
}
|
||||
}
|
||||
.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildSettingsV2(card: TangemPayCard): ImmutableList<TangemPayCardPageSettingV2> {
|
||||
if (!designFeatureToggles.isRedesignEnabled) return persistentListOf()
|
||||
return persistentListOf(
|
||||
TangemPayCardPageSettingV2(
|
||||
id = TangemPayCardPageSettingV2.Id.Details,
|
||||
title = TextReference.Res(R.string.details_title),
|
||||
onClick = ::onClickViewDetails,
|
||||
iconRes = CoreUiR.drawable.ic_visa_card_details_24,
|
||||
),
|
||||
TangemPayCardPageSettingV2(
|
||||
id = TangemPayCardPageSettingV2.Id.Freeze,
|
||||
title = TextReference.Res(
|
||||
if (card.isFrozen) {
|
||||
R.string.tangem_pay_freeze_card_unfreeze
|
||||
} else {
|
||||
R.string.tangem_pay_freeze_card_freeze
|
||||
},
|
||||
),
|
||||
onClick = { onClickFreezeOrUnfreezeCard(card.isFrozen) },
|
||||
iconRes = CoreUiR.drawable.ic_freeze_24,
|
||||
testTag = TangemPayTestTags.FREEZE_CARD_ROW,
|
||||
),
|
||||
TangemPayCardPageSettingV2(
|
||||
id = TangemPayCardPageSettingV2.Id.ChangePin,
|
||||
title = TextReference.Res(R.string.tangempay_card_details_change_pin),
|
||||
onClick = { onClickChangePIN(card.hasPinCode) },
|
||||
iconRes = CoreUiR.drawable.ic_card_pin_24,
|
||||
testTag = TangemPayTestTags.CHANGE_PIN_ROW,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onClickViewDetails() {
|
||||
modelScope.launch(dispatchers.default) {
|
||||
cardDetailsEventListener.send(CardDetailsEvent.Show)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onClickLimitChange() {
|
||||
analytics.send(TangemPayAnalyticsEvents.LimitChangeClicked())
|
||||
router.push(TangemPayCardDetailsInnerRoute.LimitSetup)
|
||||
|
|
@ -284,6 +353,7 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
addToWalletBlockState = AddToWalletBlockState(
|
||||
onClick = ::onClickAddToWallet,
|
||||
onClickClose = ::onClickCloseBanner,
|
||||
shouldUseMagicEffect = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ internal class DetailsAddToWalletBannerTransformer(
|
|||
addToWalletBlockState = if (isDone) {
|
||||
null
|
||||
} else {
|
||||
AddToWalletBlockState(onClick = onClickBanner, onClickClose = onClickCloseBanner)
|
||||
AddToWalletBlockState(
|
||||
onClick = onClickBanner,
|
||||
onClickClose = onClickCloseBanner,
|
||||
shouldUseMagicEffect = true,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,12 @@ import androidx.compose.ui.graphics.ColorFilter
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.ds.message.TangemMessage
|
||||
import com.tangem.core.ui.ds.message.TangemMessageEffect
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
|
|
@ -32,6 +37,15 @@ private const val GRADIENT_RADIUS = 200F
|
|||
|
||||
@Composable
|
||||
internal fun TangemPayAddToWalletBlock(state: AddToWalletBlockState, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TangemPayAddToWalletBlockV2(state = state, modifier = modifier)
|
||||
} else {
|
||||
TangemPayAddToWalletBlockV1(state = state, modifier = modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayAddToWalletBlockV1(state: AddToWalletBlockState, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -55,7 +69,9 @@ internal fun TangemPayAddToWalletBlock(state: AddToWalletBlockState, modifier: M
|
|||
Image(
|
||||
painter = painterResource(R.drawable.img_google_wallet_48),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(36.dp).clip(CircleShape),
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape),
|
||||
)
|
||||
|
||||
Spacer(Modifier.width(12.dp))
|
||||
|
|
@ -97,11 +113,26 @@ internal fun TangemPayAddToWalletBlock(state: AddToWalletBlockState, modifier: M
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayAddToWalletBlockV2(state: AddToWalletBlockState, modifier: Modifier = Modifier) {
|
||||
TangemMessage(
|
||||
modifier = modifier.clickableSingle(onClick = state.onClick),
|
||||
onCloseClick = state.onClickClose,
|
||||
title = resourceReference(R.string.tangempay_card_details_open_wallet_notification_title),
|
||||
subtitle = resourceReference(R.string.tangempay_card_details_open_wallet_notification_subtitle),
|
||||
messageEffect = if (state.shouldUseMagicEffect) {
|
||||
TangemMessageEffect.Magic
|
||||
} else {
|
||||
TangemMessageEffect.None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewTangemPayAddToWalletBlock() {
|
||||
TangemThemePreview {
|
||||
TangemPayAddToWalletBlock(AddToWalletBlockState({}, {}))
|
||||
TangemPayAddToWalletBlock(AddToWalletBlockState(onClick = {}, onClickClose = {}, shouldUseMagicEffect = false))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.tangempay.ui
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.EaseInOut
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
|
|
@ -13,10 +14,7 @@ import androidx.compose.foundation.text.BasicTextField
|
|||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -26,9 +24,11 @@ import androidx.compose.ui.graphics.Brush
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
|
|
@ -37,18 +37,20 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstrainedLayoutReference
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.ConstraintLayoutScope
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import com.tangem.core.ui.components.SpacerW4
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds2.button.TangemButton
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.*
|
||||
import com.tangem.core.ui.test.TangemPayTestTags
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
|
|
@ -129,23 +131,7 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
|
|||
painter = painterResource(id = imageResId),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_cloud_fill_16),
|
||||
tint = TangemTheme.colors.icon.constant,
|
||||
contentDescription = null,
|
||||
)
|
||||
SpacerW4()
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.tangempay_digital_card),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
}
|
||||
CardTopBlock()
|
||||
|
||||
if (state.isActionsAvailable) {
|
||||
ConstraintLayout(
|
||||
|
|
@ -167,18 +153,11 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = state.numberShort,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
modifier = Modifier
|
||||
.constrainAs(cardNumberRef) {
|
||||
start.linkTo(parent.start)
|
||||
bottom.linkTo(parent.bottom)
|
||||
}
|
||||
.padding(bottom = 8.dp),
|
||||
CardNumberBlock(
|
||||
numberShort = state.numberShort,
|
||||
cardNumberRef = cardNumberRef,
|
||||
)
|
||||
|
||||
when (state.cardFrozenState) {
|
||||
TangemPayCardFrozenState.Frozen -> Icon(
|
||||
modifier = Modifier
|
||||
|
|
@ -209,23 +188,93 @@ private fun TangemPayCardDetailsHiddenBlock(state: TangemPayCardDetailsUM, modif
|
|||
)
|
||||
TangemPayCardFrozenState.Unfrozen -> Unit
|
||||
}
|
||||
|
||||
TangemPayCardDetailsCustomButton(
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier
|
||||
.constrainAs(buttonRef) {
|
||||
end.linkTo(parent.end)
|
||||
bottom.linkTo(parent.bottom)
|
||||
}
|
||||
.testTag(TangemPayTestTags.CARD_DETAILS_SHOW_BUTTON),
|
||||
text = stringResourceSafe(id = R.string.tangempay_card_details_show_details),
|
||||
onClick = state.onClick,
|
||||
showProgress = state.isLoading,
|
||||
)
|
||||
visible = !LocalRedesignEnabled.current || state.isLoading,
|
||||
) {
|
||||
TangemPayCardDetailsCustomButton(
|
||||
text = stringResourceSafe(id = R.string.tangempay_card_details_show_details),
|
||||
onClick = state.onClick,
|
||||
showProgress = state.isLoading,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardTopBlock(modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.tangempay_digital_card),
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.staticDark.primary,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x5),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_cloud_fill_16),
|
||||
tint = TangemTheme.colors3.icon.staticDark,
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_cloud_fill_16),
|
||||
tint = TangemTheme.colors.icon.constant,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.tangempay_digital_card),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConstraintLayoutScope.CardNumberBlock(
|
||||
numberShort: String,
|
||||
cardNumberRef: ConstrainedLayoutReference,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
Text(
|
||||
text = numberShort,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.staticDark.primary,
|
||||
modifier = modifier
|
||||
.constrainAs(cardNumberRef) {
|
||||
start.linkTo(parent.start)
|
||||
bottom.linkTo(parent.bottom)
|
||||
}
|
||||
.padding(bottom = 8.dp),
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = numberShort,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
modifier = modifier
|
||||
.constrainAs(cardNumberRef) {
|
||||
start.linkTo(parent.start)
|
||||
bottom.linkTo(parent.bottom)
|
||||
}
|
||||
.padding(bottom = 8.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardDisplayName(state: DisplayNameState, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
|
|
@ -236,36 +285,67 @@ private fun CardDisplayName(state: DisplayNameState, modifier: Modifier = Modifi
|
|||
|
||||
@Composable
|
||||
private fun DisplayOnlyCardDisplayName(state: DisplayNameState.Display, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier.conditional(
|
||||
condition = state.isEditingEnabled,
|
||||
modifier = { clickable(onClick = state.onClick) },
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = state.displayName,
|
||||
style = TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite),
|
||||
maxLines = 1,
|
||||
)
|
||||
if (state.isEditingEnabled) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_edit_new_12),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(10.dp),
|
||||
tint = TangemTheme.colors.text.constantWhite,
|
||||
if (LocalRedesignEnabled.current) {
|
||||
Row(
|
||||
modifier = modifier.conditional(
|
||||
condition = state.isEditingEnabled,
|
||||
modifier = { clickable(onClick = state.onClick) },
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = state.displayName,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.staticDark.secondary,
|
||||
maxLines = 1,
|
||||
)
|
||||
if (state.isEditingEnabled) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_edit_card_20),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x5),
|
||||
tint = TangemTheme.colors3.icon.staticDark,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
modifier = modifier.conditional(
|
||||
condition = state.isEditingEnabled,
|
||||
modifier = { clickable(onClick = state.onClick) },
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = state.displayName,
|
||||
style = TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite),
|
||||
maxLines = 1,
|
||||
)
|
||||
if (state.isEditingEnabled) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_edit_new_12),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(10.dp),
|
||||
tint = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditingCardDisplayName(state: DisplayNameState.Editing, modifier: Modifier = Modifier) {
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val placeholder = stringResourceSafe(R.string.tangempay_card_edit_name_placeholder)
|
||||
|
||||
val textStyle = TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite)
|
||||
val textStyle = if (isRedesignEnabled) {
|
||||
TangemTheme.typography3.body.medium.copy(color = TangemTheme.colors3.text.staticDark.primary)
|
||||
} else {
|
||||
TangemTheme.typography.caption1.copy(color = TangemTheme.colors.text.constantWhite)
|
||||
}
|
||||
val textMeasurer = rememberTextMeasurer()
|
||||
val measuredText = state.editingValue.text.ifEmpty { placeholder }
|
||||
val textWidthDp = with(LocalDensity.current) {
|
||||
|
|
@ -280,7 +360,11 @@ private fun EditingCardDisplayName(state: DisplayNameState.Editing, modifier: Mo
|
|||
.focusRequester(focusRequester),
|
||||
textStyle = textStyle,
|
||||
singleLine = true,
|
||||
cursorBrush = SolidColor(TangemTheme.colors.text.constantWhite),
|
||||
cursorBrush = if (isRedesignEnabled) {
|
||||
SolidColor(TangemTheme.colors3.text.staticDark.primary)
|
||||
} else {
|
||||
SolidColor(TangemTheme.colors.text.constantWhite)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = if (state.isSubmitEnabled) {
|
||||
|
|
@ -294,7 +378,13 @@ private fun EditingCardDisplayName(state: DisplayNameState.Editing, modifier: Mo
|
|||
if (state.editingValue.text.isEmpty()) {
|
||||
Text(
|
||||
text = placeholder,
|
||||
style = textStyle.copy(color = TangemTheme.colors.text.tertiary),
|
||||
style = textStyle.copy(
|
||||
color = if (isRedesignEnabled) {
|
||||
TangemTheme.colors3.text.staticDark.secondary
|
||||
} else {
|
||||
TangemTheme.colors.text.tertiary
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
innerTextField()
|
||||
|
|
@ -317,10 +407,7 @@ private fun TangemPayCardDetailsShownBlock(
|
|||
onHideDetails: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
Column(modifier = modifier.fillMaxSize()) {
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp, bottom = 12.dp, start = 16.dp, end = 16.dp)
|
||||
|
|
@ -361,14 +448,31 @@ private fun TangemPayCardDetailsShownBlock(
|
|||
Spacer(modifier = Modifier.weight(1f))
|
||||
Row {
|
||||
SpacerWMax()
|
||||
TangemPayCardDetailsCustomButton(
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp, bottom = 8.dp)
|
||||
.testTag(TangemPayTestTags.CARD_DETAILS_HIDE_BUTTON),
|
||||
text = stringResourceSafe(id = R.string.tangempay_card_details_hide_details),
|
||||
onClick = onHideDetails,
|
||||
showProgress = false,
|
||||
)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
// Must use dark theme locally for button cause card is dark
|
||||
CompositionLocalProvider(LocalIsInDarkTheme provides true) {
|
||||
TangemThemeRedesign {
|
||||
TangemButton(
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp, bottom = 8.dp)
|
||||
.testTag(TangemPayTestTags.CARD_DETAILS_HIDE_BUTTON),
|
||||
variant = TangemButton.Variant.Material,
|
||||
size = TangemButton.Size.X8,
|
||||
onClick = onHideDetails,
|
||||
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_close_20),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TangemPayCardDetailsCustomButton(
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp, bottom = 8.dp)
|
||||
.testTag(TangemPayTestTags.CARD_DETAILS_HIDE_BUTTON),
|
||||
text = stringResourceSafe(id = R.string.tangempay_card_details_hide_details),
|
||||
onClick = onHideDetails,
|
||||
showProgress = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -26,8 +27,10 @@ import androidx.compose.ui.util.fastForEach
|
|||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
|
||||
|
|
@ -44,6 +47,7 @@ internal fun TangemPayCardPageScreen(
|
|||
cardDetailsState: TangemPayCardDetailsUM,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
|
|
@ -53,7 +57,11 @@ internal fun TangemPayCardPageScreen(
|
|||
)
|
||||
},
|
||||
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(WindowInsets.navigationBars),
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
containerColor = if (isRedesignEnabled) {
|
||||
TangemTheme.colors3.bg.primary
|
||||
} else {
|
||||
TangemTheme.colors.background.secondary
|
||||
},
|
||||
) { scaffoldPaddings ->
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
LazyColumn(
|
||||
|
|
@ -73,6 +81,14 @@ internal fun TangemPayCardPageScreen(
|
|||
state = cardDetailsState,
|
||||
)
|
||||
}
|
||||
if (isRedesignEnabled && state.settingsV2.isNotEmpty()) {
|
||||
cardPageItem("Settings buttons") {
|
||||
TangemPayCardPageSettingsButtonsBlock(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
settings = state.settingsV2,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (state.isReissueInProgress) {
|
||||
cardPageItem(key = "Reissue") {
|
||||
TangemPayReplacingCardBlock()
|
||||
|
|
@ -104,6 +120,7 @@ private fun TangemPayCardPageSettingsBlock(
|
|||
settings: ImmutableList<TangemPayCardPageSetting>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (LocalRedesignEnabled.current) return
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -176,11 +193,27 @@ private fun LazyListScope.cardPageItem(
|
|||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun preview() = TangemThemePreview {
|
||||
TangemPayCardPageScreen(
|
||||
state = TangemPayCardPageUM.stub(),
|
||||
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
|
||||
TangemPayCardDetailsUM(
|
||||
private fun TangemPayCardPageScreenPreviewV1() {
|
||||
TangemThemePreview {
|
||||
TangemPayCardPageScreen(
|
||||
state = TangemPayCardPageUM.stub(),
|
||||
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
|
||||
TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = { _, _ -> },
|
||||
onClick = {},
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = DisplayNameState.Display(
|
||||
displayName = "Tangem Pay Card",
|
||||
onClick = {},
|
||||
isEditingEnabled = true,
|
||||
),
|
||||
),
|
||||
),
|
||||
cardDetailsState = TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
|
|
@ -191,23 +224,52 @@ private fun preview() = TangemThemePreview {
|
|||
displayNameState = DisplayNameState.Display(
|
||||
displayName = "Tangem Pay Card",
|
||||
onClick = {},
|
||||
isEditingEnabled = true,
|
||||
isEditingEnabled = false,
|
||||
),
|
||||
),
|
||||
),
|
||||
cardDetailsState = TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = { _, _ -> },
|
||||
onClick = {},
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = DisplayNameState.Display(
|
||||
displayName = "Tangem Pay Card",
|
||||
onClick = {},
|
||||
isEditingEnabled = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayCardPageScreenPreviewV2() {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
TangemPayCardPageScreen(
|
||||
state = TangemPayCardPageUM.stub(),
|
||||
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
|
||||
TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = { _, _ -> },
|
||||
onClick = {},
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = DisplayNameState.Display(
|
||||
displayName = "Tangem Pay Card",
|
||||
onClick = {},
|
||||
isEditingEnabled = true,
|
||||
),
|
||||
),
|
||||
),
|
||||
cardDetailsState = TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
numberShort = "··1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = { _, _ -> },
|
||||
onClick = {},
|
||||
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
displayNameState = DisplayNameState.Display(
|
||||
displayName = "Tangem Pay Card",
|
||||
onClick = {},
|
||||
isEditingEnabled = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tangem.features.tangempay.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds2.button.TangemButton
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardPageSettingV2
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCardPageSettingsButtonsBlock(
|
||||
settings: ImmutableList<TangemPayCardPageSettingV2>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (settings.isEmpty()) return
|
||||
Row(
|
||||
modifier = modifier.padding(vertical = TangemTheme.dimens2.x6),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
settings.fastForEach { setting ->
|
||||
TangemPaySettingButton(
|
||||
setting = setting,
|
||||
modifier = Modifier.then(if (setting.testTag != null) Modifier.testTag(setting.testTag) else Modifier),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemPaySettingButton(setting: TangemPayCardPageSettingV2, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.padding(horizontal = TangemTheme.dimens2.x6),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
TangemButton(
|
||||
variant = TangemButton.Variant.Material,
|
||||
size = TangemButton.Size.X14,
|
||||
onClick = setting.onClick,
|
||||
iconStart = TangemIconUM.Icon(
|
||||
iconRes = setting.iconRes,
|
||||
tintReference = { TangemTheme.colors3.icon.primary },
|
||||
),
|
||||
isLoading = setting.isLoading,
|
||||
isEnabled = setting.isEnabled,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = setting.title.resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography3.subheading.medium,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TangemPayCardPageSettingsButtonsBlockPreview() {
|
||||
TangemThemePreviewRedesign {
|
||||
TangemPayCardPageSettingsButtonsBlock(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors3.bg.secondary),
|
||||
settings = TangemPayCardPageSettingV2.stubList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, name = "Frozen card")
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Frozen card — dark")
|
||||
@Composable
|
||||
private fun TangemPayCardPageSettingsButtonsBlockFrozenPreview() {
|
||||
TangemThemePreviewRedesign {
|
||||
TangemPayCardPageSettingsButtonsBlock(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TangemTheme.colors3.bg.secondary),
|
||||
settings = TangemPayCardPageSettingV2.stubList(isFrozen = true),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import android.content.res.Configuration
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -11,7 +12,11 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -19,15 +24,31 @@ import com.tangem.core.ui.components.*
|
|||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.ds.row.TangemRowContainer
|
||||
import com.tangem.core.ui.ds.row.TangemRowLayoutId
|
||||
import com.tangem.core.ui.ds2.button.TangemButton
|
||||
import com.tangem.core.ui.ds2.shimmers.TextShimmer
|
||||
import com.tangem.core.ui.ds2.shimmers.TextShimmerStyle
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayDailyLimitBlockState
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayDailyLimitBlock(state: TangemPayDailyLimitBlockState, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
CurrentLimitBlockV2(state, modifier)
|
||||
} else {
|
||||
TangemPayDailyLimitBlockV1(state, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TangemPayDailyLimitBlockV1(state: TangemPayDailyLimitBlockState, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -43,12 +64,12 @@ internal fun TangemPayDailyLimitBlock(state: TangemPayDailyLimitBlockState, modi
|
|||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
SpacerH4()
|
||||
CurrentLimitBlock(state)
|
||||
CurrentLimitBlockV1(state)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CurrentLimitBlock(state: TangemPayDailyLimitBlockState) {
|
||||
private fun CurrentLimitBlockV1(state: TangemPayDailyLimitBlockState) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
|
@ -107,8 +128,147 @@ private fun CurrentLimitBlock(state: TangemPayDailyLimitBlockState) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CurrentLimitBlockV2(state: TangemPayDailyLimitBlockState, modifier: Modifier = Modifier) {
|
||||
TangemRowContainer(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens2.x6))
|
||||
.background(color = TangemTheme.colors3.bg.secondary),
|
||||
contentPadding = PaddingValues(TangemTheme.dimens2.x4),
|
||||
) {
|
||||
LimitHeadIcon(
|
||||
modifier = Modifier.layoutId(TangemRowLayoutId.HEAD),
|
||||
state = state,
|
||||
)
|
||||
|
||||
TitleLimit(
|
||||
modifier = Modifier
|
||||
.padding(start = TangemTheme.dimens2.x3)
|
||||
.layoutId(TangemRowLayoutId.START_TOP),
|
||||
state = state,
|
||||
)
|
||||
|
||||
SubtitleLimit(
|
||||
modifier = Modifier
|
||||
.padding(start = TangemTheme.dimens2.x3)
|
||||
.layoutId(TangemRowLayoutId.START_BOTTOM),
|
||||
state = state,
|
||||
)
|
||||
|
||||
if (state is TangemPayDailyLimitBlockState.Content) {
|
||||
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
|
||||
TangemButton(
|
||||
modifier = Modifier
|
||||
.padding(start = TangemTheme.dimens2.x3)
|
||||
.layoutId(TangemRowLayoutId.TAIL),
|
||||
variant = TangemButton.Variant.Secondary,
|
||||
text = resourceReference(R.string.common_edit),
|
||||
onClick = state.onChangeClick,
|
||||
size = TangemButton.Size.X10,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LimitHeadIcon(state: TangemPayDailyLimitBlockState, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(TangemTheme.dimens2.x10)
|
||||
.background(
|
||||
color = when (state) {
|
||||
is TangemPayDailyLimitBlockState.Content,
|
||||
TangemPayDailyLimitBlockState.Loading,
|
||||
-> TangemTheme.colors3.bg.status.infoSubtle
|
||||
TangemPayDailyLimitBlockState.Error -> TangemTheme.colors3.bg.status.warningSubtle
|
||||
},
|
||||
shape = CircleShape,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
when (state) {
|
||||
is TangemPayDailyLimitBlockState.Content,
|
||||
TangemPayDailyLimitBlockState.Loading,
|
||||
-> {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_limit_new_20),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.brand,
|
||||
)
|
||||
}
|
||||
TangemPayDailyLimitBlockState.Error -> {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_warning_20),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors3.icon.status.warning,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TitleLimit(state: TangemPayDailyLimitBlockState, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
is TangemPayDailyLimitBlockState.Content,
|
||||
TangemPayDailyLimitBlockState.Loading,
|
||||
-> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(R.string.tangempay_card_page_daily_limit_title),
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
)
|
||||
}
|
||||
TangemPayDailyLimitBlockState.Error -> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(R.string.tangempay_card_page_daily_limit_error_title),
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SubtitleLimit(state: TangemPayDailyLimitBlockState, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
TangemPayDailyLimitBlockState.Error -> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(R.string.tangempay_card_page_daily_limit_error_subtitle),
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
is TangemPayDailyLimitBlockState.Content -> {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = state.limit,
|
||||
style = TangemTheme.typography3.body.medium,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
TangemPayDailyLimitBlockState.Loading -> {
|
||||
TextShimmer(
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
modifier = modifier,
|
||||
style = TextShimmerStyle.BODY,
|
||||
text = "$50,000",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayDailyLimitErrorBlock(modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) return
|
||||
Notification(
|
||||
config = NotificationConfig(
|
||||
title = resourceReference(R.string.tangempay_card_page_daily_limit_error_title),
|
||||
|
|
@ -123,13 +283,33 @@ internal fun TangemPayDailyLimitErrorBlock(modifier: Modifier = Modifier) {
|
|||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun preview() = TangemThemePreview {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Content.stub())
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Error)
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Loading)
|
||||
TangemPayDailyLimitErrorBlock()
|
||||
private fun Preview() {
|
||||
TangemThemePreview {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Content.stub())
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Error)
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Loading)
|
||||
TangemPayDailyLimitErrorBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewV2() {
|
||||
TangemThemePreviewRedesign {
|
||||
CompositionLocalProvider(LocalRedesignEnabled provides true) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Content.stub())
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Error)
|
||||
TangemPayDailyLimitBlock(state = TangemPayDailyLimitBlockState.Loading)
|
||||
TangemPayDailyLimitErrorBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -457,7 +457,11 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
|||
),
|
||||
isBalanceHidden = false,
|
||||
addFundsEnabled = true,
|
||||
addToWalletBlockState = AddToWalletBlockState(onClick = {}, onClickClose = {}),
|
||||
addToWalletBlockState = AddToWalletBlockState(
|
||||
onClick = {},
|
||||
onClickClose = {},
|
||||
shouldUseMagicEffect = false,
|
||||
),
|
||||
accountDeactivatedNotificationConfig = null,
|
||||
),
|
||||
TangemPayDetailsUM(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue