Merge pull request #3082 from vladyslav-iosdev/#3081

Refactor: extract ActivitiesView to separate file #3081
pull/3091/head
Hwee-Boon Yar 3 years ago committed by GitHub
commit c2a3f525b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      AlphaWallet.xcodeproj/project.pbxproj
  2. 24
      AlphaWallet/Activities/ActivitiesService.swift
  3. 215
      AlphaWallet/Activities/ViewControllers/ActivitiesViewController.swift
  4. 1
      AlphaWallet/Activities/ViewModels/ActivitiesViewModel.swift
  5. 218
      AlphaWallet/Activities/Views/ActivitiesView.swift
  6. 12
      AlphaWallet/Tokens/ViewControllers/TokenViewController.swift
  7. 8
      AlphaWallet/Transactions/Views/ActivityPageView.swift

@ -732,6 +732,7 @@
87374A4525DFB17600267160 /* HoneySwapERC20Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87374A4425DFB17600267160 /* HoneySwapERC20Token.swift */; };
8738DDDC2652B98200064CCA /* ActivitiesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8738DDDB2652B98200064CCA /* ActivitiesService.swift */; };
8738DDDE2652CD1300064CCA /* MulticastDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8738DDDD2652CD1300064CCA /* MulticastDelegate.swift */; };
8739BB8F26CCF2F70045CFED /* ActivitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8739BB8E26CCF2F70045CFED /* ActivitiesView.swift */; };
873F8063246E8E3E00EEE5EF /* SelectCurrencyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873F8062246E8E3E00EEE5EF /* SelectCurrencyButton.swift */; };
8743CB50255059780039E469 /* DomainResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8743CB4F255059780039E469 /* DomainResolver.swift */; };
874AF0832603405F00D613A5 /* LoadingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874AF0822603405F00D613A5 /* LoadingIndicatorView.swift */; };
@ -1689,6 +1690,7 @@
87374A4425DFB17600267160 /* HoneySwapERC20Token.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoneySwapERC20Token.swift; sourceTree = "<group>"; };
8738DDDB2652B98200064CCA /* ActivitiesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitiesService.swift; sourceTree = "<group>"; };
8738DDDD2652CD1300064CCA /* MulticastDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MulticastDelegate.swift; sourceTree = "<group>"; };
8739BB8E26CCF2F70045CFED /* ActivitiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitiesView.swift; sourceTree = "<group>"; };
873F8062246E8E3E00EEE5EF /* SelectCurrencyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectCurrencyButton.swift; sourceTree = "<group>"; };
8743CB4F255059780039E469 /* DomainResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainResolver.swift; sourceTree = "<group>"; };
874AF0822603405F00D613A5 /* LoadingIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingIndicatorView.swift; sourceTree = "<group>"; };
@ -3298,6 +3300,7 @@
5E7C7AEDAAE638601C7122A5 /* DefaultActivityView.swift */,
8795994426049EF8006722B2 /* ActivityStateView.swift */,
5E7C7E58DD0CF4E2B35B6ED2 /* GroupActivityViewCell.swift */,
8739BB8E26CCF2F70045CFED /* ActivitiesView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -5170,6 +5173,7 @@
2963B6C11F9AE0E4003063C1 /* Data.swift in Sources */,
2932045E1F8EEE760095B7C1 /* BalanceCoordinator.swift in Sources */,
29F114F61FA8147300114A29 /* RequestCoordinator.swift in Sources */,
8739BB8F26CCF2F70045CFED /* ActivitiesView.swift in Sources */,
73ED85A520349BE400593BF3 /* StringFormatter.swift in Sources */,
293112101FC4ADCB00966EEA /* InCoordinatorViewModel.swift in Sources */,
87BBF9972563DD7600FF4846 /* TransactionInProgressCoordinatorBridgeToPromise.swift in Sources */,

