Wallet improvements

This commit is contained in:
Peter
2019-09-25 00:57:46 +04:00
parent ee9815cff8
commit c64c16b8ee
39 changed files with 4202 additions and 3733 deletions

View File

@@ -11,6 +11,59 @@ import SolidRoundedButtonNode
import AnimationUI
import SwiftSignalKit
import MergeLists
import TelegramStringFormatting
private func stringForRelativeUpdateTime(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String {
let dayString: String
switch day {
case .today:
dayString = strings.Updated_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0
case .yesterday:
dayString = strings.Updated_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0
}
return dayString
}
private func lastUpdateTimestampString(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, statusTimestamp: Int32, relativeTo timestamp: Int32) -> String {
let difference = timestamp - statusTimestamp
let expanded = true
if difference < 60 {
return strings.Updated_JustNow
} else if difference < 60 * 60 && !expanded {
let minutes = difference / 60
return strings.Updated_MinutesAgo(minutes)
} else {
var t: time_t = time_t(statusTimestamp)
var timeinfo: tm = tm()
localtime_r(&t, &timeinfo)
var now: time_t = time_t(timestamp)
var timeinfoNow: tm = tm()
localtime_r(&now, &timeinfoNow)
if timeinfo.tm_year != timeinfoNow.tm_year {
return strings.Updated_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).0
}
let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday
if dayDifference == 0 || dayDifference == -1 {
let day: RelativeTimestampFormatDay
if dayDifference == 0 {
if expanded {
day = .today
} else {
let minutes = difference / (60 * 60)
return strings.Updated_HoursAgo(minutes)
}
} else {
day = .yesterday
}
return stringForRelativeUpdateTime(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min)
} else {
return strings.Updated_AtDate(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)).0
}
}
}
public final class WalletInfoScreen: ViewController {
private let context: AccountContext
@@ -20,6 +73,11 @@ public final class WalletInfoScreen: ViewController {
private var presentationData: PresentationData
private let _ready = Promise<Bool>()
override public var ready: Promise<Bool> {
return self._ready
}
public init(context: AccountContext, tonContext: TonContext, walletInfo: WalletInfo, address: String) {
self.context = context
self.tonContext = tonContext
@@ -77,6 +135,8 @@ public final class WalletInfoScreen: ViewController {
})
self.displayNodeDidLoad()
self._ready.set((self.displayNode as! WalletInfoScreenNode).contentReady.get())
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
@@ -126,11 +186,7 @@ private final class WalletInfoBalanceNode: ASDisplayNode {
let balanceTextFrame = CGRect(origin: balanceOrigin, size: balanceTextSize)
let balanceIconFrame: CGRect
if self.isLoading {
balanceIconFrame = CGRect(origin: CGPoint(x: floor((width - balanceIconSize.width) / 2.0), y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize)
} else {
balanceIconFrame = CGRect(origin: CGPoint(x: balanceTextFrame.maxX + balanceIconSpacing, y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize)
}
balanceIconFrame = CGRect(origin: CGPoint(x: balanceTextFrame.maxX + balanceIconSpacing, y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize)
transition.updateFrameAdditive(node: self.balanceTextNode, frame: balanceTextFrame)
transition.updateFrame(node: self.balanceIconNode, frame: balanceIconFrame)
@@ -140,20 +196,33 @@ private final class WalletInfoBalanceNode: ASDisplayNode {
private final class WalletInfoHeaderNode: ASDisplayNode {
var balance: Int64?
var isRefreshing: Bool = false
var timestampString: String = "" {
didSet {
self.balanceTimestampNode.attributedText = NSAttributedString(string: self.timestampString, font: Font.regular(13), textColor: UIColor(white: 1.0, alpha: 0.6))
}
}
let balanceNode: WalletInfoBalanceNode
private let refreshNode: AnimatedStickerNode
private let balanceSubtitleNode: ImmediateTextNode
private let balanceTimestampNode: ImmediateTextNode
private let receiveButtonNode: SolidRoundedButtonNode
private let sendButtonNode: SolidRoundedButtonNode
private let headerBackgroundNode: ASImageNode
init(theme: PresentationTheme, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void) {
init(account: Account, theme: PresentationTheme, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void) {
self.balanceNode = WalletInfoBalanceNode(theme: theme)
self.balanceSubtitleNode = ImmediateTextNode()
self.balanceSubtitleNode.displaysAsynchronously = false
self.balanceSubtitleNode.attributedText = NSAttributedString(string: "your balance", font: Font.regular(13), textColor: UIColor(white: 1.0, alpha: 0.6))
self.balanceTimestampNode = ImmediateTextNode()
self.balanceTimestampNode.displaysAsynchronously = false
self.balanceTimestampNode.attributedText = NSAttributedString(string: "", font: Font.regular(13), textColor: UIColor(white: 1.0, alpha: 0.6))
self.headerBackgroundNode = ASImageNode()
self.headerBackgroundNode.displaysAsynchronously = false
self.headerBackgroundNode.displayWithoutProcessing = true
@@ -168,6 +237,13 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
self.receiveButtonNode = SolidRoundedButtonNode(title: "Receive", icon: UIImage(bundleImageName: "Wallet/ReceiveButtonIcon"), theme: SolidRoundedButtonTheme(backgroundColor: .white, foregroundColor: .black), height: 50.0, cornerRadius: 10.0, gloss: false)
self.sendButtonNode = SolidRoundedButtonNode(title: "Send", icon: UIImage(bundleImageName: "Wallet/SendButtonIcon"), theme: SolidRoundedButtonTheme(backgroundColor: .white, foregroundColor: .black), height: 50.0, cornerRadius: 10.0, gloss: false)
self.refreshNode = AnimatedStickerNode()
self.refreshNode.playToCompletionOnStop = true
self.refreshNode.automaticallyLoadFirstFrame = true
if let path = getAppBundle().path(forResource: "celebrate", ofType: "tgs") {
self.refreshNode.setup(account: account, resource: .localFile(path), width: Int(32.0 * UIScreenScale), height: Int(32.0 * UIScreenScale), mode: .direct)
}
super.init()
self.addSubnode(self.headerBackgroundNode)
@@ -175,6 +251,8 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
self.addSubnode(self.sendButtonNode)
self.addSubnode(self.balanceNode)
self.addSubnode(self.balanceSubtitleNode)
self.addSubnode(self.balanceTimestampNode)
self.addSubnode(self.refreshNode)
self.receiveButtonNode.pressed = {
receiveAction()
@@ -206,11 +284,13 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
let buttonAlpha = buttonTransition * 1.0
let balanceSubtitleSize = self.balanceSubtitleNode.updateLayout(CGSize(width: size.width - sideInset * 2.0, height: 200.0))
let balanceTimestampSize = self.balanceTimestampNode.updateLayout(CGSize(width: size.width - sideInset * 2.0, height: 200.0))
let balanceHeight = self.balanceNode.update(width: size.width, transition: transition)
let balanceSize = CGSize(width: size.width, height: balanceHeight)
let minHeaderScale: CGFloat = 0.435
let maxHeaderScale: CGFloat = min(1.0, (size.width - 40.0) / balanceSize.width)
let minHeaderScale: CGFloat = min(0.435, (size.width - 80.0 * 2.0) / balanceSize.width)
let minHeaderHeight: CGFloat = balanceSize.height + balanceSubtitleSize.height + balanceSubtitleSpacing
@@ -219,13 +299,39 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
let headerScaleTransition: CGFloat = max(0.0, min(1.0, (effectiveOffset - minHeaderOffset) / (maxHeaderOffset - minHeaderOffset)))
let headerPositionTransition: CGFloat = max(0.0, (effectiveOffset - minHeaderOffset) / (maxOffset - minHeaderOffset))
let headerY = headerPositionTransition * maxHeaderY + (1.0 - headerPositionTransition) * minHeaderY
let headerScale = headerScaleTransition * 1.0 + (1.0 - headerScaleTransition) * minHeaderScale
let headerScale = headerScaleTransition * maxHeaderScale + (1.0 - headerScaleTransition) * minHeaderScale
let refreshSize = CGSize(width: 32.0, height: 32.0)
self.refreshNode.updateLayout(size: refreshSize)
transition.updateFrame(node: self.refreshNode, frame: CGRect(origin: CGPoint(x: floor((size.width - refreshSize.width) / 2.0), y: navigationHeight - 44.0 + floor((44.0 - refreshSize.height) / 2.0)), size: refreshSize))
if self.balance == nil {
transition.updateAlpha(node: self.refreshNode, alpha: 0.0)
transition.updateSublayerTransformScale(node: self.refreshNode, scale: 0.1)
self.refreshNode.visibility = false
} else if self.isRefreshing {
transition.updateAlpha(node: self.refreshNode, alpha: 1.0)
transition.updateSublayerTransformScale(node: self.refreshNode, scale: 1.0)
self.refreshNode.visibility = true
} else {
let refreshOffset: CGFloat = 20.0
let refreshScaleTransition: CGFloat = max(0.0, min(1.0, (offset - maxOffset) / refreshOffset))
transition.updateAlpha(node: self.refreshNode, alpha: refreshScaleTransition)
let refreshScale: CGFloat = refreshScaleTransition * 1.0 + (1.0 - refreshScaleTransition) * 0.1
transition.updateSublayerTransformScale(node: self.refreshNode, scale: refreshScale)
self.refreshNode.visibility = false
}
let balanceFrame = CGRect(origin: CGPoint(x: 0.0, y: headerY), size: balanceSize)
transition.updateFrame(node: self.balanceNode, frame: balanceFrame)
transition.updateSublayerTransformScale(node: self.balanceNode, scale: headerScale)
transition.updateFrameAdditive(node: self.balanceSubtitleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - balanceSubtitleSize.width) / 2.0), y: balanceFrame.midY + (balanceFrame.height / 2.0 * headerScale) + balanceSubtitleSpacing), size: balanceSubtitleSize))
let balanceSubtitleFrame = CGRect(origin: CGPoint(x: floor((size.width - balanceSubtitleSize.width) / 2.0), y: balanceFrame.midY + (balanceFrame.height / 2.0 * headerScale) + balanceSubtitleSpacing), size: balanceSubtitleSize)
transition.updateFrameAdditive(node: self.balanceSubtitleNode, frame: balanceSubtitleFrame)
let balanceTimestampFrame = CGRect(origin: CGPoint(x: floor((size.width - balanceTimestampSize.width) / 2.0), y: balanceSubtitleFrame.maxY + 2.0), size: balanceTimestampSize)
transition.updateFrameAdditive(node: self.balanceTimestampNode, frame: balanceTimestampFrame)
transition.updateAlpha(node: self.balanceTimestampNode, alpha: headerScaleTransition)
let headerHeight: CGFloat = 1000.0
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: effectiveOffset + 10.0 - headerHeight), size: CGSize(width: size.width, height: headerHeight)))
@@ -252,11 +358,13 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
}
}
if self.balance == nil {
self.balanceNode.balanceTextNode.isHidden = true
self.balanceNode.isHidden = true
self.balanceSubtitleNode.isHidden = true
self.balanceTimestampNode.isHidden = true
} else {
self.balanceNode.balanceTextNode.isHidden = false
self.balanceNode.isHidden = false
self.balanceSubtitleNode.isHidden = false
self.balanceTimestampNode.isHidden = false
}
transition.updateFrame(node: self.receiveButtonNode, frame: receiveButtonFrame)
transition.updateAlpha(node: self.receiveButtonNode, alpha: buttonAlpha)
@@ -276,12 +384,19 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
return nil
}
func animateIn() {
self.sendButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.receiveButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
func becameReady(animated: Bool) {
if animated {
self.sendButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.receiveButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.balanceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.balanceSubtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.balanceTimestampNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
self.balanceNode.isLoading = false
self.balanceNode.balanceTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.balanceSubtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
func animateBeganRefreshing() {
//self.refreshNode.layer.animate(from: 0.5 as NSNumber, to: 0.0 as NSNumber, keyPath: "transform.scale", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.2, delay: 0.0, removeOnCompletion: true, additive: true)
}
}
@@ -358,24 +473,34 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
private let address: String
private let openTransaction: (WalletTransaction) -> Void
private let hapticFeedback = HapticFeedback()
private let headerNode: WalletInfoHeaderNode
private let listNode: ListView
private let loadingIndicator: UIActivityIndicatorView
private var enqueuedTransactions: [WalletInfoListTransaction] = []
private var validLayout: (ContainerViewLayout, CGFloat)?
private let balanceDisposable = MetaDisposable()
private let stateDisposable = MetaDisposable()
private let transactionListDisposable = MetaDisposable()
private var listOffset: CGFloat?
private var reloadingState: Bool = false
private var loadingMoreTransactions: Bool = false
private var canLoadMoreTransactions: Bool = true
private var combinedState: CombinedWalletState?
private var currentEntries: [WalletInfoListEntry]?
private var isReady: Bool = false
let contentReady = Promise<Bool>()
private var didSetContentReady = false
private var updateTimestampTimer: SwiftSignalKit.Timer?
init(account: Account, tonContext: TonContext, presentationData: PresentationData, walletInfo: WalletInfo, address: String, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void, openTransaction: @escaping (WalletTransaction) -> Void) {
self.account = account
self.tonContext = tonContext
@@ -384,47 +509,50 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.address = address
self.openTransaction = openTransaction
self.headerNode = WalletInfoHeaderNode(theme: presentationData.theme, sendAction: sendAction, receiveAction: receiveAction)
self.headerNode = WalletInfoHeaderNode(account: account, theme: presentationData.theme, sendAction: sendAction, receiveAction: receiveAction)
self.listNode = ListView()
self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.listNode.isHidden = true
self.loadingIndicator = UIActivityIndicatorView(style: .whiteLarge)
super.init()
self.backgroundColor = .white
self.balanceDisposable.set((getWalletState(address: address, tonInstance: tonContext.instance)
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
}
strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.balance))
strongSelf.headerNode.balance = max(0, value.balance)
if let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate)
}
let wasReady = strongSelf.isReady
strongSelf.isReady = strongSelf.headerNode.balance != nil && strongSelf.currentEntries != nil
if strongSelf.isReady && !wasReady {
strongSelf.animateReadyIn()
}
}))
self.addSubnode(self.listNode)
self.addSubnode(self.headerNode)
self.view.addSubview(self.loadingIndicator)
var canBeginRefresh = true
var isScrolling = false
self.listNode.beganInteractiveDragging = {
isScrolling = true
}
self.listNode.endedInteractiveDragging = {
isScrolling = false
}
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, listTransition in
guard let strongSelf = self, let (layout, navigationHeight) = strongSelf.validLayout else {
return
}
let headerHeight: CGFloat = navigationHeight + 260.0
strongSelf.listOffset = offset
if strongSelf.isReady {
if !strongSelf.reloadingState && canBeginRefresh && isScrolling {
if offset >= headerHeight + 100.0 {
canBeginRefresh = false
strongSelf.headerNode.isRefreshing = true
strongSelf.headerNode.animateBeganRefreshing()
strongSelf.hapticFeedback.impact()
strongSelf.refreshTransactions()
}
}
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: offset, transition: listTransition)
}
}
@@ -436,12 +564,14 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
guard case let .known(value) = offset, value < 100.0 else {
return
}
if !strongSelf.loadingMoreTransactions && strongSelf.canLoadMoreTransactions {
if !strongSelf.loadingMoreTransactions && !strongSelf.reloadingState && strongSelf.canLoadMoreTransactions {
strongSelf.loadMoreTransactions()
}
}
self.listNode.didEndScrolling = { [weak self] in
canBeginRefresh = true
guard let strongSelf = self, let (_, navigationHeight) = strongSelf.validLayout else {
return
}
@@ -460,6 +590,26 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
}
self.refreshTransactions()
self.updateTimestampTimer = SwiftSignalKit.Timer(timeout: 1.0, repeat: true, completion: { [weak self] in
guard let strongSelf = self, let combinedState = strongSelf.combinedState, !strongSelf.reloadingState else {
return
}
let string = lastUpdateTimestampString(strings: strongSelf.presentationData.strings, dateTimeFormat: strongSelf.presentationData.dateTimeFormat, statusTimestamp: Int32(clamping: combinedState.timestamp), relativeTo: Int32(Date().timeIntervalSince1970))
if strongSelf.headerNode.timestampString != string {
strongSelf.headerNode.timestampString = string
if let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .immediate)
}
}
}, queue: .mainQueue())
self.updateTimestampTimer?.start()
}
deinit {
self.stateDisposable.dispose()
self.transactionListDisposable.dispose()
self.updateTimestampTimer?.invalidate()
}
func scrollToHideHeader() {
@@ -477,6 +627,9 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
let isFirstLayout = self.validLayout == nil
self.validLayout = (layout, navigationHeight)
let indicatorSize = self.loadingIndicator.bounds.size
self.loadingIndicator.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - indicatorSize.width) / 2.0), y: floor((layout.size.height - indicatorSize.height) / 2.0)), size: indicatorSize)
let headerHeight: CGFloat = navigationHeight + 260.0
let topInset: CGFloat = headerHeight
@@ -531,13 +684,73 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
private func refreshTransactions() {
self.transactionListDisposable.set(nil)
self.loadingMoreTransactions = true
self.reloadingState = true
self.transactionListDisposable.set((getWalletTransactions(address: self.address, previousId: nil, tonInstance: self.tonContext.instance)
|> deliverOnMainQueue).start(next: { [weak self] transactions in
self.headerNode.timestampString = "updating"
self.stateDisposable.set((getCombinedWalletState(postbox: self.account.postbox, walletInfo: self.walletInfo, tonInstance: self.tonContext.instance)
|> delay(self.combinedState == nil ? 0.0 : 2.0, queue: .mainQueue())
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
}
strongSelf.transactionsLoaded(isReload: true, transactions: transactions)
let combinedState: CombinedWalletState?
switch value {
case let .cached(state):
if state == nil {
strongSelf.loadingIndicator.startAnimating()
} else {
strongSelf.loadingIndicator.stopAnimating()
strongSelf.loadingIndicator.isHidden = true
}
combinedState = state
case let .updated(state):
strongSelf.loadingIndicator.stopAnimating()
strongSelf.loadingIndicator.isHidden = true
combinedState = state
}
strongSelf.combinedState = combinedState
if let combinedState = combinedState {
strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, combinedState.walletState.balance))
strongSelf.headerNode.balance = max(0, combinedState.walletState.balance)
if strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate)
}
strongSelf.reloadingState = false
strongSelf.headerNode.timestampString = lastUpdateTimestampString(strings: strongSelf.presentationData.strings, dateTimeFormat: strongSelf.presentationData.dateTimeFormat, statusTimestamp: Int32(clamping: combinedState.timestamp), relativeTo: Int32(Date().timeIntervalSince1970))
if strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .immediate)
}
strongSelf.transactionsLoaded(isReload: true, transactions: combinedState.topTransactions)
strongSelf.headerNode.isRefreshing = false
if strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut))
}
let wasReady = strongSelf.isReady
strongSelf.isReady = strongSelf.combinedState != nil
if strongSelf.isReady && !wasReady {
if let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: layout.size.height, transition: .immediate)
}
strongSelf.becameReady(animated: strongSelf.didSetContentReady)
}
}
if !strongSelf.didSetContentReady {
strongSelf.didSetContentReady = true
strongSelf.contentReady.set(.single(true))
}
}, error: { [weak self] _ in
guard let strongSelf = self else {
return
@@ -576,12 +789,14 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.loadingMoreTransactions = false
self.canLoadMoreTransactions = transactions.count > 2
let isFirst = self.currentEntries == nil
var updatedEntries: [WalletInfoListEntry] = []
if isReload {
var existingIds = Set<WalletTransactionId>()
for transaction in transactions {
updatedEntries.append(.transaction(updatedEntries.count, transaction))
if !existingIds.contains(transaction.transactionId) {
existingIds.insert(transaction.transactionId)
updatedEntries.append(.transaction(updatedEntries.count, transaction))
}
}
if updatedEntries.isEmpty {
updatedEntries.append(.empty(self.address))
@@ -625,13 +840,6 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.enqueuedTransactions.append(transaction)
self.dequeueTransaction()
let wasReady = self.isReady
self.isReady = self.headerNode.balance != nil && self.currentEntries != nil
if self.isReady && !wasReady {
self.animateReadyIn()
}
}
private func dequeueTransaction() {
@@ -650,11 +858,13 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
})
}
private func animateReadyIn() {
private func becameReady(animated: Bool) {
self.listNode.isHidden = false
self.headerNode.animateIn()
self.loadingIndicator.stopAnimating()
self.loadingIndicator.isHidden = true
self.headerNode.becameReady(animated: animated)
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring))
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: animated ? .animated(duration: 0.5, curve: .spring) : .immediate)
}
}
}