Skip to content

Commit

Permalink
[484] account storage alert (#525)
Browse files Browse the repository at this point in the history
484 Account storage alert
- Extracted a reusable `StorageUsageView` from `WalletSettingView`
- Added the `StorageUsageView` to `TokenDetailView`
- Added `getAccountInfo` cadence
- Handled the `insufficientStorage` case in the remote config to display an insufficient storage alert
- Fixed bug causing `getAccountInfo()` to fail right after launching the app
- Added system-wide popup to notify the user about storage transaction failure
- Refactored `AlertView` to allow for injected custom content
- Created `PersistentToastView`
- Added storage usage progress in TokenDetailView
- Added storage warning to move/send token/nft views
- Implemented generic and reusable `InsufficientStorageToastView` as a drop-in specifically for showing the insufficient warning
- Refactored the alert view, wrapped in a UIHostincController and injected in the presented view controller
  • Loading branch information
jeden authored Nov 27, 2024
1 parent 184709e commit f41c578
Show file tree
Hide file tree
Showing 56 changed files with 1,310 additions and 301 deletions.
32 changes: 31 additions & 1 deletion FRW.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,16 @@
4EFF94C52AEEDD0A00365EF7 /* IPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EFF94C32AEEDD0A00365EF7 /* IPResponse.swift */; };
4EFF94C72AEEE5DD00365EF7 /* DevicesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EFF94C62AEEE5DD00365EF7 /* DevicesViewModel.swift */; };
4EFF94C82AEEE5DD00365EF7 /* DevicesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EFF94C62AEEE5DD00365EF7 /* DevicesViewModel.swift */; };
571A806D2CF54C12009112EE /* InsufficientStorageAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 571A806C2CF54C12009112EE /* InsufficientStorageAlert.swift */; };
571A806E2CF54C12009112EE /* InsufficientStorageAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 571A806C2CF54C12009112EE /* InsufficientStorageAlert.swift */; };
573429B62CDC4B2E00BDE016 /* AccountModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573429B52CDC4B2E00BDE016 /* AccountModels.swift */; };
573429B72CDC4B2E00BDE016 /* AccountModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573429B52CDC4B2E00BDE016 /* AccountModels.swift */; };
576F9E5A2CDB28590038E9CA /* StorageUsageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 576F9E592CDB28590038E9CA /* StorageUsageView.swift */; };
576F9E5B2CDB28590038E9CA /* StorageUsageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 576F9E592CDB28590038E9CA /* StorageUsageView.swift */; };
57ACE9AE2CE17901004DCA3E /* PersistentToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ACE9AD2CE17901004DCA3E /* PersistentToastView.swift */; };
57ACE9AF2CE17901004DCA3E /* PersistentToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ACE9AD2CE17901004DCA3E /* PersistentToastView.swift */; };
57E9AB772CE40B2600F04CE5 /* InsufficientStorageToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E9AB762CE40B2600F04CE5 /* InsufficientStorageToastView.swift */; };
57E9AB782CE40B2600F04CE5 /* InsufficientStorageToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E9AB762CE40B2600F04CE5 /* InsufficientStorageToastView.swift */; };
57999B7C2CF4267400C342D7 /* Helper+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57999B7B2CF4267400C342D7 /* Helper+Extensions.swift */; };
57999B7D2CF4267400C342D7 /* Helper+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57999B7B2CF4267400C342D7 /* Helper+Extensions.swift */; };
6A0137662897E7A0009BEF20 /* HalfSheetModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0137652897E7A0009BEF20 /* HalfSheetModal.swift */; };
Expand Down Expand Up @@ -2578,6 +2588,11 @@
4EFF94C02AEEDC1C00365EF7 /* FRWAPI+IP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FRWAPI+IP.swift"; sourceTree = "<group>"; };
4EFF94C32AEEDD0A00365EF7 /* IPResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPResponse.swift; sourceTree = "<group>"; };
4EFF94C62AEEE5DD00365EF7 /* DevicesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesViewModel.swift; sourceTree = "<group>"; };
571A806C2CF54C12009112EE /* InsufficientStorageAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsufficientStorageAlert.swift; sourceTree = "<group>"; };
573429B52CDC4B2E00BDE016 /* AccountModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModels.swift; sourceTree = "<group>"; };
576F9E592CDB28590038E9CA /* StorageUsageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageUsageView.swift; sourceTree = "<group>"; };
57ACE9AD2CE17901004DCA3E /* PersistentToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentToastView.swift; sourceTree = "<group>"; };
57E9AB762CE40B2600F04CE5 /* InsufficientStorageToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsufficientStorageToastView.swift; sourceTree = "<group>"; };
57999B7B2CF4267400C342D7 /* Helper+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Helper+Extensions.swift"; sourceTree = "<group>"; };
6A0137652897E7A0009BEF20 /* HalfSheetModal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HalfSheetModal.swift; sourceTree = "<group>"; };
6A06CB0528AA25F400C81BE1 /* NFTUIKitListDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NFTUIKitListDataSource.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4602,6 +4617,9 @@
4E9D8F1D2BF87A0400E11CC7 /* TitleWithClosedView.swift */,
4EAFBD802C1051D00031EA20 /* CircularProgressView.swift */,
4E5F2F242C1AF398008589C4 /* PresentHostingController.swift */,
576F9E592CDB28590038E9CA /* StorageUsageView.swift */,
57ACE9AD2CE17901004DCA3E /* PersistentToastView.swift */,
57E9AB762CE40B2600F04CE5 /* InsufficientStorageToastView.swift */,
);
path = Component;
sourceTree = "<group>";
Expand Down Expand Up @@ -5507,6 +5525,7 @@
isa = PBXGroup;
children = (
6A4BFE2F2893CA5500142113 /* AlertView.swift */,
571A806C2CF54C12009112EE /* InsufficientStorageAlert.swift */,
);
path = AlertView;
sourceTree = "<group>";
Expand Down Expand Up @@ -5829,6 +5848,7 @@
6AAD4E6828BC6E9900AEAB1F /* TransactionModels.swift */,
6AC476E728F3C993008503E6 /* WebBookmark.swift */,
6A2C560A290BE46800306A6C /* Currency.swift */,
573429B52CDC4B2E00BDE016 /* AccountModels.swift */,
15DFD34B2CE197F9004B0DB8 /* AppExternalLinks.swift */,
);
path = Model;
Expand Down Expand Up @@ -6823,6 +6843,7 @@
15DC20BF27819C56000B187A /* VSquareButtonState.swift in Sources */,
6A8FA49A285B192800EE5BE3 /* SnapAnchorPreferenceKey.swift in Sources */,
15DC217527819C56000B187A /* VDialogButtonModel.swift in Sources */,
57E9AB782CE40B2600F04CE5 /* InsufficientStorageToastView.swift in Sources */,
158832EB28942F8500142B35 /* serviceDefinition.swift in Sources */,
156E84AE281CDF4F00415896 /* WalletModels.swift in Sources */,
4E5054222C33DB1F00D4BA56 /* AppConfig.swift in Sources */,
Expand Down Expand Up @@ -7070,6 +7091,7 @@
4EE6FA8A2B19677B006A827B /* SyncConfirmViewModel.swift in Sources */,
6A73BF5328C59029004B836A /* JSMessageHandler.swift in Sources */,
6A16F19428B8B1AC0055936E /* TransactionHolderView.swift in Sources */,
571A806E2CF54C12009112EE /* InsufficientStorageAlert.swift in Sources */,
4EAFBD822C1051D00031EA20 /* CircularProgressView.swift in Sources */,
154B8908276A1EEB00780E93 /* ColorBook.swift in Sources */,
1565FB9028B15D890086A652 /* LottieView.swift in Sources */,
Expand Down Expand Up @@ -7208,6 +7230,7 @@
1588330D28943D1D00142B35 /* SPQRCameraController.swift in Sources */,
15DC21A727819C56000B187A /* VBaseTextField.swift in Sources */,
6A0137672897E7A0009BEF20 /* HalfSheetModal.swift in Sources */,
57ACE9AF2CE17901004DCA3E /* PersistentToastView.swift in Sources */,
1575A73528B286DA00ADC513 /* LottieButton.swift in Sources */,
15DC210727819C56000B187A /* VSliderState.swift in Sources */,
6AFE1D062A384E3000824D5C /* AccountSwitchView.swift in Sources */,
Expand Down Expand Up @@ -7267,6 +7290,7 @@
15DC212D27819C56000B187A /* VWheelPicker.swift in Sources */,
15DC20EB27819C56000B187A /* VAccordionLayoutType.swift in Sources */,
15DC218527819C56000B187A /* VToggleModel.swift in Sources */,
576F9E5A2CDB28590038E9CA /* StorageUsageView.swift in Sources */,
6A164F6C2845F1CB0026B31E /* Indexable.swift in Sources */,
6AEF839C28647B830081E285 /* FRWAPI+Crypto.swift in Sources */,
4EB2C6B72B4947DF00EB899C /* MultiBackupiCloudTarget.swift in Sources */,
Expand Down Expand Up @@ -7462,6 +7486,7 @@
4E09A1EB2CC793FE0099606E /* EventTrack.swift in Sources */,
6A29114D28CB37E8003295BD /* TransferListHandler.swift in Sources */,
4EC97653286A07060066811D /* NFTCollectionEnableView.swift in Sources */,
573429B62CDC4B2E00BDE016 /* AccountModels.swift in Sources */,
6AE4605F286ED142009C2B96 /* TokenDetailViewModel.swift in Sources */,
15DC209327819C56000B187A /* VToast.swift in Sources */,
15DC21CD27819C56000B187A /* SliderHelpers.swift in Sources */,
Expand Down Expand Up @@ -7621,6 +7646,7 @@
15C58AD22868A4EE00BD4FC6 /* VSquareButtonState.swift in Sources */,
15C58AD32868A4EE00BD4FC6 /* SnapAnchorPreferenceKey.swift in Sources */,
15C58AD42868A4EE00BD4FC6 /* VDialogButtonModel.swift in Sources */,
57E9AB772CE40B2600F04CE5 /* InsufficientStorageToastView.swift in Sources */,
158832EA28942F8500142B35 /* serviceDefinition.swift in Sources */,
15C58AD52868A4EE00BD4FC6 /* WalletModels.swift in Sources */,
4E5054212C33DB1F00D4BA56 /* AppConfig.swift in Sources */,
Expand Down Expand Up @@ -7868,6 +7894,7 @@
6A16F19328B8B1AC0055936E /* TransactionHolderView.swift in Sources */,
15C58B532868A4EE00BD4FC6 /* ColorBook.swift in Sources */,
1565FB8F28B15D890086A652 /* LottieView.swift in Sources */,
571A806D2CF54C12009112EE /* InsufficientStorageAlert.swift in Sources */,
4EAFBD812C1051D00031EA20 /* CircularProgressView.swift in Sources */,
15D874E328C5D37F0072C6EA /* MatrixView.swift in Sources */,
4E42DC5F2B22AEB700EF0A75 /* BackupListView.swift in Sources */,
Expand Down Expand Up @@ -8006,6 +8033,7 @@
6A0137662897E7A0009BEF20 /* HalfSheetModal.swift in Sources */,
1575A73428B286DA00ADC513 /* LottieButton.swift in Sources */,
15C58B9C2868A4EE00BD4FC6 /* VSliderState.swift in Sources */,
57ACE9AE2CE17901004DCA3E /* PersistentToastView.swift in Sources */,
15C58B9D2868A4EE00BD4FC6 /* VMenuButtonType.swift in Sources */,
6AFE1D052A384E3000824D5C /* AccountSwitchView.swift in Sources */,
158832E128942D5800142B35 /* RequestInfo.swift in Sources */,
Expand Down Expand Up @@ -8065,6 +8093,7 @@
15C58BB32868A4EE00BD4FC6 /* VToggleModel.swift in Sources */,
15C58BB42868A4EE00BD4FC6 /* Indexable.swift in Sources */,
15C58BB52868A4EE00BD4FC6 /* FRWAPI+Crypto.swift in Sources */,
576F9E5B2CDB28590038E9CA /* StorageUsageView.swift in Sources */,
15C58BB62868A4EE00BD4FC6 /* VDialogButton.swift in Sources */,
4EB2C6B62B4947DF00EB899C /* MultiBackupiCloudTarget.swift in Sources */,
15C58BB72868A4EE00BD4FC6 /* StateOpacities_P.swift in Sources */,
Expand Down Expand Up @@ -8260,6 +8289,7 @@
4E09A1EA2CC793FE0099606E /* EventTrack.swift in Sources */,
6A29114C28CB37E8003295BD /* TransferListHandler.swift in Sources */,
4EC97652286A07060066811D /* NFTCollectionEnableView.swift in Sources */,
573429B72CDC4B2E00BDE016 /* AccountModels.swift in Sources */,
6AE4605E286ED142009C2B96 /* TokenDetailViewModel.swift in Sources */,
15C58C1F2868A4EE00BD4FC6 /* VToast.swift in Sources */,
15C58C202868A4EE00BD4FC6 /* SliderHelpers.swift in Sources */,
Expand Down Expand Up @@ -9465,7 +9495,7 @@
repositoryURL = "https://github.com/outblock/flow-swift";
requirement = {
kind = exactVersion;
version = 0.3.8;
version = 0.3.9;
};
};
15F517F928C6574C00504FDC /* XCRemoteSwiftPackageReference "atlantis" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/outblock/flow-swift",
"state" : {
"revision" : "bbe28ecf73e18e5fe5c5f7dd4b35c3577f7d5558",
"version" : "0.3.8"
"revision" : "50b60826c4ce18adaa151946d11d468ac1fc98dd",
"version" : "0.3.9"
}
},
{
Expand Down
54 changes: 27 additions & 27 deletions FRW/Foundation/Define/NotificationDefine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,41 @@

import Foundation

extension Notification.Name {
public static let walletHiddenFlagUpdated = Notification.Name("walletHiddenFlagUpdated")
public static let quoteMarketUpdated = Notification.Name("quoteMarketUpdated")
public static let coinSummarysUpdated = Notification.Name("coinSummarysUpdated")
public static let addressBookDidAdd = Notification.Name("addressBookDidAdd")
public static let addressBookDidEdit = Notification.Name("addressBookDidEdit")
public static let backupTypeDidChanged = Notification.Name("backupTypeDidChanged")
public static let nftFavDidChanged = Notification.Name("nftFavDidChanged")
public static let nftCollectionsDidChanged = Notification.Name("nftCollectionsDidChanged")
public static let nftCacheDidChanged = Notification.Name("nftCacheDidChanged")
public extension Notification.Name {
static let walletHiddenFlagUpdated = Notification.Name("walletHiddenFlagUpdated")
static let quoteMarketUpdated = Notification.Name("quoteMarketUpdated")
static let coinSummarysUpdated = Notification.Name("coinSummarysUpdated")
static let addressBookDidAdd = Notification.Name("addressBookDidAdd")
static let addressBookDidEdit = Notification.Name("addressBookDidEdit")
static let backupTypeDidChanged = Notification.Name("backupTypeDidChanged")
static let nftFavDidChanged = Notification.Name("nftFavDidChanged")
static let nftCollectionsDidChanged = Notification.Name("nftCollectionsDidChanged")
static let nftCacheDidChanged = Notification.Name("nftCacheDidChanged")

public static let transactionManagerDidChanged = Notification
.Name("transactionManagerDidChanged")
public static let transactionStatusDidChanged = Notification.Name("transactionStatusDidChanged")
static let transactionManagerDidChanged = Notification.Name("transactionManagerDidChanged")
static let transactionStatusDidChanged = Notification.Name("transactionStatusDidChanged")

public static let transactionCountDidChanged = Notification.Name("transactionCountDidChanged")
static let transactionCountDidChanged = Notification.Name("transactionCountDidChanged")

public static let watchAddressDidChanged = Notification.Name("watchAddressDidChanged")
static let watchAddressDidChanged = Notification.Name("watchAddressDidChanged")

public static let webBookmarkDidChanged = Notification.Name("webBookmarkDidChanged")
public static let willResetWallet = Notification.Name("willResetWallet")
public static let didResetWallet = Notification.Name("didResetWallet")
public static let didFinishAccountLogin = Notification.Name("didFinishedAccountLogin")
static let webBookmarkDidChanged = Notification.Name("webBookmarkDidChanged")
static let willResetWallet = Notification.Name("willResetWallet")
static let didResetWallet = Notification.Name("didResetWallet")
static let didFinishAccountLogin = Notification.Name("didFinishedAccountLogin")

public static let networkChange = Notification.Name("networkChange")
static let networkChange = Notification.Name("networkChange")

public static let openNFTCollectionList = Notification.Name("openNFTCollectionList")
public static let toggleSideMenu = Notification.Name("toggleSideMenu")
static let openNFTCollectionList = Notification.Name("openNFTCollectionList")
static let toggleSideMenu = Notification.Name("toggleSideMenu")

public static let nftCountChanged = Notification.Name("nftCountChanged")
public static let childAccountChanged = Notification.Name("childAccountChanged")
static let nftCountChanged = Notification.Name("nftCountChanged")
static let childAccountChanged = Notification.Name("childAccountChanged")

public static let syncDeviceStatusDidChanged = Notification.Name("syncDeviceStatusDidChanged")
static let syncDeviceStatusDidChanged = Notification.Name("syncDeviceStatusDidChanged")

public static let nftDidChangedByMoving = Notification.Name("nftDidChangedByMoving")
static let nftDidChangedByMoving = Notification.Name("nftDidChangedByMoving")

public static let remoteConfigDidUpdate = Notification.Name("remoteConfigDidUpdate")
static let remoteConfigDidUpdate = Notification.Name("remoteConfigDidUpdate")
static let accountDataDidUpdate = Notification.Name("accountDataDidUpdate")
}
47 changes: 47 additions & 0 deletions FRW/Foundation/Model/AccountModels.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// AccountModels.swift
// FRW
//
// Created by Antonio Bello on 11/7/24.
//

import Foundation
import Flow

extension Flow {
struct AccountInfo: Decodable {
public let address: Flow.Address
public let balance: Decimal
public let availableBalance: Decimal
public let storageUsed: UInt64
public let storageCapacity: UInt64
public let storageFlow: Decimal
}
}

extension Flow.AccountInfo {
var storageUsedRatio: Double {
guard self.storageCapacity > 0 else { return 0 }
let ratio = Double(self.storageUsed) / Double(self.storageCapacity)
return min(1, max(0, ratio))
}

var storageUsedString: String {
let usedStr = humanReadableByteCount(bytes: self.storageUsed)
let capacityStr = humanReadableByteCount(bytes: self.storageCapacity)
return "\(usedStr) / \(capacityStr)"
}

private func humanReadableByteCount(bytes: UInt64) -> String {
if bytes < 1024 { return "\(bytes) B" }
let exp = Int(log2(Double(bytes)) / log2(1024.0))
let unit = ["KB", "MB", "GB", "TB", "PB", "EB"][exp - 1]
let number = Double(bytes) / pow(1024, Double(exp))
if exp <= 1 || number >= 100 {
return String(format: "%.0f %@", number, unit)
} else {
return String(format: "%.1f %@", number, unit)
.replacingOccurrences(of: ".0", with: "")
}
}
}
1 change: 1 addition & 0 deletions FRW/Foundation/Model/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum LLError: Error {
case accountNotFound
case fetchUserInfoFailed
case invalidAddress
case invalidCadence
case signFailed
case decodeFailed
case unknown
Expand Down
9 changes: 7 additions & 2 deletions FRW/Modules/Browser/View/BrowserAuthzView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,13 @@ struct BrowserAuthzView: View {
}

var actionView: some View {
WalletSendButtonView(allowEnable: .constant(true)) {
vm.didChooseAction(true)
VStack(spacing: 0) {
InsufficientStorageToastView<BrowserAuthzViewModel>()
.environmentObject(self.vm)

WalletSendButtonView(allowEnable: .constant(true)) {
vm.didChooseAction(true)
}
}
}

Expand Down
Loading

0 comments on commit f41c578

Please sign in to comment.