@ -125,12 +125,9 @@ class ActivitiesService: NSObject, ActivitiesServiceType {
private var rateLimitedUpdater: RateLimiter?
private var rateLimitedViewControllerReloader: RateLimiter?
private var hasLoadedActivitiesTheFirstTime = false
private var lastActivitiesCount: Int = 0
private var lastTransactionRowsCount: Int = 0
private var lastTransactionBlockNumbers: [Int] = .init()
let subscribableUpdatedActivity: Subscribable<Activity> = .init(nil)
let subscribableViewModel: Subscribable<ActivitiesViewModel> = .init(nil)
let subscribableViewModel: Subscribable<ActivitiesViewModel> = .init(.init(activities: []))
private var tokensInDatabase: [TokenObject] {
tokensStorages.values.flatMap { $0.enabledObject }
@ -174,11 +171,11 @@ class ActivitiesService: NSObject, ActivitiesServiceType {
self.transactionsFilterStrategy = transactionsFilterStrategy
super.init()
filteredTransactionsSubscriptionKey = filteredTransactionsSubscription.subscribe { [weak self] txs in
filteredTransactionsSubscriptionKey = filteredTransactionsSubscription.subscribe { [weak self] _ in
self?.reloadImpl(reloadImmediately: true)
}
recentEventsSubscriptionKey = recentEventsSubscribable.subscribe { [weak self] activities in
recentEventsSubscriptionKey = recentEventsSubscribable.subscribe { [weak self] _ in
self?.reloadImpl(reloadImmediately: true)
}
}
@ -202,7 +199,7 @@ class ActivitiesService: NSObject, ActivitiesServiceType {
}
}
func reloadImpl(reloadImmediately: Bool) {
private func reloadImpl(reloadImmediately: Bool) {
let contractServerXmlHandlers: [(contract: AlphaWallet.Address, server: RPCServer, xmlHandler: XMLHandler)] = tokensInDatabase.compactMap { each in
let eachContract = each.contractAddress
let eachServer = each.server
@ -244,7 +241,6 @@ class ActivitiesService: NSObject, ActivitiesServiceType {
}
return contractAndCard
}
let contractsAndCards = contractsAndCardsOptional.flatMap { $0 }
fetchAndRefreshActivities(contractsAndCards: contractsAndCards, reloadImmediately: reloadImmediately)
}
@ -259,12 +255,15 @@ class ActivitiesService: NSObject, ActivitiesServiceType {
activities = activitiesAndTokens.map { $0.0 }
activities.sort { $0.blockNumber > $1.blockNumber }
updateActivitiesIndexLookup()
reloadViewController(reloadImmediately: reloadImmediately)
for (activity, tokenObject, tokenHolder) in activitiesAndTokens {
refreshActivity(tokenObject: tokenObject, tokenHolder: tokenHolder, activity: activity)
}
}
//Cache tokens lookup for performance
private static var tokensCache: ThreadSafeDictionary<AlphaWallet.Address, Activity.AssignedToken> = .init()
private func getActivities(_ allActivities: [EventActivity], forTokenContract contract: AlphaWallet.Address, server: RPCServer, card: TokenScriptCard, interpolatedFilter: String) -> [(Activity, Activity.AssignedToken, TokenHolder)] {
let events = allActivities.filter {
@ -274,17 +273,14 @@ class ActivitiesService: NSObject, ActivitiesServiceType {
&& $0.filter == interpolatedFilter
}
//Cache tokens lookup for performance
var tokensCache: [AlphaWallet.Address: Activity.AssignedToken] = .init()
let activitiesForThisCard: [(activity: Activity, tokenObject: Activity.AssignedToken, tokenHolder: TokenHolder)] = events.compactMap { eachEvent in
let token: Activity.AssignedToken
if let t = tokensCache[contract] {
if let t = Self.tokensCache[contract] {
token = t
} else {
guard let tokensDatastore = tokensStorages[safe: server] else { return nil }
guard let t = tokensDatastore.tokenThreadSafe(forContract: contract) else { return nil }
let tt = Activity.AssignedToken(tokenObject: t)
tokensCache[contract] = tt
guard let tt = tokensDatastore.tokenThreadSafe(forContract: contract).flatMap({ Activity.AssignedToken(tokenObject: $0) }) else { return nil }
Self.tokensCache[contract] = tt
token = tt
}

@ -9,217 +9,6 @@ protocol ActivitiesViewControllerDelegate: AnyObject {
func didPressTransaction(transaction: TransactionInstance, in viewController: ActivitiesViewController)
}
protocol ActivitiesViewDelegate: class {
func didPressActivity(activity: Activity, in view: ActivitiesView)
func didPressTransaction(transaction: TransactionInstance, in view: ActivitiesView)
}
class ActivitiesView: UIView {
private var viewModel: ActivitiesViewModel
private let sessions: ServerDictionary<WalletSession>
private let tableView = UITableView(frame: .zero, style: .grouped)
weak var delegate: ActivitiesViewDelegate?
init(viewModel: ActivitiesViewModel, sessions: ServerDictionary<WalletSession>) {
self.viewModel = viewModel
self.sessions = sessions
super.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
tableView.register(ActivityViewCell.self)
tableView.register(DefaultActivityItemViewCell.self)
tableView.register(TransactionViewCell.self)
tableView.register(GroupActivityViewCell.self)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .singleLine
tableView.backgroundColor = viewModel.backgroundColor
tableView.estimatedRowHeight = TokensCardViewController.anArbitraryRowHeightSoAutoSizingCellsWorkIniOS10
addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: topAnchor),
tableView.leadingAnchor.constraint(equalTo: leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
emptyView = TransactionsEmptyView(title: R.string.localizable.activityEmpty(), image: R.image.activities_empty_list())
}
func resetStatefulStateToReleaseObjectToAvoidMemoryLeak() {
// NOTE: Stateful lib set to object state machine that later causes ref cycle when applying it to view
// here we release all associated objects to release state machine
// this method callget get called while parent's view deinit get called
objc_removeAssociatedObjects(self)
}
required init?(coder: NSCoder) {
return nil
}
func reloadData() {
tableView.reloadData()
}
func configure(viewModel: ActivitiesViewModel) {
self.viewModel = viewModel
}
func applySearch(keyword: String?) {
viewModel.filter(.keyword(keyword))
reloadData()
}
}
extension ActivitiesView: StatefulViewController {
func hasContent() -> Bool {
return viewModel.numberOfSections > 0
}
}
extension ActivitiesView: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true )
let item = viewModel.item(for: indexPath.row, section: indexPath.section)
switch item {
case .parentTransaction:
break
case .childActivity(_, activity: let activity):
delegate?.didPressActivity(activity: activity, in: self)
case .childTransaction(let transaction, _, let activity):
if let activity = activity {
delegate?.didPressActivity(activity: activity, in: self)
} else {
delegate?.didPressTransaction(transaction: transaction, in: self)
}
case .standaloneTransaction(transaction: let transaction, let activity):
if let activity = activity {
delegate?.didPressActivity(activity: activity, in: self)
} else {
delegate?.didPressTransaction(transaction: transaction, in: self)
}
case .standaloneActivity(activity: let activity):
delegate?.didPressActivity(activity: activity, in: self)
}
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
let item = viewModel.item(for: indexPath.row, section: indexPath.section)
switch item {
case .parentTransaction:
return nil
case .childActivity, .childTransaction, .standaloneTransaction, .standaloneActivity:
return indexPath
}
}
//Hide the footer
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
.leastNormalMagnitude
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
nil
}
}
extension ActivitiesView: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.numberOfSections
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = viewModel.item(for: indexPath.row, section: indexPath.section)
switch item {
case .parentTransaction(_, isSwap: let isSwap, _):
let cell: GroupActivityViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(groupType: isSwap ? .swap : .unknown))
return cell
case .childActivity(_, activity: let activity):
let activity: Activity = {
var a = activity
a.rowType = .item
return a
}()
switch activity.nativeViewType {
case .erc20Received, .erc20Sent, .erc20OwnerApproved, .erc20ApprovalObtained, .erc721Received, .erc721Sent, .erc721OwnerApproved, .erc721ApprovalObtained, .nativeCryptoSent, .nativeCryptoReceived:
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
case .none:
let cell: ActivityViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
}
case .childTransaction(transaction: let transaction, operation: let operation, let activity):
if let activity = activity {
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
} else {
let cell: TransactionViewCell = tableView.dequeueReusableCell(for: indexPath)
let session = sessions[transaction.server]
cell.configure(viewModel: .init(transactionRow: .item(transaction: transaction, operation: operation), chainState: session.chainState, currentWallet: session.account, server: transaction.server))
return cell
}
case .standaloneTransaction(transaction: let transaction, let activity):
if let activity = activity {
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
} else {
let cell: TransactionViewCell = tableView.dequeueReusableCell(for: indexPath)
let session = sessions[transaction.server]
cell.configure(viewModel: .init(transactionRow: .standalone(transaction), chainState: session.chainState, currentWallet: session.account, server: transaction.server))
return cell
}
case .standaloneActivity(activity: let activity):
switch activity.nativeViewType {
case .erc20Received, .erc20Sent, .erc20OwnerApproved, .erc20ApprovalObtained, .erc721Received, .erc721Sent, .erc721OwnerApproved, .erc721ApprovalObtained, .nativeCryptoSent, .nativeCryptoReceived:
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
case .none:
let cell: ActivityViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.numberOfItems(for: section)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return ActivitiesViewController.functional.headerView(for: section, viewModel: viewModel)
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
}
fileprivate func headerView(for section: Int) -> UIView {
let container = UIView()
container.backgroundColor = viewModel.headerBackgroundColor
let title = UILabel()
title.text = viewModel.titleForHeader(in: section)
title.sizeToFit()
title.textColor = viewModel.headerTitleTextColor
title.font = viewModel.headerTitleFont
container.addSubview(title)
title.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
title.anchorsConstraint(to: container, edgeInsets: .init(top: 18, left: 20, bottom: 16, right: 0))
])
return container
}
}
class ActivitiesViewController: UIViewController {
private var viewModel: ActivitiesViewModel
private let searchController: UISearchController
@ -237,7 +26,7 @@ class ActivitiesViewController: UIViewController {
title = R.string.localizable.activityTabbarItemTitle()
activitiesView.delegate = self
view.backgroundColor = self.viewModel.backgroundColor
view.backgroundColor = viewModel.backgroundColor
bottomConstraint = activitiesView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
keyboardChecker.constraint = bottomConstraint
@ -371,7 +160,7 @@ extension ActivitiesViewController {
extension ActivitiesViewController.functional {
fileprivate static func headerView(for section: Int, viewModel: ActivitiesViewModel) -> UIView {
static func headerView(for section: Int, viewModel: ActivitiesViewModel) -> UIView {
let container = UIView()
container.backgroundColor = viewModel.headerBackgroundColor
let title = UILabel()

@ -24,7 +24,6 @@ struct ActivitiesViewModel {
hasher.combine(stringValue)
}
static func == (_ lhs: ActivityDateKey, _ rhs: ActivityDateKey) -> Bool {
return lhs.stringValue == rhs.stringValue
}

@ -0,0 +1,218 @@
//
// ActivitiesView.swift
// AlphaWallet
//
// Created by Vladyslav Shepitko on 18.08.2021.
//
import UIKit
import BigInt
import StatefulViewController
protocol ActivitiesViewDelegate: class {
func didPressActivity(activity: Activity, in view: ActivitiesView)
func didPressTransaction(transaction: TransactionInstance, in view: ActivitiesView)
}
class ActivitiesView: UIView {
private var viewModel: ActivitiesViewModel
private let sessions: ServerDictionary<WalletSession>
private let tableView = UITableView(frame: .zero, style: .grouped)
weak var delegate: ActivitiesViewDelegate?
init(viewModel: ActivitiesViewModel, sessions: ServerDictionary<WalletSession>) {
self.viewModel = viewModel
self.sessions = sessions
super.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
tableView.register(ActivityViewCell.self)
tableView.register(DefaultActivityItemViewCell.self)
tableView.register(TransactionViewCell.self)
tableView.register(GroupActivityViewCell.self)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .singleLine
tableView.backgroundColor = viewModel.backgroundColor
tableView.estimatedRowHeight = TokensCardViewController.anArbitraryRowHeightSoAutoSizingCellsWorkIniOS10
addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: topAnchor),
tableView.leadingAnchor.constraint(equalTo: leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
emptyView = TransactionsEmptyView(title: R.string.localizable.activityEmpty(), image: R.image.activities_empty_list())
}
func resetStatefulStateToReleaseObjectToAvoidMemoryLeak() {
// NOTE: Stateful lib set to object state machine that later causes ref cycle when applying it to view
// here we release all associated objects to release state machine
// this method callget get called while parent's view deinit get called
objc_removeAssociatedObjects(self)
}
required init?(coder: NSCoder) {
return nil
}
func reloadData() {
tableView.reloadData()
}
func configure(viewModel: ActivitiesViewModel) {
self.viewModel = viewModel
}
func applySearch(keyword: String?) {
viewModel.filter(.keyword(keyword))
reloadData()
}
}
extension ActivitiesView: StatefulViewController {
func hasContent() -> Bool {
return viewModel.numberOfSections > 0
}
}
extension ActivitiesView: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true )
switch viewModel.item(for: indexPath.row, section: indexPath.section) {
case .parentTransaction:
break
case .childActivity(_, activity: let activity):
delegate?.didPressActivity(activity: activity, in: self)
case .childTransaction(let transaction, _, let activity):
if let activity = activity {
delegate?.didPressActivity(activity: activity, in: self)
} else {
delegate?.didPressTransaction(transaction: transaction, in: self)
}
case .standaloneTransaction(transaction: let transaction, let activity):
if let activity = activity {
delegate?.didPressActivity(activity: activity, in: self)
} else {
delegate?.didPressTransaction(transaction: transaction, in: self)
}
case .standaloneActivity(activity: let activity):
delegate?.didPressActivity(activity: activity, in: self)
}
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
switch viewModel.item(for: indexPath.row, section: indexPath.section) {
case .parentTransaction:
return nil
case .childActivity, .childTransaction, .standaloneTransaction, .standaloneActivity:
return indexPath
}
}
//Hide the footer
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
.leastNormalMagnitude
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
nil
}
}
extension ActivitiesView: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.numberOfSections
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch viewModel.item(for: indexPath.row, section: indexPath.section) {
case .parentTransaction(_, isSwap: let isSwap, _):
let cell: GroupActivityViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(groupType: isSwap ? .swap : .unknown))
return cell
case .childActivity(_, activity: let activity):
let activity: Activity = {
var a = activity
a.rowType = .item
return a
}()
switch activity.nativeViewType {
case .erc20Received, .erc20Sent, .erc20OwnerApproved, .erc20ApprovalObtained, .erc721Received, .erc721Sent, .erc721OwnerApproved, .erc721ApprovalObtained, .nativeCryptoSent, .nativeCryptoReceived:
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
case .none:
let cell: ActivityViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
}
case .childTransaction(transaction: let transaction, operation: let operation, let activity):
if let activity = activity {
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
} else {
let cell: TransactionViewCell = tableView.dequeueReusableCell(for: indexPath)
let session = sessions[transaction.server]
cell.configure(viewModel: .init(transactionRow: .item(transaction: transaction, operation: operation), chainState: session.chainState, currentWallet: session.account, server: transaction.server))
return cell
}
case .standaloneTransaction(transaction: let transaction, let activity):
if let activity = activity {
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
} else {
let cell: TransactionViewCell = tableView.dequeueReusableCell(for: indexPath)
let session = sessions[transaction.server]
cell.configure(viewModel: .init(transactionRow: .standalone(transaction), chainState: session.chainState, currentWallet: session.account, server: transaction.server))
return cell
}
case .standaloneActivity(activity: let activity):
switch activity.nativeViewType {
case .erc20Received, .erc20Sent, .erc20OwnerApproved, .erc20ApprovalObtained, .erc721Received, .erc721Sent, .erc721OwnerApproved, .erc721ApprovalObtained, .nativeCryptoSent, .nativeCryptoReceived:
let cell: DefaultActivityItemViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
case .none:
let cell: ActivityViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(viewModel: .init(activity: activity))
return cell
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.numberOfItems(for: section)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return ActivitiesViewController.functional.headerView(for: section, viewModel: viewModel)
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
}
fileprivate func headerView(for section: Int) -> UIView {
let container = UIView()
container.backgroundColor = viewModel.headerBackgroundColor
let title = UILabel()
title.text = viewModel.titleForHeader(in: section)
title.sizeToFit()
title.textColor = viewModel.headerTitleTextColor
title.font = viewModel.headerTitleFont
container.addSubview(title)
title.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
title.anchorsConstraint(to: container, edgeInsets: .init(top: 18, left: 20, bottom: 16, right: 0))
])
return container
}
}

