From 93b59bf9fa5c84e79f19210ccd8e3936ab639568 Mon Sep 17 00:00:00 2001 From: polstianka Date: Thu, 16 May 2024 17:04:07 -0400 Subject: [PATCH 01/14] bug fixeds --- apps/signer/build.gradle.kts | 7 +- apps/signer/src/main/AndroidManifest.xml | 8 +- .../signer/src/main/ic_launcher-playstore.png | Bin 11006 -> 24708 bytes .../signer/core/repository/KeyRepository.kt | 18 +- .../com/tonapps/signer/deeplink/TKDeepLink.kt | 10 +- .../com/tonapps/signer/password/Password.kt | 6 +- .../signer/screen/camera/CameraFragment.kt | 7 +- .../signer/screen/create/CreateFragment.kt | 4 +- .../signer/screen/create/CreateViewModel.kt | 64 +- .../screen/create/child/CreateNameFragment.kt | 22 +- .../create/child/CreatePasswordFragment.kt | 6 + .../tonapps/signer/screen/key/KeyFragment.kt | 5 +- .../signer/screen/legal/LegalFragment.kt | 31 + .../signer/screen/root/RootActivity.kt | 28 +- .../signer/screen/root/RootViewModel.kt | 22 +- .../screen/settings/SettingsFragment.kt | 11 +- .../signer/screen/sign/SignFragment.kt | 2 +- .../signer/screen/sign/SignViewModel.kt | 4 +- .../drawable-v24/ic_launcher_foreground.xml | 84 +++ .../signer/src/main/res/drawable/bg_intro.xml | 131 ++-- .../src/main/res/drawable/bg_splash.xml | 6 +- .../signer/src/main/res/drawable/bg_wrong.xml | 6 + .../ic_exclamationmark_triangle_28.xml | 20 + .../res/drawable/ic_launcher_background.xml | 14 + .../res/drawable/ic_launcher_foreground.xml | 15 - .../src/main/res/layout/fragment_add_key.xml | 2 +- .../src/main/res/layout/fragment_camera.xml | 9 +- .../res/layout/fragment_camera_permission.xml | 3 +- .../res/layout/fragment_create_phrase.xml | 28 + .../src/main/res/layout/fragment_intro.xml | 19 +- .../src/main/res/layout/fragment_legal.xml | 48 ++ .../src/main/res/layout/fragment_settings.xml | 11 +- .../src/main/res/layout/fragment_sign.xml | 5 +- .../main/res/layout/view_message_action.xml | 1 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 2 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 908 -> 2016 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 2318 -> 3332 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 696 -> 1382 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 1454 -> 2230 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 1256 -> 2568 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 3252 -> 4656 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 1860 -> 3730 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 5256 -> 6930 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 2414 -> 5112 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 7396 -> 9808 bytes .../signer/src/main/res/values-ru/strings.xml | 54 +- apps/signer/src/main/res/values/strings.xml | 18 +- .../src/main/res/xml/locales_config.xml | 5 + .../main/java/com/tonapps/wallet/api/API.kt | 58 +- .../wallet/api/entity/BalanceEntity.kt | 2 +- .../tonapps/wallet/api/entity}/ChartEntity.kt | 8 +- .../tonapps/wallet/api/entity/TokenEntity.kt | 5 +- .../wallet/api/internal/ConfigRepository.kt | 6 +- .../wallet/api/internal/InternalApi.kt | 29 +- .../wallet/data/account/WalletRepository.kt | 22 +- .../data/account/entities/WalletEntity.kt | 12 +- .../data/account/entities/WalletLabel.kt | 7 +- .../wallet/data/browser/BrowserRepository.kt | 13 +- .../data/browser/source/RemoteDataSource.kt | 8 +- .../data/collectibles/entities/NftEntity.kt | 9 +- .../com/tonapps/wallet/data/core/Theme.kt | 31 + .../wallet/data/events/EventsRepository.kt | 31 + .../data/events/entities/ActionEntity.kt | 4 +- .../data/events/source/RemoteDataSource.kt | 2 +- .../tonapps/wallet/data/push/PushManager.kt | 84 +-- .../wallet/data/rates/entity/RatesEntity.kt | 4 + .../data/settings/SettingsRepository.kt | 24 +- .../wallet/data/token/TokenRepository.kt | 8 +- .../data/token/entities/AccountTokenEntity.kt | 2 +- .../data/tonconnect/TonConnectRepository.kt | 19 +- .../data/tonconnect/source/LocalDataSource.kt | 70 +- apps/wallet/instance/build.gradle.kts | 7 +- .../instance/src/main/AndroidManifest.xml | 19 +- .../main/java/com/tonapps/tonkeeper/App.kt | 12 +- .../java/com/tonapps/tonkeeper/AppDatabase.kt | 59 -- .../com/tonapps/tonkeeper/api/Extensions.kt | 7 +- .../api/account/AccountRepository.kt | 70 -- .../tonkeeper/api/account/db/AccountDao.kt | 34 - .../tonkeeper/api/account/db/AccountEntity.kt | 10 - .../api/base/BaseAccountRepository.kt | 99 --- .../tonkeeper/api/chart/ChartHelper.kt | 30 - .../tonkeeper/api/jetton/JettonRepository.kt | 89 --- .../tonkeeper/api/jetton/db/JettonDao.kt | 34 - .../tonkeeper/api/jetton/db/JettonEntity.kt | 50 -- .../tonkeeper/api/rates/RatesRepository.kt | 90 --- .../tonkeeper/core/history/HistoryHelper.kt | 39 +- .../core/history/list/HistoryAdapter.kt | 27 +- .../list/holder/HistoryActionHolder.kt | 84 ++- .../core/history/list/item/HistoryItem.kt | 28 +- .../core/tonconnect/models/TCData.kt | 2 +- .../tonkeeper/dialog/TransactionDialog.kt | 20 +- .../tonkeeper/dialog/fiat/FiatDialog.kt | 4 +- .../tonapps/tonkeeper/extensions/Context.kt | 2 +- .../tonkeeper/extensions/FragmentManager.kt | 11 + .../tonapps/tonkeeper/extensions/Wallet.kt | 2 +- .../tonkeeper/fragment/chart/ChartScreen.kt | 91 --- .../fragment/chart/ChartScreenEffect.kt | 5 - .../fragment/chart/ChartScreenFeature.kt | 148 ----- .../fragment/chart/ChartScreenState.kt | 42 -- .../fragment/chart/list/ChartAdapter.kt | 28 - .../fragment/chart/list/ChartItem.kt | 47 -- .../chart/list/ChartItemDecoration.kt | 32 - .../chart/list/holder/ChartActionsHolder.kt | 52 -- .../chart/list/holder/ChartDividerHolder.kt | 14 - .../chart/list/holder/ChartHeaderHolder.kt | 19 - .../fragment/chart/list/holder/ChartHolder.kt | 10 - .../chart/list/holder/ChartLineHolder.kt | 19 - .../chart/list/holder/ChartPeriodHolder.kt | 24 - .../chart/list/holder/ChartPriceHolder.kt | 22 - .../fragment/country/CountryScreenFeature.kt | 9 +- .../fragment/country/CountryScreenState.kt | 2 +- .../fragment/fiat/modal/FiatModalFragment.kt | 3 +- .../fragment/fiat/web/FiatWebFragment.kt | 4 +- .../tonkeeper/fragment/jetton/JettonScreen.kt | 110 ---- .../fragment/jetton/JettonScreenEffect.kt | 5 - .../fragment/jetton/JettonScreenFeature.kt | 126 ---- .../fragment/jetton/JettonScreenState.kt | 43 -- .../fragment/jetton/list/JettonAdapter.kt | 18 - .../fragment/jetton/list/JettonItem.kt | 31 - .../jetton/list/JettonItemDecoration.kt | 30 - .../jetton/list/holder/JettonActionsHolder.kt | 39 -- .../jetton/list/holder/JettonDividerHolder.kt | 14 - .../jetton/list/holder/JettonHeaderHolder.kt | 26 - .../jetton/list/holder/JettonHolder.kt | 10 - .../fragment/send/SendScreenFeature.kt | 7 + .../fragment/send/TransactionData.kt | 1 + .../fragment/send/amount/AmountScreen.kt | 27 +- .../send/amount/AmountScreenFeature.kt | 33 +- .../fragment/send/amount/AmountScreenState.kt | 6 +- .../fragment/send/confirm/ConfirmScreen.kt | 15 + .../send/confirm/ConfirmScreenFeature.kt | 7 +- .../fragment/send/popup/SelectTokenPopup.kt | 3 - .../send/recipient/RecipientScreen.kt | 41 +- .../fragment/send/view/AmountInput.kt | 79 ++- .../tonkeeper/fragment/space/SpaceActivity.kt | 13 - .../tonapps/tonkeeper/helper/DateHelper.kt | 16 +- .../tonkeeper/helper/ShortcutHelper.kt | 63 ++ .../com/tonapps/tonkeeper/koin/Extension.kt | 8 + .../com/tonapps/tonkeeper/koin/KoinModule.kt | 31 +- .../tonkeeper/password/PasscodeDataStore.kt | 8 + .../tonkeeper/password/PasscodeRepository.kt | 2 + .../ui/component/MainRecyclerView.kt | 5 +- .../tonkeeper/ui/component/PasscodeView.kt | 17 + .../ui/component/wallet/WalletHeaderView.kt | 2 +- .../connected/BrowserConnectedScreen.kt | 17 +- .../ui/screen/browser/dapp/DAppScreen.kt | 61 +- .../ui/screen/browser/dapp/DAppViewModel.kt | 30 +- .../browser/explore/BrowserExploreScreen.kt | 38 ++ .../explore/BrowserExploreViewModel.kt | 6 +- .../browser/search/BrowserSearchViewModel.kt | 2 +- .../screen/collectibles/CollectiblesScreen.kt | 2 +- .../collectibles/CollectiblesViewModel.kt | 32 +- .../ui/screen/collectibles/list/Item.kt | 13 +- .../collectibles/list/holder/NftHolder.kt | 34 +- .../tonkeeper/ui/screen/dialog/DeleteMe.kt | 2 + .../dialog/encrypted/EncryptedCommentArgs.kt | 25 + .../encrypted/EncryptedCommentScreen.kt | 48 ++ .../encrypted/EncryptedCommentViewModel.kt | 100 +++ .../ui/screen/events/EventsScreen.kt | 1 - .../ui/screen/events/EventsViewModel.kt | 46 +- .../tonkeeper/ui/screen/init/InitScreen.kt | 2 - .../tonkeeper/ui/screen/init/InitViewModel.kt | 40 +- .../tonkeeper/ui/screen/main/MainScreen.kt | 30 +- .../ui/screen/name/base/NameViewModel.kt | 2 +- .../tonkeeper/ui/screen/nft/NftScreen.kt | 23 +- .../notifications/NotificationsScreen.kt | 35 + .../notifications/NotificationsViewModel.kt | 52 ++ .../ui/screen/notifications/list/Adapter.kt | 23 + .../ui/screen/notifications/list/Item.kt | 48 ++ .../list/NotificationsAdapter.kt | 4 + .../notifications/list/holder/AppHolder.kt | 37 ++ .../list/holder/AppsHeaderHolder.kt | 13 + .../notifications/list/holder/Holder.kt | 11 + .../notifications/list/holder/SpaceHolder.kt | 11 + .../list/holder/WalletPushHolder.kt | 28 + .../ui/screen/phrase/PhraseScreen.kt | 12 +- .../tonkeeper/ui/screen/picker/list/Holder.kt | 7 +- .../tonkeeper/ui/screen/picker/list/Item.kt | 3 +- .../screen/picker/list/WalletPickerAdapter.kt | 4 +- .../tonkeeper/ui/screen/qr/QRScreen.kt | 21 +- .../tonkeeper/ui/screen/root/RootActivity.kt | 9 +- .../tonkeeper/ui/screen/root/RootViewModel.kt | 97 ++- .../ui/screen/settings/main/SettingsScreen.kt | 14 + .../screen/settings/main/SettingsViewModel.kt | 2 + .../ui/screen/settings/main/list/Item.kt | 20 +- .../passcode/ChangePasscodeModelState.kt | 24 + .../settings/passcode/ChangePasscodeScreen.kt | 72 +++ .../passcode/ChangePasscodeViewModel.kt | 88 +++ .../settings/security/SecurityScreen.kt | 25 +- .../ui/screen/settings/theme/ThemeScreen.kt | 44 +- .../screen/settings/theme/ThemeViewModel.kt | 33 +- .../ui/screen/settings/theme/list/Adapter.kt | 15 + .../ui/screen/settings/theme/list/Holder.kt | 35 + .../ui/screen/settings/theme/list/Item.kt | 11 + .../tonkeeper/ui/screen/swap/SwapScreen.kt | 5 + .../tonkeeper/ui/screen/token/TokenArgs.kt | 29 + .../tonkeeper/ui/screen/token/TokenData.kt | 41 ++ .../tonkeeper/ui/screen/token/TokenScreen.kt | 65 ++ .../ui/screen/token/TokenViewModel.kt | 236 +++++++ .../tonkeeper/ui/screen/token/list/Item.kt | 43 ++ .../ui/screen/token/list/TokenAdapter.kt | 22 + .../screen/token/list/holder/ActionsHolder.kt | 34 + .../screen/token/list/holder/BalanceHolder.kt | 20 + .../screen/token/list/holder/ChartHolder.kt | 16 + .../ui/screen/token/list/holder/Holder.kt | 11 + .../screen/token/list/holder/PriceHolder.kt | 21 + .../ui/screen/wallet/WalletViewModel.kt | 19 +- .../tonkeeper/ui/screen/wallet/list/Item.kt | 8 +- .../screen/wallet/list/holder/TokenHolder.kt | 4 +- .../com/tonapps/tonkeeper/view/ChartView.kt | 2 +- .../tonkeeper/view/TransactionDetailView.kt | 8 +- .../src/main/res/drawable/bg_intro_blue.xml | 85 +++ .../src/main/res/drawable/ic_doc_28.xml | 25 - .../src/main/res/drawable/ic_logo_splash.xml | 604 ++++++++++++++++++ .../main/res/drawable/ic_send_shortcut.xml | 22 + .../res/layout/fragment_browser_connected.xml | 25 +- .../res/layout/fragment_change_passcode.xml | 16 + .../src/main/res/layout/fragment_dapp.xml | 7 +- .../res/layout/fragment_encrypted_comment.xml | 70 ++ .../src/main/res/layout/fragment_intro.xml | 4 +- .../src/main/res/layout/fragment_nft.xml | 52 +- .../res/layout/fragment_notifications.xml | 20 + .../src/main/res/layout/fragment_phrase.xml | 61 +- .../src/main/res/layout/fragment_security.xml | 18 +- .../res/layout/fragment_send_recipient.xml | 24 + .../src/main/res/layout/fragment_swap.xml | 11 +- .../src/main/res/layout/fragment_theme.xml | 21 +- .../main/res/layout/view_browser_title.xml | 3 +- .../src/main/res/layout/view_collectibles.xml | 25 +- .../main/res/layout/view_history_action.xml | 1 + .../res/layout/view_notifications_app.xml | 32 + .../layout/view_notifications_apps_header.xml | 20 + .../res/layout/view_notifications_wallet.xml | 37 ++ .../src/main/res/layout/view_passcode.xml | 1 + .../main/res/layout/view_token_actions.xml | 35 + .../main/res/layout/view_token_balance.xml | 41 ++ .../src/main/res/layout/view_token_chart.xml | 5 + .../src/main/res/layout/view_token_price.xml | 24 + .../res/layout/view_transaction_detail.xml | 1 + .../src/main/res/menu/bottom_tabs.xml | 2 +- .../instance/src/main/res/values/themes.xml | 13 + .../src/main/res/values-ru/strings.xml | 27 + .../src/main/res/values/strings.xml | 25 + buildSrc/src/main/kotlin/Dependence.kt | 16 +- .../main/java/com/tonapps/blockchain/Coin.kt | 11 +- .../tonapps/blockchain/ton/extensions/Cell.kt | 1 - .../src/main/java/com/tonapps/emoji/Emoji.kt | 4 + .../main/java/com/tonapps/extensions/Flow.kt | 4 + .../java/com/tonapps/icu/CurrencyFormatter.kt | 18 +- .../src/main/java/com/tonapps/qr/ui/QRView.kt | 5 + .../src/main/res/values/colors_light.xml | 84 +-- .../main/java/uikit/base/BaseListFragment.kt | 14 + .../main/java/uikit/drawable/InputDrawable.kt | 9 +- .../src/main/java/uikit/extensions/String.kt | 7 + .../src/main/java/uikit/extensions/View.kt | 12 + .../src/main/java/uikit/widget/HeaderView.kt | 4 +- .../src/main/java/uikit/widget/InputView.kt | 30 +- .../src/main/java/uikit/widget/PhraseWords.kt | 2 +- .../main/java/uikit/widget/PinInputView.kt | 6 +- .../main/java/uikit/widget/SlideActionView.kt | 2 +- .../main/java/uikit/widget/TextHeaderView.kt | 1 - .../src/main/java/uikit/widget/ToastView.kt | 5 +- .../java/uikit/widget/item/BaseItemView.kt | 2 +- .../widget/webview/bridge/BridgeWebView.kt | 12 +- .../button_primary_foreground_selector.xml | 3 +- .../src/main/res/values/textappearance.xml | 2 - ui/uikit/core/src/main/res/values/themes.xml | 1 + .../icon/src/main/res/drawable/ic_bell_16.xml | 10 + .../main/res/drawable/ic_bell_disable_16.xml | 10 + .../icon/src/main/res/drawable/ic_copy_16.xml | 14 + .../main/res/drawable/ic_disconnect_16.xml | 10 + .../icon/src/main/res/drawable/ic_doc_28.xml | 25 + .../src/main/res/drawable/ic_lock_128.xml | 16 + .../icon/src/main/res/drawable/ic_lock_16.xml | 10 + .../main/res/drawable/ic_notifications_28.xml | 14 + .../src/main/res/drawable/ic_refresh_16.xml | 10 + .../main/res/drawable/ic_sale_badge_16.xml | 10 + .../src/main/res/drawable/ic_share_16.xml | 12 + .../icon/src/main/res/drawable/ic_star_28.xml | 9 + .../main/res/drawable/ic_verification_16.xml | 14 + 281 files changed, 4609 insertions(+), 2535 deletions(-) create mode 100644 apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt create mode 100644 apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 apps/signer/src/main/res/drawable/bg_wrong.xml create mode 100644 apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml create mode 100644 apps/signer/src/main/res/drawable/ic_launcher_background.xml delete mode 100644 apps/signer/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 apps/signer/src/main/res/layout/fragment_legal.xml create mode 100644 apps/signer/src/main/res/xml/locales_config.xml rename apps/wallet/{instance/src/main/java/com/tonapps/tonkeeper/api/chart => api/src/main/java/com/tonapps/wallet/api/entity}/ChartEntity.kt (53%) create mode 100644 apps/wallet/data/core/src/main/java/com/tonapps/wallet/data/core/Theme.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/AppDatabase.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/account/AccountRepository.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/account/db/AccountDao.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/account/db/AccountEntity.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/base/BaseAccountRepository.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/chart/ChartHelper.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/jetton/JettonRepository.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/jetton/db/JettonDao.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/jetton/db/JettonEntity.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/api/rates/RatesRepository.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/extensions/FragmentManager.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/ChartScreen.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/ChartScreenEffect.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/ChartScreenFeature.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/ChartScreenState.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/ChartAdapter.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/ChartItem.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/ChartItemDecoration.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartActionsHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartDividerHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartHeaderHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartLineHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartPeriodHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/chart/list/holder/ChartPriceHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/JettonScreen.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/JettonScreenEffect.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/JettonScreenFeature.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/JettonScreenState.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/JettonAdapter.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/JettonItem.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/JettonItemDecoration.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/holder/JettonActionsHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/holder/JettonDividerHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/holder/JettonHeaderHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/jetton/list/holder/JettonHolder.kt delete mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/fragment/space/SpaceActivity.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/helper/ShortcutHelper.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/dialog/DeleteMe.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/dialog/encrypted/EncryptedCommentArgs.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/dialog/encrypted/EncryptedCommentScreen.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/dialog/encrypted/EncryptedCommentViewModel.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/NotificationsScreen.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/NotificationsViewModel.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/Adapter.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/Item.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/NotificationsAdapter.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/holder/AppHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/holder/AppsHeaderHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/holder/Holder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/holder/SpaceHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/notifications/list/holder/WalletPushHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/passcode/ChangePasscodeModelState.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/passcode/ChangePasscodeScreen.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/passcode/ChangePasscodeViewModel.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/theme/list/Adapter.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/theme/list/Holder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/settings/theme/list/Item.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/TokenArgs.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/TokenData.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/TokenScreen.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/TokenViewModel.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/Item.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/TokenAdapter.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/holder/ActionsHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/holder/BalanceHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/holder/ChartHolder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/holder/Holder.kt create mode 100644 apps/wallet/instance/src/main/java/com/tonapps/tonkeeper/ui/screen/token/list/holder/PriceHolder.kt create mode 100644 apps/wallet/instance/src/main/res/drawable/bg_intro_blue.xml delete mode 100644 apps/wallet/instance/src/main/res/drawable/ic_doc_28.xml create mode 100644 apps/wallet/instance/src/main/res/drawable/ic_logo_splash.xml create mode 100644 apps/wallet/instance/src/main/res/drawable/ic_send_shortcut.xml create mode 100644 apps/wallet/instance/src/main/res/layout/fragment_change_passcode.xml create mode 100644 apps/wallet/instance/src/main/res/layout/fragment_encrypted_comment.xml create mode 100644 apps/wallet/instance/src/main/res/layout/fragment_notifications.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_notifications_app.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_notifications_apps_header.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_notifications_wallet.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_token_actions.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_token_balance.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_token_chart.xml create mode 100644 apps/wallet/instance/src/main/res/layout/view_token_price.xml create mode 100644 apps/wallet/instance/src/main/res/values/themes.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_bell_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_bell_disable_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_copy_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_disconnect_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_doc_28.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_lock_128.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_lock_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_notifications_28.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_refresh_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_sale_badge_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_share_16.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_star_28.xml create mode 100644 ui/uikit/icon/src/main/res/drawable/ic_verification_16.xml diff --git a/apps/signer/build.gradle.kts b/apps/signer/build.gradle.kts index a12e3e680..fed26c3ee 100644 --- a/apps/signer/build.gradle.kts +++ b/apps/signer/build.gradle.kts @@ -9,11 +9,11 @@ android { compileSdk = Build.compileSdkVersion defaultConfig { - applicationId = "com.tonapps.signer" + applicationId = Build.namespacePrefix("signer") minSdk = Build.minSdkVersion targetSdk = 34 - versionCode = 8 - versionName = "0.0.8" + versionCode = 10 + versionName = "0.1.0" } lint { @@ -68,6 +68,7 @@ dependencies { implementation(Dependence.AndroidX.fragment) implementation(Dependence.AndroidX.recyclerView) implementation(Dependence.AndroidX.viewPager2) + implementation(Dependence.AndroidX.splashscreen) implementation(Dependence.UI.material) implementation(Dependence.AndroidX.Camera.base) diff --git a/apps/signer/src/main/AndroidManifest.xml b/apps/signer/src/main/AndroidManifest.xml index b69d17758..42c19eb6a 100644 --- a/apps/signer/src/main/AndroidManifest.xml +++ b/apps/signer/src/main/AndroidManifest.xml @@ -34,10 +34,11 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" + android:supportsRtl="false" android:theme="@style/Theme.Signer.Starting" android:hardwareAccelerated="true" - android:largeHeap="true"> + android:largeHeap="true" + android:localeConfig="@xml/locales_config"> @@ -64,7 +64,7 @@ diff --git a/apps/signer/src/main/ic_launcher-playstore.png b/apps/signer/src/main/ic_launcher-playstore.png index 75977e3a368555d3fcfb471fa2adc6a250a8d255..76640c8a17b4a99e3178247d647aa12e5a8e6d32 100644 GIT binary patch literal 24708 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 L(ama&+mHSa%rgtB diff --git a/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt b/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt index 02b05a203..50842f51d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/core/repository/KeyRepository.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.ton.api.pub.PublicKeyEd25519 +import org.ton.crypto.hex class KeyRepository( private val dataSource: KeyDataSource, @@ -27,6 +28,12 @@ class KeyRepository( init { Scope.repositories.launch(Dispatchers.IO) { + /*val testKey = KeyEntity( + id = 1, + name = "Test", + publicKey = PublicKeyEd25519(hex("db642e022c80911fe61f19eb4f22d7fb95c1ea0b589c0f74ecf0cbf6db746c13")) + ) + _keysEntityFlow.value = listOf(testKey)*/ _keysEntityFlow.value = dataSource.getEntities() } } @@ -43,10 +50,13 @@ class KeyRepository( _keysEntityFlow.value?.size ?: 0 } - fun findIdByPublicKey(publicKey: PublicKeyEd25519): Flow = flow { - val id = dataSource.findIdByPublicKey(publicKey) - emit(id) - }.filterNotNull() + fun findIdByPublicKey(publicKey: PublicKeyEd25519): Long? { + val id = dataSource.findIdByPublicKey(publicKey) ?: return null + if (0 >= id) { + return null + } + return id + } suspend fun setName(id: Long, name: String) = withContext(Dispatchers.IO) { dataSource.setName(id, name) diff --git a/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt b/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt index c232599bc..a882cd53b 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/deeplink/TKDeepLink.kt @@ -19,11 +19,18 @@ object TKDeepLink { return builder.build() } - fun buildLinkUri(publicKey: PublicKeyEd25519, name: String): Uri { + fun buildLinkUri( + publicKey: PublicKeyEd25519, + name: String, + local: Boolean + ): Uri { val baseUri = Uri.parse("${APP_SCHEME}://signer/link") val builder = baseUri.buildUpon() builder.appendQueryParameter("pk", publicKey.base64()) builder.appendQueryParameter("name", name) + if (local) { + builder.appendQueryParameter("local", "true") + } return builder.build() } @@ -32,6 +39,7 @@ object TKDeepLink { val builder = baseUri.buildUpon() builder.appendQueryParameter("pk", publicKey.base64()) builder.appendQueryParameter("name", name) + builder.appendQueryParameter("local", "true") return builder.build() } diff --git a/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt b/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt index 0048c450b..df7e74f4d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/password/Password.kt @@ -40,7 +40,7 @@ object Password { val dialog = PasswordDialog(context, ::trySend) dialog.setOnDismissListener { if (isActive) { - close(Throwable("User canceled")) + close(UserCancelThrowable ) } else { close() } @@ -48,4 +48,8 @@ object Password { dialog.show() awaitClose { dialog.destroy() } }.flowOn(Dispatchers.Main).take(1) + + object UserCancelThrowable : Throwable("User canceled") { + private fun readResolve(): Any = UserCancelThrowable + } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt index b891b8cfc..543db65bb 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/camera/CameraFragment.kt @@ -48,6 +48,7 @@ class CameraFragment: BaseFragment(R.layout.fragment_camera), BaseFragment.Botto } private var isFlashAvailable = false + private var isReady = false private val qrAnalyzer = QRImageAnalyzer() private val chunks = mutableListOf() @@ -95,6 +96,9 @@ class CameraFragment: BaseFragment(R.layout.fragment_camera), BaseFragment.Botto } private fun handleBarcode(barcode: Barcode) { + if (isReady) { + return + } val data = barcode.rawValue ?: return if (data.startsWith("${Key.SCHEME}://")) { @@ -108,12 +112,13 @@ class CameraFragment: BaseFragment(R.layout.fragment_camera), BaseFragment.Botto val uri = chunks.joinToString("").uriOrNull ?: return if (rootViewModel.processDeepLink(uri, false)) { + isReady = true finishDelay() } } private fun finishDelay() { - postDelayed(ModalView.animationDuration) { + postDelayed(300) { finish() } } diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt index 4ca16f44d..21ec4a3ee 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateFragment.kt @@ -2,6 +2,7 @@ package com.tonapps.signer.screen.create import android.graphics.Color import android.os.Bundle +import android.util.Log import android.view.View import androidx.core.view.doOnLayout import androidx.lifecycle.lifecycleScope @@ -53,6 +54,7 @@ class CreateFragment: BaseFragment(R.layout.fragment_create), BaseFragment.Swipe adapter = PagerAdapter(this, createViewModel.pages) pagerView = view.findViewById(R.id.pager) + pagerView.offscreenPageLimit = adapter.itemCount pagerView.isUserInputEnabled = false pagerView.adapter = adapter @@ -65,7 +67,7 @@ class CreateFragment: BaseFragment(R.layout.fragment_create), BaseFragment.Swipe private fun setPage(index: Int) { val currentIndex = pagerView.currentItem if (currentIndex != index) { - pagerView.setCurrentItem(index, true) + post { pagerView.setCurrentItem(index, true) } } } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt index eac9a59b6..b02e24a47 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/CreateViewModel.kt @@ -29,6 +29,10 @@ import kotlinx.coroutines.launch import org.ton.api.pk.PrivateKeyEd25519 import org.ton.mnemonic.Mnemonic import com.tonapps.security.tryCallGC +import com.tonapps.signer.extensions.authorizationRequiredError +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.withContext import javax.crypto.SecretKey class CreateViewModel( @@ -54,15 +58,19 @@ class CreateViewModel( add(PageType.Name) } - private val _onReady = Channel(Channel.BUFFERED) - val onReady: Flow = _onReady.receiveAsFlow() + private val _onReady = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + val onReady: Flow = _onReady.asSharedFlow() - private val _currentPage = MutableStateFlow(pages.first()) + private val _currentPage = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) val currentPage = _currentPage.asSharedFlow() private val _uiTopOffset = MutableStateFlow(0) val uiTopOffset = _uiTopOffset.asStateFlow() + init { + _currentPage.tryEmit(pages.first()) + } + fun pageIndex() = currentPage.map { pageIndex(it) } fun page(pageType: PageType) = currentPage.filter { it == pageType } @@ -98,22 +106,27 @@ class CreateViewModel( return true } - fun addKey(context: Context) { - viewModelScope.launch(Dispatchers.IO) { - try { - val name = args.name ?: throw IllegalStateException("Name is null") - val secret = masterSecret(context).single() - Password.setUnlock() - - if (import) { - val mnemonic = args.mnemonic ?: throw IllegalStateException("Mnemonic is null") - addNewKey(secret, name, mnemonic) - } else { - createNewKey(secret, name) - } - - _onReady.trySend(Unit) - } catch (e: Throwable) { + fun addKey(context: Context) = flow { + try { + val name = args.name ?: throw IllegalStateException("Name is null") + val secret = masterSecret(context).single() + Password.setUnlock() + + if (import) { + val mnemonic = args.mnemonic ?: throw IllegalStateException("Mnemonic is null") + addNewKey(secret, name, mnemonic) + } else { + createNewKey(secret, name) + } + + emit(true) + _onReady.tryEmit(Unit) + + } catch (e: Throwable) { + emit(false) + if (e is Password.UserCancelThrowable) { + context.authorizationRequiredError() + } else { CrashActivity.open(e, context) _currentPage.tryEmit(pages.first()) } @@ -131,14 +144,21 @@ class CreateViewModel( private fun createMasterSecret(password: CharArray) = flow { emit(vault.createMasterSecret(password)) - }.take(1) + }.take(1).flowOn(Dispatchers.IO) - private suspend fun createNewKey(secret: SecretKey, name: String) { + private suspend fun createNewKey( + secret: SecretKey, + name: String + ) = withContext(Dispatchers.IO) { val mnemonic = Mnemonic.generate() addNewKey(secret, name, mnemonic) } - private suspend fun addNewKey(secret: SecretKey, name: String, mnemonic: List) { + private suspend fun addNewKey( + secret: SecretKey, + name: String, + mnemonic: List + ) = withContext(Dispatchers.IO) { val seed = Mnemonic.toSeed(mnemonic) val publicKey = PrivateKeyEd25519(seed).publicKey() diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt index 598936d01..d592e7e6d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreateNameFragment.kt @@ -1,12 +1,15 @@ package com.tonapps.signer.screen.create.child import android.os.Bundle +import android.util.Log import android.view.View import android.widget.Button import androidx.lifecycle.lifecycleScope import com.tonapps.signer.R +import com.tonapps.signer.extensions.authorizationRequiredError import com.tonapps.signer.screen.create.CreateViewModel import com.tonapps.signer.screen.create.pager.PageType +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.koin.androidx.viewmodel.ext.android.getViewModel @@ -56,6 +59,10 @@ class CreateNameFragment: BaseFragment(R.layout.fragment_create_name) { nameInput.focus() } + collectFlow(createViewModel.page(PageType.RepeatPassword)) { + nameInput.clear() + } + collectFlow(createViewModel.uiTopOffset) { contentView.setPaddingTop(it) } @@ -66,12 +73,23 @@ class CreateNameFragment: BaseFragment(R.layout.fragment_create_name) { if (name.isBlank()) { return } - createViewModel.setName(name) - createViewModel.addKey(requireContext()) + collectFlow(createViewModel.addKey(requireContext())) { done -> + if (!done) { + applyDefaultState() + } + } + applyLoadingState() + } + private fun applyLoadingState() { loaderView.visibility = View.VISIBLE doneButton.visibility = View.GONE nameInput.hideKeyboard() } + + private fun applyDefaultState() { + loaderView.visibility = View.GONE + doneButton.visibility = View.VISIBLE + } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt index 903cd2d5b..525264925 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/create/child/CreatePasswordFragment.kt @@ -83,6 +83,12 @@ class CreatePasswordFragment : BaseFragment(R.layout.fragment_create_password) { passwordInput.focusWithKeyboard() } + if (isRepeat) { + collectFlow(createViewModel.page(PageType.Password)) { + passwordInput.clear() + } + } + collectFlow(createViewModel.uiTopOffset) { contentView.setPaddingTop(it) } diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt index 8655b52f1..89974c39d 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/key/KeyFragment.kt @@ -114,11 +114,10 @@ class KeyFragment: BaseFragment(R.layout.fragment_key), BaseFragment.SwipeBack { } private fun setExportByUri(publicKey: PublicKeyEd25519, name: String) { - val uri = TKDeepLink.buildLinkUri(publicKey, name) - qrView.setContent(uri.toString()) + qrView.setContent(TKDeepLink.buildLinkUri(publicKey, name, false).toString()) exportTonkeeperView.setOnClickListener { - TKDeepLink.openOrInstall(requireContext(), uri) + TKDeepLink.openOrInstall(requireContext(), TKDeepLink.buildLinkUri(publicKey, name, true)) } exportTonkeeperWebView.setOnClickListener { diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt new file mode 100644 index 000000000..6d50b4d02 --- /dev/null +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/legal/LegalFragment.kt @@ -0,0 +1,31 @@ +package com.tonapps.signer.screen.legal + +import android.os.Bundle +import android.view.View +import com.tonapps.signer.R +import uikit.base.BaseFragment +import uikit.navigation.Navigation.Companion.navigation +import uikit.widget.HeaderView + +class LegalFragment: BaseFragment(R.layout.fragment_legal), BaseFragment.SwipeBack { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val header = view.findViewById(R.id.header) + header.doOnCloseClick = { finish() } + + val termsView = view.findViewById(R.id.terms) + termsView.setOnClickListener { + navigation?.openURL("https://tonkeeper.com/terms", true) + } + + val privacyView = view.findViewById(R.id.privacy) + privacyView.setOnClickListener { + navigation?.openURL("https://tonkeeper.com/privacy", true) + } + } + + companion object { + fun newInstance() = LegalFragment() + } +} \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt index 75ea797b3..175092311 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootActivity.kt @@ -16,6 +16,7 @@ import com.tonapps.signer.SimpleState import com.tonapps.signer.extensions.toast import com.tonapps.signer.password.Password import com.tonapps.signer.password.ui.PasswordView +import com.tonapps.signer.screen.crash.CrashActivity import com.tonapps.signer.screen.intro.IntroFragment import com.tonapps.signer.screen.main.MainFragment import com.tonapps.signer.screen.root.action.RootAction @@ -138,12 +139,29 @@ class RootActivity: NavigationActivity() { private fun onAction(action: RootAction) { when (action) { - is RootAction.RequestBodySign -> add(SignFragment.newInstance(action.id, action.body, action.v, action.returnResult)) + is RootAction.RequestBodySign -> requestSign(action) is RootAction.ResponseBoc -> responseBoc(action.boc) is RootAction.ResponseKey -> responseKey(action.publicKey, action.name) } } + private fun requestSign(request: RootAction.RequestBodySign) { + removeSignSheets { + add(SignFragment.newInstance(request.id, request.body, request.v, request.returnResult)) + } + } + + private fun removeSignSheets(runnable: Runnable) { + val transaction = supportFragmentManager.beginTransaction() + supportFragmentManager.fragments.forEach { + if (it is SignFragment) { + transaction.remove(it) + } + } + transaction.runOnCommit(runnable) + transaction.commitNow() + } + private fun responseBoc(boc: String) { val intent = Intent() intent.putExtra(Key.BOC, boc) @@ -207,14 +225,18 @@ class RootActivity: NavigationActivity() { checkPasswordJob?.cancel() } - /*override fun onWindowFocusChanged(hasFocus: Boolean) { + override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) + if (BuildConfig.DEBUG) { + return + } + if (hasFocus) { baseContainer.visibility = View.VISIBLE } else { baseContainer.visibility = View.GONE } - }*/ + } override fun onResume() { super.onResume() diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt index b0a7ceb0a..85bbd2c82 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/root/RootViewModel.kt @@ -11,7 +11,10 @@ import com.tonapps.signer.password.Password import com.tonapps.signer.screen.root.action.RootAction import com.tonapps.signer.vault.SignerVault import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -22,6 +25,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch import org.ton.cell.Cell +import uikit.extensions.collectFlow class RootViewModel( private val vault: SignerVault, @@ -32,8 +36,8 @@ class RootViewModel( it.isNotEmpty() }.distinctUntilChanged() - private val _action = Channel(Channel.BUFFERED) - val action = _action.receiveAsFlow() + private val _action = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + val action = _action.asSharedFlow() fun checkPassword(password: CharArray) = flow { val valid = vault.isValidPassword(password) @@ -51,7 +55,7 @@ class RootViewModel( } fun responseSignedBoc(boc: String) { - _action.trySend(RootAction.ResponseBoc(boc)) + _action.tryEmit(RootAction.ResponseBoc(boc)) } fun processDeepLink(uri: Uri, fromApp: Boolean): Boolean { @@ -71,17 +75,13 @@ class RootViewModel( } private fun signRequest(signRequest: SignRequestEntity) { - keyRepository.findIdByPublicKey(signRequest.publicKey).onEach { id -> + viewModelScope.launch(Dispatchers.IO) { + val id = keyRepository.findIdByPublicKey(signRequest.publicKey) ?: return@launch sign(id, signRequest.body, signRequest.v, signRequest.returnResult) - }.launchIn(viewModelScope) + } } private fun sign(id: Long, body: Cell, v: String, returnResult: ReturnResultEntity) { - _action.trySend(RootAction.RequestBodySign(id, body, v, returnResult)) - } - - override fun onCleared() { - super.onCleared() - _action.close() + _action.tryEmit(RootAction.RequestBodySign(id, body, v, returnResult)) } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt index 2360b4ea7..655748ef2 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/settings/SettingsFragment.kt @@ -10,6 +10,7 @@ import com.tonapps.signer.BuildConfig import com.tonapps.signer.R import com.tonapps.signer.screen.change.ChangeFragment import com.tonapps.signer.screen.debug.DebugFragment +import com.tonapps.signer.screen.legal.LegalFragment import uikit.base.BaseFragment import uikit.navigation.Navigation.Companion.navigation import uikit.widget.HeaderView @@ -24,6 +25,7 @@ class SettingsFragment: BaseFragment(R.layout.fragment_settings), BaseFragment.S private lateinit var scrollView: NestedScrollView private lateinit var changeView: View private lateinit var supportView: View + private lateinit var legalView: View private lateinit var versionView: AppCompatTextView override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -39,6 +41,11 @@ class SettingsFragment: BaseFragment(R.layout.fragment_settings), BaseFragment.S supportView = view.findViewById(R.id.support) supportView.setOnClickListener { openSupport() } + legalView = view.findViewById(R.id.legal) + legalView.setOnClickListener { + navigation?.add(LegalFragment.newInstance()) + } + versionView = view.findViewById(R.id.version) versionView.text = getString(R.string.version, BuildConfig.VERSION_NAME) versionView.setOnClickListener { @@ -47,8 +54,8 @@ class SettingsFragment: BaseFragment(R.layout.fragment_settings), BaseFragment.S } private fun openSupport() { - val uri = Uri.parse("mailto:support@tonkeeper.com") - val intent = Intent(Intent.ACTION_SENDTO, uri) + val uri = Uri.parse("https://t.me/tonkeeper_supportbot") + val intent = Intent(Intent.ACTION_VIEW, uri) startActivity(intent) } } \ No newline at end of file diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt index 8f0e8e5d3..8abb4efbe 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignFragment.kt @@ -169,7 +169,7 @@ class SignFragment: BaseFragment(R.layout.fragment_sign), BaseFragment.Modal { } private fun finishDelay() { - postDelayed(ModalView.animationDuration) { + postDelayed(300) { finish() } } diff --git a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt index 0c09f0e12..ad2c66bdd 100644 --- a/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt +++ b/apps/signer/src/main/java/com/tonapps/signer/screen/sign/SignViewModel.kt @@ -48,9 +48,7 @@ class SignViewModel( private val vault: SignerVault, ): ViewModel() { - val keyEntity = repository.getKey(id) - .filterNotNull() - .shareIn(viewModelScope, SharingStarted.Lazily, 1) + val keyEntity = repository.getKey(id).filterNotNull() private val _actionsFlow = MutableStateFlow?>(null) val actionsFlow = _actionsFlow.asStateFlow().filterNotNull() diff --git a/apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml b/apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..448c3f743 --- /dev/null +++ b/apps/signer/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/signer/src/main/res/drawable/bg_intro.xml b/apps/signer/src/main/res/drawable/bg_intro.xml index 8d7802f60..b85517a7b 100644 --- a/apps/signer/src/main/res/drawable/bg_intro.xml +++ b/apps/signer/src/main/res/drawable/bg_intro.xml @@ -1,64 +1,79 @@ + android:width="200dp" + android:height="254dp" + android:viewportWidth="200" + android:viewportHeight="254"> - - - - - - - - - - - - - - - - - - - - - - - - - + android:pathData="m0,0.67h200v253.33h-200z"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/signer/src/main/res/drawable/bg_splash.xml b/apps/signer/src/main/res/drawable/bg_splash.xml index a2ac2d736..b5a0e99a2 100644 --- a/apps/signer/src/main/res/drawable/bg_splash.xml +++ b/apps/signer/src/main/res/drawable/bg_splash.xml @@ -1,8 +1,4 @@ - + \ No newline at end of file diff --git a/apps/signer/src/main/res/drawable/bg_wrong.xml b/apps/signer/src/main/res/drawable/bg_wrong.xml new file mode 100644 index 000000000..d1c0daf1f --- /dev/null +++ b/apps/signer/src/main/res/drawable/bg_wrong.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml b/apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml new file mode 100644 index 000000000..1b91ae97c --- /dev/null +++ b/apps/signer/src/main/res/drawable/ic_exclamationmark_triangle_28.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/signer/src/main/res/drawable/ic_launcher_background.xml b/apps/signer/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..cbccc117c --- /dev/null +++ b/apps/signer/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/apps/signer/src/main/res/drawable/ic_launcher_foreground.xml b/apps/signer/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index d329c683a..000000000 --- a/apps/signer/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/apps/signer/src/main/res/layout/fragment_add_key.xml b/apps/signer/src/main/res/layout/fragment_add_key.xml index 9f3b6387c..a7389302b 100644 --- a/apps/signer/src/main/res/layout/fragment_add_key.xml +++ b/apps/signer/src/main/res/layout/fragment_add_key.xml @@ -19,7 +19,7 @@ diff --git a/apps/signer/src/main/res/layout/fragment_camera.xml b/apps/signer/src/main/res/layout/fragment_camera.xml index 6773dff46..8ca8369e8 100644 --- a/apps/signer/src/main/res/layout/fragment_camera.xml +++ b/apps/signer/src/main/res/layout/fragment_camera.xml @@ -27,7 +27,7 @@ app:ignoreSystemOffset="true" android:icon="@drawable/ic_chevron_down_16"/> - + + - + diff --git a/apps/signer/src/main/res/layout/fragment_camera_permission.xml b/apps/signer/src/main/res/layout/fragment_camera_permission.xml index 9fa18b9a9..acc1e4b0a 100644 --- a/apps/signer/src/main/res/layout/fragment_camera_permission.xml +++ b/apps/signer/src/main/res/layout/fragment_camera_permission.xml @@ -23,7 +23,8 @@ android:layout_width="84dp" android:layout_height="84dp" android:layout_gravity="center" - android:src="@drawable/ic_camera_84"/> + android:src="@drawable/ic_camera_84" + android:tint="?attr/accentBlueColor"/> + + + + + + + + + + + android:layout_margin="@dimen/offsetLarge"> - - - + android:layout_marginHorizontal="@dimen/offsetMedium" + android:title="@string/app_name" + android:description="@string/intro_subtitle"/>