From 1643e995afa52ed2d3d99ecbecae7876896f312a Mon Sep 17 00:00:00 2001 From: Esenbek Date: Fri, 26 Apr 2024 16:04:11 +0600 Subject: [PATCH] Implement settings page minor redesign --- .../Settings/Appearance/AppearanceView.swift | 30 +++++ .../Appearance/AppearanceViewModel.swift | 14 +++ .../Settings/Main/MainSettingsModule.swift | 1 - .../Settings/Main/MainSettingsService.swift | 16 +-- .../Main/MainSettingsViewController.swift | 108 +++++++++--------- .../Settings/Main/MainSettingsViewModel.swift | 16 --- .../WalletConnect/WalletConnectService.swift | 10 +- ...WalletConnectSocketConnectionService.swift | 2 +- .../UserInterface/SwiftUI/NavigationRow.swift | 15 ++- .../en.lproj/Localizable.strings | 2 + 10 files changed, 121 insertions(+), 93 deletions(-) diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceView.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceView.swift index 26bb9629b7..cc0dab1d3a 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceView.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceView.swift @@ -8,6 +8,36 @@ struct AppearanceView: View { var body: some View { ScrollableThemeView { VStack(spacing: .margin24) { + VStack(spacing: 0) { + ListSection { + NavigationRow(spacing: .margin8, destination: { + BaseCurrencySettingsModule.view() + }) { + HStack(spacing: .margin16) { + Image("usd_24").themeIcon() + Text("settings.base_currency".localized).textBody() + } + Spacer() + Text(viewModel.baseCurrency.code).textSubhead1() + Image.disclosureIcon + } + + NavigationRow(spacing: .margin8, destination: { + LanguageSettingsModule.view() + }) { + HStack(spacing: .margin16) { + Image("globe_24").themeIcon() + Text("settings.language".localized).textBody() + } + Spacer() + if let language = viewModel.currentLanguageDisplayName { + Text(language).textSubhead1() + } + Image.disclosureIcon + } + } + } + VStack(spacing: 0) { ListSectionHeader(text: "appearance.theme".localized) ListSection { diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceViewModel.swift index 72c56c4e0d..05e7b835a1 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Appearance/AppearanceViewModel.swift @@ -1,17 +1,28 @@ +import Combine import MarketKit import SwiftUI import ThemeKit class AppearanceViewModel: ObservableObject { + private var cancellables = Set() + private let themeManager = App.shared.themeManager private let launchScreenManager = App.shared.launchScreenManager private let appIconManager = App.shared.appIconManager private let balancePrimaryValueManager = App.shared.balancePrimaryValueManager private let balanceConversionManager = App.shared.balanceConversionManager + private let currencyManager = App.shared.currencyManager + private let languageManager = LanguageManager.shared let themeModes: [ThemeMode] = [.system, .dark, .light] let conversionTokens: [Token] + var currentLanguageDisplayName: String? { + languageManager.currentLanguageDisplayName + } + + @Published var baseCurrency: Currency + @Published var themMode: ThemeMode { didSet { themeManager.themeMode = themMode @@ -57,5 +68,8 @@ class AppearanceViewModel: ObservableObject { conversionToken = balanceConversionManager.conversionToken balancePrimaryValue = balancePrimaryValueManager.balancePrimaryValue appIcon = appIconManager.appIcon + baseCurrency = currencyManager.baseCurrency + + currencyManager.$baseCurrency.sink { [weak self] in self?.baseCurrency = $0 }.store(in: &cancellables) } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsModule.swift index 967d1edf0d..cc16254590 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsModule.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsModule.swift @@ -11,7 +11,6 @@ enum MainSettingsModule { passcodeManager: App.shared.passcodeManager, termsManager: App.shared.termsManager, systemInfoManager: App.shared.systemInfoManager, - currencyManager: App.shared.currencyManager, walletConnectSessionManager: App.shared.walletConnectSessionManager, subscriptionManager: App.shared.subscriptionManager, rateAppManager: App.shared.rateAppManager diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift index f9f8e5c890..0bef9d114c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsService.swift @@ -14,7 +14,6 @@ class MainSettingsService { private let passcodeManager: PasscodeManager private let termsManager: TermsManager private let systemInfoManager: SystemInfoManager - private let currencyManager: CurrencyManager private let walletConnectSessionManager: WalletConnectSessionManager private let subscriptionManager: SubscriptionManager private let rateAppManager: RateAppManager @@ -23,7 +22,7 @@ class MainSettingsService { private let noWalletRequiredActionsRelay = BehaviorRelay(value: false) init(backupManager: BackupManager, cloudAccountBackupManager: CloudBackupManager, accountRestoreWarningManager: AccountRestoreWarningManager, accountManager: AccountManager, contactBookManager: ContactBookManager, passcodeManager: PasscodeManager, termsManager: TermsManager, - systemInfoManager: SystemInfoManager, currencyManager: CurrencyManager, walletConnectSessionManager: WalletConnectSessionManager, subscriptionManager: SubscriptionManager, rateAppManager: RateAppManager) + systemInfoManager: SystemInfoManager, walletConnectSessionManager: WalletConnectSessionManager, subscriptionManager: SubscriptionManager, rateAppManager: RateAppManager) { self.cloudAccountBackupManager = cloudAccountBackupManager self.backupManager = backupManager @@ -33,7 +32,6 @@ class MainSettingsService { self.passcodeManager = passcodeManager self.termsManager = termsManager self.systemInfoManager = systemInfoManager - self.currencyManager = currencyManager self.walletConnectSessionManager = walletConnectSessionManager self.subscriptionManager = subscriptionManager self.rateAppManager = rateAppManager @@ -106,18 +104,6 @@ extension MainSettingsService { walletConnectSessionManager.activePendingRequestsObservable.map(\.count) } - var currentLanguageDisplayName: String? { - LanguageManager.shared.currentLanguageDisplayName - } - - var baseCurrency: Currency { - currencyManager.baseCurrency - } - - var baseCurrencyPublisher: AnyPublisher { - currencyManager.$baseCurrency - } - var appVersion: String { systemInfoManager.appVersion.description } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift index 818d3ae7b9..987d13d549 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewController.swift @@ -22,8 +22,6 @@ class MainSettingsViewController: ThemeViewController { private let securityCell = BaseSelectableThemeCell() private let appearanceCell = BaseSelectableThemeCell() private let contactBookCell = BaseSelectableThemeCell() - private let baseCurrencyCell = BaseSelectableThemeCell() - private let languageCell = BaseSelectableThemeCell() private let themeModeCell = BaseSelectableThemeCell() private let aboutCell = BaseSelectableThemeCell() private let footerCell = MainSettingsFooterCell() @@ -52,6 +50,7 @@ class MainSettingsViewController: ThemeViewController { title = "settings.title".localized navigationItem.backBarButtonItem = UIBarButtonItem(title: title, style: .plain, target: nil, action: nil) + tableView.registerHeaderFooter(forClass: HighlightedSubtitleHeaderFooterView.self) tableView.sectionDataSource = self tableView.separatorStyle = .none @@ -77,12 +76,6 @@ class MainSettingsViewController: ThemeViewController { contactBookCell.set(backgroundStyle: .lawrence) syncContactBookCell() - baseCurrencyCell.set(backgroundStyle: .lawrence) - syncBaseCurrency() - - languageCell.set(backgroundStyle: .lawrence, isLast: true) - buildTitleValue(cell: languageCell, image: UIImage(named: "globe_24"), title: "settings.language".localized, value: viewModel.currentLanguage) - aboutCell.set(backgroundStyle: .lawrence, isFirst: true) syncAboutCell() @@ -100,7 +93,6 @@ class MainSettingsViewController: ThemeViewController { subscribe(disposeBag, viewModel.walletConnectCountDriver) { [weak self] tuple in self?.syncWalletConnectCell(text: tuple?.text, highlighted: tuple?.highlighted ?? false) } - subscribe(disposeBag, viewModel.baseCurrencyDriver) { [weak self] in self?.syncBaseCurrency(value: $0) } subscribe(disposeBag, viewModel.aboutAlertDriver) { [weak self] in self?.syncAboutCell(alert: $0) } subscribe(disposeBag, viewModel.openWalletConnectSignal) { [weak self] in self?.openWalletConnect(mode: $0) } @@ -168,10 +160,6 @@ class MainSettingsViewController: ThemeViewController { ) } - private func syncBaseCurrency(value: String? = nil) { - buildTitleValue(cell: baseCurrencyCell, image: UIImage(named: "usd_24"), title: "settings.base_currency".localized, value: value) - } - private func buildTitleValue(cell: BaseThemeCell, image: UIImage?, title: String, value: String? = nil, badge: String? = nil) { CellBuilderNew.buildStatic(cell: cell, rootElement: .hStack([ .image24 { (component: ImageComponent) in @@ -234,6 +222,15 @@ class MainSettingsViewController: ThemeViewController { stat(page: .settings, event: .open(page: .blockchainSettings)) } ), + StaticRow( + cell: walletConnectCell, + id: "wallet-connect", + height: .heightCell48, + autoDeselect: true, + action: { [weak self] in + self?.viewModel.onTapWalletConnect() + } + ), tableView.universalRow48( id: "backup-manager", image: .local(UIImage(named: "icloud_24")), @@ -250,20 +247,6 @@ class MainSettingsViewController: ThemeViewController { ] } - private var walletConnectRows: [RowProtocol] { - [ - StaticRow( - cell: walletConnectCell, - id: "wallet-connect", - height: .heightCell48, - autoDeselect: true, - action: { [weak self] in - self?.viewModel.onTapWalletConnect() - } - ), - ] - } - private var appearanceRows: [RowProtocol] { [ StaticRow( @@ -301,27 +284,6 @@ class MainSettingsViewController: ThemeViewController { stat(page: .settings, event: .open(page: .appearance)) } ), - StaticRow( - cell: baseCurrencyCell, - id: "base-currency", - height: .heightCell48, - action: { [weak self] in - self?.navigationController?.pushViewController(BaseCurrencySettingsModule.view().toViewController(title: "settings.base_currency.title".localized), animated: true) - - stat(page: .settings, event: .open(page: .baseCurrency)) - } - ), - StaticRow( - cell: languageCell, - id: "language", - height: .heightCell48, - action: { [weak self] in - let module = LanguageSettingsModule.view().toViewController(title: "settings.language".localized) - self?.navigationController?.pushViewController(module, animated: true) - - stat(page: .settings, event: .open(page: .language)) - } - ), ] } @@ -358,7 +320,7 @@ class MainSettingsViewController: ThemeViewController { [ tableView.universalRow48( id: "telegram", - image: .local(UIImage(named: "telegram_24")), + image: .local(UIImage(named: "filled_telegram_24")?.withTintColor(.themeJacob)), title: .body("Telegram"), accessoryType: .disclosure, autoDeselect: true, @@ -371,7 +333,7 @@ class MainSettingsViewController: ThemeViewController { ), tableView.universalRow48( id: "twitter", - image: .local(UIImage(named: "twitter_24")), + image: .local(UIImage(named: "filled_twitter_24")?.withTintColor(.themeJacob)), title: .body("Twitter"), accessoryType: .disclosure, autoDeselect: true, @@ -526,10 +488,20 @@ extension MainSettingsViewController: SectionsDataSource { func buildSections() -> [SectionProtocol] { var sections: [SectionProtocol] = [ Section(id: "account", headerState: .margin(height: AppConfig.donateEnabled ? .margin32 : .margin12), rows: accountRows), - Section(id: "wallet_connect", headerState: .margin(height: .margin32), rows: walletConnectRows), - Section(id: "appearance_settings", headerState: .margin(height: .margin32), rows: appearanceRows), + Section(id: "appearance_settings", headerState: .margin(height: .margin32), footerState: .margin(height: .margin24), rows: appearanceRows), + Section( + id: "social", + headerState: .cellType( + hash: "settings.social_networks.label".localized, + binder: { (view: HighlightedSubtitleHeaderFooterView) in + view.bind(text: "settings.social_networks.label".localized, color: .themeJacob, backgroundColor: UIColor.clear) + }, + dynamicHeight: { _ in .margin32 } + ), + footerState: tableView.sectionFooter(text: "settings.social_networks.footer".localized, topMargin: .margin12, bottomMargin: .zero), + rows: socialRows + ), Section(id: "knowledge", headerState: .margin(height: .margin32), rows: knowledgeRows), - Section(id: "social", headerState: .margin(height: .margin32), rows: socialRows), Section(id: "about", headerState: .margin(height: .margin32), rows: aboutRows), Section(id: "footer", headerState: .margin(height: .margin32), footerState: .margin(height: .margin32), rows: footerRows), ] @@ -580,3 +552,33 @@ extension MainSettingsViewController: MFMailComposeViewControllerDelegate { controller.dismiss(animated: true) } } + +class HighlightedSubtitleHeaderFooterView: UITableViewHeaderFooterView { + private let label = UILabel() + + override public init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + + backgroundView = UIView() + + addSubview(label) + label.snp.makeConstraints { maker in + maker.leading.trailing.equalToSuperview().inset(CGFloat.margin32) + maker.centerY.equalToSuperview() + } + + label.font = .subhead1 + label.textColor = .themeGray + } + + @available(*, unavailable) + public required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func bind(text: String?, color: UIColor = .clear, backgroundColor: UIColor = .clear) { + label.text = text?.uppercased() + label.textColor = color + backgroundView?.backgroundColor = backgroundColor + } +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewModel.swift index c9e8cc47f5..109ec14dfc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Settings/Main/MainSettingsViewModel.swift @@ -13,7 +13,6 @@ class MainSettingsViewModel { private let securityCenterAlertRelay: BehaviorRelay private let iCloudSyncAlertRelay: BehaviorRelay private let walletConnectCountRelay: BehaviorRelay<(highlighted: Bool, text: String)?> - private let baseCurrencyRelay: BehaviorRelay private let aboutAlertRelay: BehaviorRelay private let openWalletConnectRelay = PublishRelay() private let openLinkRelay = PublishRelay() @@ -25,7 +24,6 @@ class MainSettingsViewModel { securityCenterAlertRelay = BehaviorRelay(value: !service.isPasscodeSet) iCloudSyncAlertRelay = BehaviorRelay(value: service.isCloudAvailableError) walletConnectCountRelay = BehaviorRelay(value: Self.convert(walletConnectSessionCount: service.walletConnectSessionCount, walletConnectPendingRequestCount: service.walletConnectPendingRequestCount)) - baseCurrencyRelay = BehaviorRelay(value: service.baseCurrency.code) aboutAlertRelay = BehaviorRelay(value: !service.termsAccepted) service.noWalletRequiredActionsObservable @@ -62,12 +60,6 @@ class MainSettingsViewModel { }) .disposed(by: disposeBag) - service.baseCurrencyPublisher - .sink { [weak self] currency in - self?.baseCurrencyRelay.accept(currency.code) - } - .store(in: &cancellables) - service.termsAcceptedPublisher .sink { [weak self] accepted in self?.aboutAlertRelay.accept(!accepted) @@ -108,18 +100,10 @@ extension MainSettingsViewModel { walletConnectCountRelay.asDriver() } - var baseCurrencyDriver: Driver { - baseCurrencyRelay.asDriver() - } - var aboutAlertDriver: Driver { aboutAlertRelay.asDriver() } - var currentLanguage: String? { - service.currentLanguageDisplayName - } - var appVersion: String { service.appVersion } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift index bf358022b4..f790935e68 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectService.swift @@ -1,6 +1,7 @@ import Combine import CryptoSwift import Foundation +import HsCryptoKit import HsToolKit import RxRelay import RxSwift @@ -12,7 +13,6 @@ import WalletConnectRelay import WalletConnectSign import WalletConnectUtils import Web3Wallet -import HsCryptoKit extension Starscream.WebSocket: WebSocketConnecting {} @@ -73,7 +73,7 @@ class WalletConnectService { setUpAuthSubscribing() connectionService.relayClient = Networking.instance - + updateSessions() updatePairings() } @@ -192,7 +192,7 @@ extension WalletConnectService { // works with pending requests public var pendingRequests: [WalletConnectSign.Request] { - Web3Wallet.instance.getPendingRequests().map { $0.request } + Web3Wallet.instance.getPendingRequests().map(\.request) } public var pendingRequestsUpdatedObservable: Observable { @@ -383,13 +383,12 @@ extension WalletConnectSign.SocketConnectionStatus { } struct DefaultCryptoProvider: CryptoProvider { - public func recoverPubKey(signature: EthereumSignature, message: Data) throws -> Data { let signature = Data(signature.r + signature.s + [signature.v]) let messageHash = keccak256(message) var pubKey = HsCryptoKit.Crypto.ellipticPublicKey(signature: signature, of: messageHash, compressed: false) pubKey?.remove(at: 0) - + return pubKey ?? Data() } @@ -398,5 +397,4 @@ struct DefaultCryptoProvider: CryptoProvider { let hash = digest.calculate(for: [UInt8](data)) return Data(hash) } - } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift index 03e2f15389..0b92997fa4 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/WalletConnect/WalletConnectSocketConnectionService.swift @@ -4,11 +4,11 @@ import HsToolKit import RxCocoa import RxRelay import RxSwift +import UIKit import WalletConnectRelay import WalletConnectSign import WalletConnectUtils import Web3Wallet -import UIKit class WalletConnectSocketConnectionService { private static let retryInterval = 10 diff --git a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/NavigationRow.swift b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/NavigationRow.swift index 7c39a09b58..34cef02324 100644 --- a/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/NavigationRow.swift +++ b/UnstoppableWallet/UnstoppableWallet/UserInterface/SwiftUI/NavigationRow.swift @@ -1,12 +1,25 @@ import SwiftUI struct NavigationRow: View { + private let padding: EdgeInsets + private let spacing: CGFloat + private let minHeight: CGFloat + @ViewBuilder let destination: Destination var isActive: Binding? @ViewBuilder let content: Content + init(padding: EdgeInsets = EdgeInsets(top: .margin12, leading: .margin16, bottom: .margin12, trailing: .margin16), spacing: CGFloat = .margin16, minHeight: CGFloat = .heightCell48, @ViewBuilder destination: () -> Destination, isActive: Binding? = nil, @ViewBuilder content: () -> Content) { + self.padding = padding + self.spacing = spacing + self.minHeight = minHeight + self.destination = destination() + self.isActive = isActive + self.content = content() + } + var body: some View { - let row = ListRow { + let row = ListRow(padding: padding, spacing: spacing, minHeight: minHeight) { content } if let isActive { diff --git a/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings b/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings index 295703b061..706036a3cd 100644 --- a/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings +++ b/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings @@ -1237,6 +1237,8 @@ "settings.rate_us" = "Rate Us"; "settings.tell_friends" = "Tell Friends"; "settings.contact_us" = "Contact Us"; +"settings.social_networks.label" = "JOIN UNSTOPPABLES"; +"settings.social_networks.footer" = "Stay on top of Unstoppable happenings. Be the first to know about new features, user reported issues and things we work on!"; // Settings -> Base Currency