@ -46,7 +46,7 @@ class TokenViewController: UIViewController {
private lazy var alertsPageView = AlertsPageView()
private let sessions: ServerDictionary<WalletSession>
private let activitiesService: ActivitiesServiceType
private var activitiesSubscriptionKey: Subscribable<ActivitiesViewModel>.SubscribableKey?
init(session: WalletSession, tokensDataStore: TokensDataStore, assetDefinition: AssetDefinitionStore, transactionType: TransactionType, analyticsCoordinator: AnalyticsCoordinator, token: TokenObject, viewModel: TokenViewControllerViewModel, activitiesService: ActivitiesServiceType, sessions: ServerDictionary<WalletSession>) {
self.tokenObject = token
self.viewModel = viewModel
@ -80,10 +80,10 @@ class TokenViewController: UIViewController {
navigationItem.largeTitleDisplayMode = .never
activitiesService.subscribableViewModel.subscribe { [weak self] viewModel in
guard let strongSelf = self, let viewModel = viewModel else { return }
activitiesSubscriptionKey = activitiesService.subscribableViewModel.subscribe { [weak activityPageView] viewModel in
guard let view = activityPageView else { return }
strongSelf.activityPageView.configure(viewModel: .init(activitiesViewModel: viewModel))
view.configure(viewModel: .init(activitiesViewModel: viewModel ?? .init(activities: [])))
}
}
@ -91,6 +91,10 @@ class TokenViewController: UIViewController {
return nil
}
deinit {
activitiesSubscriptionKey.flatMap { activitiesService.subscribableViewModel.unsubscribe($0) }
}
override func viewDidLoad() {
super.viewDidLoad()

@ -27,9 +27,7 @@ protocol ActivityPageViewDelegate: class {
class ActivityPageView: UIView, TokenPageViewType {
var title: String {
viewModel.title
}
var title: String { viewModel.title }
private var activitiesView: ActivitiesView
var viewModel: ActivityPageViewModel
@ -44,9 +42,7 @@ class ActivityPageView: UIView, TokenPageViewType {
translatesAutoresizingMaskIntoConstraints = false
addSubview(activitiesView)
NSLayoutConstraint.activate([
activitiesView.anchorsConstraint(to: self)
])
NSLayoutConstraint.activate([activitiesView.anchorsConstraint(to: self)])
configure(viewModel: viewModel)
}

Loading…
Cancel
Save