Skip to content

Commit

Permalink
Merge branch 'feature/manual-backup-key-list' into feature/backup-cus…
Browse files Browse the repository at this point in the history
…tom-key-flow-adaptation

# Conflicts:
#	novawallet.xcodeproj/project.pbxproj
  • Loading branch information
svojsu committed May 24, 2024
2 parents 473d9a4 + 0894a94 commit cfbf168
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 110 deletions.
4 changes: 4 additions & 0 deletions novawallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@
2D077E472BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D077E462BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift */; };
2D221CBE2BF753620053E36C /* ContentSizedCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D221CBD2BF753620053E36C /* ContentSizedCollectionView.swift */; };
2D221CC02BF753C30053E36C /* MnemonicWordCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D221CBF2BF753C30053E36C /* MnemonicWordCollectionCell.swift */; };
2D8684602C0086A500A663D2 /* ManualBackupKeyListViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D86845F2C0086A500A663D2 /* ManualBackupKeyListViewModelFactory.swift */; };
2D8684552BFF7F6000A663D2 /* ExportPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8684542BFF7F6000A663D2 /* ExportPresenter.swift */; };
2D8684582BFF8CE600A663D2 /* BaseExportPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8684572BFF8CE600A663D2 /* BaseExportPresenter.swift */; };
2D86845E2BFF9DA000A663D2 /* BackupAttentionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D86845D2BFF9DA000A663D2 /* BackupAttentionInteractor.swift */; };
Expand Down Expand Up @@ -5515,6 +5516,7 @@
2D077E462BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualBackupChainTableViewCell.swift; sourceTree = "<group>"; };
2D221CBD2BF753620053E36C /* ContentSizedCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSizedCollectionView.swift; sourceTree = "<group>"; };
2D221CBF2BF753C30053E36C /* MnemonicWordCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicWordCollectionCell.swift; sourceTree = "<group>"; };
2D86845F2C0086A500A663D2 /* ManualBackupKeyListViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualBackupKeyListViewModelFactory.swift; sourceTree = "<group>"; };
2D8684542BFF7F6000A663D2 /* ExportPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportPresenter.swift; sourceTree = "<group>"; };
2D8684572BFF8CE600A663D2 /* BaseExportPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseExportPresenter.swift; sourceTree = "<group>"; };
2D86845D2BFF9DA000A663D2 /* BackupAttentionInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupAttentionInteractor.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -11189,6 +11191,7 @@
2D077E462BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift */,
2CB02245B44D5D1036626E24 /* ManualBackupKeyListWireframe.swift */,
A6D59DCB2D2148A8DFF4F099 /* ManualBackupKeyListPresenter.swift */,
2D86845F2C0086A500A663D2 /* ManualBackupKeyListViewModelFactory.swift */,
8CA7AD4DAF33E6758420BBD6 /* ManualBackupKeyListInteractor.swift */,
0E1AB5FA9D24E5E53E703005 /* ManualBackupKeyListViewController.swift */,
29CD41F03830F4967EF06F91 /* ManualBackupKeyListViewLayout.swift */,
Expand Down Expand Up @@ -24542,6 +24545,7 @@
84EBC55124F660A700459D15 /* EventVisitor.swift in Sources */,
0C37AFD32B598D8C00009ECA /* ProxySignConfirmationInteractor.swift in Sources */,
842B2FCF2947352A002829B6 /* UITextField+Attributes.swift in Sources */,
2D8684602C0086A500A663D2 /* ManualBackupKeyListViewModelFactory.swift in Sources */,
8452585127ABC531004F9082 /* AssetsSettingsViewModel.swift in Sources */,
0C8AF7BA2B3806B700005AC9 /* ChainModel+Pdc20.swift in Sources */,
0C1BE1A62A47FC240010933C /* MultistakingSyncServiceFactory.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion novawallet/Common/View/ChainAccount/ChainAccountView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class ChainAccountView: UIView {
view.valueBottom.apply(style: .caption1Secondary)
view.valueBottom.textAlignment = .left
view.valueBottom.numberOfLines = 0
view.valueBottom.isHidden
view.valueBottom.isHidden = true

view.spacing = 4
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,24 @@ final class ManualBackupKeyListPresenter {
let interactor: ManualBackupKeyListInteractorInputProtocol

private let metaAccount: MetaAccountModel
private let viewModelFactory: ManualBackupKeyListViewModelFactory
private let walletViewModelFactory = WalletAccountViewModelFactory()
private let networkViewModelFactory: NetworkViewModelFactoryProtocol
private let localizationManager: LocalizationManagerProtocol
private let logger: Logger

private var chains: [ChainModel.Id: ChainModel] = [:]

init(
interactor: ManualBackupKeyListInteractorInputProtocol,
wireframe: ManualBackupKeyListWireframeProtocol,
viewModelFactory: ManualBackupKeyListViewModelFactory,
metaAccount: MetaAccountModel,
networkViewModelFactory: NetworkViewModelFactoryProtocol,
localizationManager: LocalizationManagerProtocol,
logger: Logger
) {
self.interactor = interactor
self.wireframe = wireframe
self.viewModelFactory = viewModelFactory
self.metaAccount = metaAccount
self.networkViewModelFactory = networkViewModelFactory
self.logger = logger
self.localizationManager = localizationManager
}
}

Expand All @@ -45,14 +42,14 @@ extension ManualBackupKeyListPresenter: ManualBackupKeyListPresenterProtocol {
view?.updateNavbar(with: walletViewModel)
}

func didTapDefaultKey() {
func activateDefaultKey() {
wireframe.showDefaultAccountBackup(
from: view,
with: metaAccount
)
}

func didTapCustomKey(with chainId: ChainModel.Id) {
func activateCustomKey(with chainId: ChainModel.Id) {
guard let chain = chains[chainId] else { return }

wireframe.showCustomKeyAccountBackup(from: view, with: metaAccount, chain: chain)
Expand All @@ -69,7 +66,10 @@ extension ManualBackupKeyListPresenter: ManualBackupKeyListInteractorOutputProto
chains,
for: metaAccount
)
let viewModel = createViewModel(from: sortedChains)
let viewModel = viewModelFactory.createViewModel(
from: sortedChains.defaultChains,
sortedChains.customChains
)

view?.update(with: viewModel)
}
Expand All @@ -78,78 +78,21 @@ extension ManualBackupKeyListPresenter: ManualBackupKeyListInteractorOutputProto
// MARK: Private

private extension ManualBackupKeyListPresenter {
func createViewModel(from sortedChains: SortedChains) -> ManualBackupKeyListViewLayout.Model {
let listHeaderText = R.string.localizable.chainAccountsListHeader(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

return .init(
listHeaderText: listHeaderText,
accountsSections: [
createDefaultChainsSection(for: sortedChains.defaultChains),
createCustomChainsSection(for: sortedChains.customChains)
]
)
}

func createDefaultChainsSection(for chains: [ChainModel]) -> ManualBackupKeyListViewLayout.Sections {
let defaultChainsHeaderText = R.string.localizable.chainAccountsListDefaultHeader(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

let defaultChainsTitleText = R.string.localizable.chainAccountsListDefaultTitle(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

return .defaultKeys(
.init(
headerText: defaultChainsHeaderText.uppercased(),
accounts: [
.init(
title: defaultChainsTitleText,
subtitle: formattedString(for: chains)
)
]
)
)
}

func createCustomChainsSection(for chains: [ChainModel]) -> ManualBackupKeyListViewLayout.Sections {
let customChainsViewModels = chains
.compactMap { [weak self] chain -> ManualBackupKeyListViewLayout.CustomAccount? in
guard let self else { return .none }

return ManualBackupKeyListViewLayout.CustomAccount(
network: networkViewModelFactory.createViewModel(from: chain),
chainId: chain.chainId
)
}

let customChainsHeaderText = R.string.localizable.chainAccountsListCustomHeader(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

return .customKeys(
.init(
headerText: customChainsHeaderText.uppercased(),
accounts: customChainsViewModels
)
)
}

func sorted(
_ chains: [ChainModel.Id: ChainModel],
for metaAccount: MetaAccountModel
) -> SortedChains {
let defaultChainsIds = Set(metaAccount.chainAccounts.map(\.chainId))
let accountsChainIds = Set(metaAccount.chainAccounts.map(\.chainId))

var defaultChains: [ChainModel] = []
var customChains: [ChainModel] = []

chains.forEach { chain in
defaultChainsIds.contains(chain.key)
? customChains.append(chain.value)
: defaultChains.append(chain.value)
if accountsChainIds.contains(chain.key) {
customChains.append(chain.value)
} else if let _ = metaAccount.fetch(for: chain.value.accountRequest()) {
defaultChains.append(chain.value)
}
}

defaultChains.sort { ChainModelCompator.defaultComparator(chain1: $0, chain2: $1) }
Expand All @@ -160,36 +103,6 @@ private extension ManualBackupKeyListPresenter {
customChains: customChains
)
}

func formattedString(for defaultChains: [ChainModel]) -> String {
let chainsToMention = defaultChains.count > 1
? defaultChains.prefix(2)
: defaultChains.prefix(1)
let separator = ", "
let restCount = defaultChains.count - chainsToMention.count

return chainsToMention
.map(\.name)
.reduce(into: "") { partialResult, name in
guard !partialResult.isEmpty else {
partialResult += name

return
}

var result = [partialResult, name].joined(separator: separator)

if chainsToMention.last?.name == name, restCount > 0 {
let othersString = R.string.localizable.chainAccountsListDefaultSubtitle(
restCount,
preferredLanguages: localizationManager.selectedLocale.rLanguages
)
result = [result, othersString].joined(separator: separator)
}

partialResult = result
}
}
}

private extension ManualBackupKeyListPresenter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ protocol ManualBackupKeyListViewProtocol: ControllerBackedProtocol {

protocol ManualBackupKeyListPresenterProtocol: AnyObject {
func setup()
func didTapDefaultKey()
func didTapCustomKey(with chainId: ChainModel.Id)
func activateDefaultKey()
func activateCustomKey(with chainId: ChainModel.Id)
}

protocol ManualBackupKeyListInteractorInputProtocol: AnyObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ extension ManualBackupKeyListViewController: UITableViewDataSource, UITableViewD

switch viewModel.accountsSections[indexPath.section] {
case .defaultKeys:
presenter.didTapDefaultKey()
presenter.activateDefaultKey()
case let .customKeys(model):
let id = model.accounts[indexPath.row].chainId
presenter.didTapCustomKey(with: id)
presenter.activateCustomKey(with: id)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import SoraFoundation
struct ManualBackupKeyListViewFactory {
static func createView(with metaAccount: MetaAccountModel) -> ManualBackupKeyListViewProtocol? {
let chainRegistry = ChainRegistryFacade.sharedRegistry
let networkViewModelFactory = NetworkViewModelFactory()
let viewModelFactory = ManualBackupKeyListViewModelFactory(
localizationManager: LocalizationManager.shared,
networkViewModelFactory: NetworkViewModelFactory()
)

let interactor = ManualBackupKeyListInteractor(
chainRegistry: chainRegistry
Expand All @@ -17,9 +20,8 @@ struct ManualBackupKeyListViewFactory {
let presenter = ManualBackupKeyListPresenter(
interactor: interactor,
wireframe: wireframe,
viewModelFactory: viewModelFactory,
metaAccount: metaAccount,
networkViewModelFactory: networkViewModelFactory,
localizationManager: LocalizationManager.shared,
logger: Logger.shared
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import Foundation
import SoraFoundation

class ManualBackupKeyListViewModelFactory {
private let localizationManager: LocalizationManagerProtocol
private let networkViewModelFactory: NetworkViewModelFactoryProtocol

init(
localizationManager: LocalizationManagerProtocol,
networkViewModelFactory: NetworkViewModelFactoryProtocol
) {
self.localizationManager = localizationManager
self.networkViewModelFactory = networkViewModelFactory
}

func createViewModel(
from defaultChains: [ChainModel],
_ customChains: [ChainModel]
) -> ManualBackupKeyListViewLayout.Model {
let listHeaderText = R.string.localizable.chainAccountsListHeader(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

var sections: [ManualBackupKeyListViewLayout.Sections] = []

if !defaultChains.isEmpty {
sections.append(createDefaultChainsSection(for: defaultChains))
}

if !customChains.isEmpty {
sections.append(createCustomChainsSection(for: customChains))
}

return .init(
listHeaderText: listHeaderText,
accountsSections: sections
)
}
}

// MARK: Private

private extension ManualBackupKeyListViewModelFactory {
func createDefaultChainsSection(for chains: [ChainModel]) -> ManualBackupKeyListViewLayout.Sections {
let defaultChainsHeaderText = R.string.localizable.chainAccountsListDefaultHeader(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

let defaultChainsTitleText = R.string.localizable.chainAccountsListDefaultTitle(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

return .defaultKeys(
.init(
headerText: defaultChainsHeaderText.uppercased(),
accounts: [
.init(
title: defaultChainsTitleText,
subtitle: formattedString(for: chains)
)
]
)
)
}

func createCustomChainsSection(for chains: [ChainModel]) -> ManualBackupKeyListViewLayout.Sections {
let customChainsViewModels = chains
.compactMap { [weak self] chain -> ManualBackupKeyListViewLayout.CustomAccount? in
guard let self else { return .none }

return ManualBackupKeyListViewLayout.CustomAccount(
network: networkViewModelFactory.createViewModel(from: chain),
chainId: chain.chainId
)
}

let customChainsHeaderText = R.string.localizable.chainAccountsListCustomHeader(
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

return .customKeys(
.init(
headerText: customChainsHeaderText.uppercased(),
accounts: customChainsViewModels
)
)
}

func formattedString(for defaultChains: [ChainModel]) -> String {
let chainsToMention = defaultChains.count > 1
? defaultChains.prefix(2)
: defaultChains.prefix(1)
let restCount = defaultChains.count - chainsToMention.count
let othersString = R.string.localizable.chainAccountsListDefaultSubtitle(
restCount,
preferredLanguages: localizationManager.selectedLocale.rLanguages
)

var joinedChains = chainsToMention
.map(\.name)
.joined(with: String.CompoundSeparator.commaSpace)

return restCount > 0
? [joinedChains, othersString].joined(with: .commaSpace)
: joinedChains
}
}

0 comments on commit cfbf168

Please sign in to comment.