From cdc63d7d2e05e252b9d918e06e8117d02857f7c7 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 14 Apr 2024 12:51:09 -0400 Subject: [PATCH 1/2] REF: Reorganize Swift code as it was a bigger mess --- ios/BlueWallet.xcodeproj/project.pbxproj | 234 ++++++++++++++---- .../xcschemes/PriceWidget.xcscheme | 2 +- .../xcshareddata/swiftpm/Package.resolved | 2 +- .../ExtensionDelegate.swift | 2 +- .../Objects/BitcoinUnit.swift | 15 ++ .../Objects/CurrencyConverter.swift | 35 +++ .../Bundle+decode.swift} | 19 +- ios/{Widgets => }/Shared/Colors.swift | 0 ios/Shared/Currency.swift | 57 +++++ ios/Shared/Fiat/FiatUnit.swift | 20 ++ .../Fiat}/XMLParserDelegate.swift | 0 ios/Shared/LatestTransaction.swift | 14 ++ .../MarketAPI+Electrum.swift} | 6 +- ios/Shared/MarketAPI.swift | 199 +++++++++++++++ ios/Shared/MarketData.swift | 37 +++ ios/Shared/Numeric+abbreviated.swift | 27 ++ ios/Shared/Placeholders.swift | 16 ++ .../Shared/UserDefaultsExtension.swift | 0 .../Shared/UserDefaultsGroup.swift | 0 ios/Shared/UserDefaultsGroupKey.swift | 20 ++ ios/Shared/WalletData.swift | 27 ++ ios/Shared/WidgetData.swift | 22 ++ ios/Shared/WidgetDataStore.swift | 62 +++++ .../WalletInformationWidget.swift | 4 +- ios/Widgets/MarketWidget/MarketWidget.swift | 4 +- ios/Widgets/PriceWidget/PriceWidget.swift | 8 +- ios/Widgets/Shared/Models.swift | 74 ------ ios/Widgets/Shared/Views/MarketView.swift | 2 +- .../Shared/Views/WalletInformationView.swift | 2 +- ios/Widgets/Shared/WidgetAPI.swift | 218 ---------------- ios/Widgets/Shared/WidgetDataStore.swift | 86 ------- .../WalletInformationAndMarketWidget.swift | 4 +- 32 files changed, 763 insertions(+), 455 deletions(-) create mode 100644 ios/BlueWalletWatch Extension/Objects/BitcoinUnit.swift create mode 100644 ios/BlueWalletWatch Extension/Objects/CurrencyConverter.swift rename ios/{Widgets/Shared/Fiat/FiatUnit.swift => Shared/Bundle+decode.swift} (79%) rename ios/{Widgets => }/Shared/Colors.swift (100%) create mode 100644 ios/Shared/Currency.swift create mode 100644 ios/Shared/Fiat/FiatUnit.swift rename ios/{Widgets/Shared => Shared/Fiat}/XMLParserDelegate.swift (100%) create mode 100644 ios/Shared/LatestTransaction.swift rename ios/{Widgets/Shared/WidgetAPI+Electrum.swift => Shared/MarketAPI+Electrum.swift} (96%) create mode 100644 ios/Shared/MarketAPI.swift create mode 100644 ios/Shared/MarketData.swift create mode 100644 ios/Shared/Numeric+abbreviated.swift create mode 100644 ios/Shared/Placeholders.swift rename ios/{Widgets => }/Shared/UserDefaultsExtension.swift (100%) rename ios/{Widgets => }/Shared/UserDefaultsGroup.swift (100%) create mode 100644 ios/Shared/UserDefaultsGroupKey.swift create mode 100644 ios/Shared/WalletData.swift create mode 100644 ios/Shared/WidgetData.swift create mode 100644 ios/Shared/WidgetDataStore.swift delete mode 100644 ios/Widgets/Shared/Models.swift delete mode 100644 ios/Widgets/Shared/WidgetAPI.swift delete mode 100644 ios/Widgets/Shared/WidgetDataStore.swift diff --git a/ios/BlueWallet.xcodeproj/project.pbxproj b/ios/BlueWallet.xcodeproj/project.pbxproj index 62795cf36..c1a368b37 100644 --- a/ios/BlueWallet.xcodeproj/project.pbxproj +++ b/ios/BlueWallet.xcodeproj/project.pbxproj @@ -15,9 +15,8 @@ 6D2A6464258BA92D0092292B /* Stickers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6D2A6463258BA92D0092292B /* Stickers.xcassets */; }; 6D2A6468258BA92D0092292B /* Stickers.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6D2A6461258BA92C0092292B /* Stickers.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 6D32C5C62596CE3A008C077C /* EventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D32C5C52596CE3A008C077C /* EventEmitter.m */; }; - 6D4AF15925D21172009DD853 /* WidgetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */; }; - 6D4AF16325D21185009DD853 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */; }; - 6D4AF16D25D21192009DD853 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Models.swift */; }; + 6D4AF15925D21172009DD853 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; }; + 6D4AF16D25D21192009DD853 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; }; 6D4AF17825D211A3009DD853 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; }; 6D4AF18425D215D1009DD853 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; }; 6DD4109D266CADF10087DE03 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D333B3A252FE1A3004D72DF /* WidgetKit.framework */; }; @@ -25,14 +24,12 @@ 6DD410A1266CADF10087DE03 /* Widgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD410A0266CADF10087DE03 /* Widgets.swift */; }; 6DD410A7266CADF40087DE03 /* WidgetsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6DD4109C266CADF10087DE03 /* WidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 6DD410AC266CAE470087DE03 /* PriceWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA4BC255872E3009312A5 /* PriceWidget.swift */; }; - 6DD410AE266CAF1F0087DE03 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; }; 6DD410AF266CAF5C0087DE03 /* WalletInformationAndMarketWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E06254BA347007B5B82 /* WalletInformationAndMarketWidget.swift */; }; 6DD410B0266CAF5C0087DE03 /* WalletInformationWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4AB1254FB59C00E9F9AA /* WalletInformationWidget.swift */; }; - 6DD410B1266CAF5C0087DE03 /* WidgetAPI+Electrum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */; }; + 6DD410B1266CAF5C0087DE03 /* MarketAPI+Electrum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */; }; 6DD410B2266CAF5C0087DE03 /* WalletInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F2225525053003792DF /* WalletInformationView.swift */; }; 6DD410B3266CAF5C0087DE03 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; }; - 6DD410B4266CAF5C0087DE03 /* WidgetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */; }; - 6DD410B5266CAF5C0087DE03 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */; }; + 6DD410B4266CAF5C0087DE03 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; }; 6DD410B6266CAF5C0087DE03 /* PriceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA5272558EC52009312A5 /* PriceView.swift */; }; 6DD410B7266CAF5C0087DE03 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6D9A2E08254BA348007B5B82 /* Assets.xcassets */; }; 6DD410B8266CAF5C0087DE03 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; }; @@ -40,7 +37,7 @@ 6DD410BA266CAF5C0087DE03 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; }; 6DD410BB266CAF5C0087DE03 /* MarketView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F17255226DA003792DF /* MarketView.swift */; }; 6DD410BE266CAF5C0087DE03 /* SendReceiveButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F3425526311003792DF /* SendReceiveButtons.swift */; }; - 6DD410BF266CB13D0087DE03 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Models.swift */; }; + 6DD410BF266CB13D0087DE03 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; }; 6DD410C0266CB1460087DE03 /* MarketWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9946622555A660000E52E8 /* MarketWidget.swift */; }; 6DF25A9F249DB97E001D06F5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6DF25A9E249DB97E001D06F5 /* LaunchScreen.storyboard */; }; 6DFC807024EA0B6C007B8700 /* EFQRCode in Frameworks */ = {isa = PBXBuildFile; productRef = 6DFC806F24EA0B6C007B8700 /* EFQRCode */; }; @@ -75,6 +72,70 @@ B43D037B225847C500FBAA95 /* TransactionTableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0375225847C500FBAA95 /* TransactionTableRow.swift */; }; B43D037C225847C500FBAA95 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0376225847C500FBAA95 /* Wallet.swift */; }; B43D037D225847C500FBAA95 /* WalletInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0377225847C500FBAA95 /* WalletInformation.swift */; }; + B44033BF2BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; + B44033C02BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; + B44033C12BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; + B44033C22BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; + B44033C42BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; + B44033C52BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; + B44033C62BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; + B44033C72BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; + B44033CA2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; + B44033CB2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; + B44033CC2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; + B44033CD2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; + B44033CE2BCC352900162242 /* UserDefaultsGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */; }; + B44033CF2BCC352C00162242 /* UserDefaultsGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */; }; + B44033D02BCC352F00162242 /* UserDefaultsGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */; }; + B44033D32BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; }; + B44033D42BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; }; + B44033D52BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; }; + B44033D62BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; }; + B44033D72BCC369400162242 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; }; + B44033D82BCC369500162242 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; }; + B44033D92BCC369900162242 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; }; + B44033DA2BCC369A00162242 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; }; + B44033DB2BCC369B00162242 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; }; + B44033DD2BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; }; + B44033DE2BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; }; + B44033DF2BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; }; + B44033E02BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; }; + B44033E12BCC36CA00162242 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; }; + B44033E22BCC36CB00162242 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; }; + B44033E42BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; }; + B44033E52BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; }; + B44033E62BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; }; + B44033E72BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; }; + B44033E92BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; }; + B44033EA2BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; }; + B44033EB2BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; }; + B44033EC2BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; }; + B44033EE2BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; }; + B44033EF2BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; }; + B44033F02BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; }; + B44033F12BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; }; + B44033F42BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; }; + B44033F52BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; }; + B44033F62BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; }; + B44033F72BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; }; + B44033F92BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; }; + B44033FA2BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; }; + B44033FB2BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; }; + B44033FC2BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; }; + B44033FD2BCC37D600162242 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; }; + B44033FE2BCC37D700162242 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; }; + B44034002BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; }; + B44034012BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; }; + B44034022BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; }; + B44034032BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; }; + B44034042BCC389100162242 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; }; + B44034052BCC389200162242 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; }; + B44034062BCC389F00162242 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; }; + B44034072BCC38A000162242 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; }; + B440340F2BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; }; + B44034102BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; }; + B44034112BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; }; + B44034122BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; }; B4549F362B82B10D002E3153 /* ci_post_clone.sh in Resources */ = {isa = PBXBuildFile; fileRef = B4549F352B82B10D002E3153 /* ci_post_clone.sh */; }; B461B852299599F800E431AA /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = B461B851299599F800E431AA /* AppDelegate.mm */; }; B47B21EC2B2128B8001F6690 /* BlueWalletUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B47B21EB2B2128B8001F6690 /* BlueWalletUITests.swift */; }; @@ -96,9 +157,7 @@ B4AB225E2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; }; B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; }; C59F90CE0D04D3E4BB39BC5D /* libPods-BlueWalletUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */; }; - C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; - E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; }; - E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; }; + C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -310,21 +369,19 @@ 6D641F2225525053003792DF /* WalletInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationView.swift; sourceTree = ""; }; 6D641F3425526311003792DF /* SendReceiveButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendReceiveButtons.swift; sourceTree = ""; }; 6D6CA4BC255872E3009312A5 /* PriceWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceWidget.swift; sourceTree = ""; }; - 6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WidgetAPI+Electrum.swift"; sourceTree = ""; }; + 6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarketAPI+Electrum.swift"; sourceTree = ""; }; 6D6CA5272558EC52009312A5 /* PriceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceView.swift; sourceTree = ""; }; 6D9946622555A660000E52E8 /* MarketWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketWidget.swift; sourceTree = ""; }; 6D9A2E06254BA347007B5B82 /* WalletInformationAndMarketWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationAndMarketWidget.swift; sourceTree = ""; }; 6D9A2E08254BA348007B5B82 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetAPI.swift; sourceTree = ""; }; - 6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = ""; }; + 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketAPI.swift; sourceTree = ""; }; 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroup.swift; sourceTree = ""; }; 6DD4109C266CADF10087DE03 /* WidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 6DD410A0266CADF10087DE03 /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = ""; }; 6DD410A4266CADF40087DE03 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = fiatUnits.json; path = ../../../../models/fiatUnits.json; sourceTree = ""; }; 6DD410C3266CCB780087DE03 /* WidgetsExtension.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = WidgetsExtension.entitlements; sourceTree = SOURCE_ROOT; }; 6DEB4AB1254FB59C00E9F9AA /* WalletInformationWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationWidget.swift; sourceTree = ""; }; - 6DEB4BFA254FBA0E00E9F9AA /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = ""; }; + 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Placeholders.swift; sourceTree = ""; }; 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; 6DF25A9E249DB97E001D06F5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 6DFC807124EA2FA9007B8700 /* ViewQRCodefaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewQRCodefaceController.swift; sourceTree = ""; }; @@ -375,6 +432,18 @@ B43D0376225847C500FBAA95 /* Wallet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = ""; }; B43D0377225847C500FBAA95 /* WalletInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletInformation.swift; sourceTree = ""; }; B43D046E22584C1B00FBAA95 /* libRNWatch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRNWatch.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B44033BE2BCC32F800162242 /* BitcoinUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinUnit.swift; sourceTree = ""; }; + B44033C32BCC332400162242 /* CurrencyConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyConverter.swift; sourceTree = ""; }; + B44033C92BCC350A00162242 /* Currency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = ""; }; + B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroupKey.swift; sourceTree = ""; }; + B44033DC2BCC36C300162242 /* LatestTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestTransaction.swift; sourceTree = ""; }; + B44033E32BCC36FF00162242 /* WalletData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletData.swift; sourceTree = ""; }; + B44033E82BCC371A00162242 /* MarketData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketData.swift; sourceTree = ""; }; + B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Numeric+abbreviated.swift"; sourceTree = ""; }; + B44033F32BCC377F00162242 /* WidgetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetData.swift; sourceTree = ""; }; + B44033F82BCC379200162242 /* WidgetDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = ""; }; + B44033FF2BCC37F800162242 /* Bundle+decode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+decode.swift"; sourceTree = ""; }; + B440340E2BCC40A400162242 /* fiatUnits.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = fiatUnits.json; path = ../../../models/fiatUnits.json; sourceTree = ""; }; B4549F352B82B10D002E3153 /* ci_post_clone.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = ci_post_clone.sh; sourceTree = ""; }; B461B850299599F800E431AA /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = BlueWallet/AppDelegate.h; sourceTree = ""; }; B461B851299599F800E431AA /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = BlueWallet/AppDelegate.mm; sourceTree = ""; }; @@ -412,7 +481,7 @@ files = ( 782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */, 764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */, - C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */, + C978A716948AB7DEC5B6F677 /* (null) in Frameworks */, 773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -567,7 +636,8 @@ 6D2AA8062568B8E50090B089 /* Fiat */ = { isa = PBXGroup; children = ( - 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */, + B440340E2BCC40A400162242 /* fiatUnits.json */, + B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */, 6D2AA8072568B8F40090B089 /* FiatUnit.swift */, ); path = Fiat; @@ -625,16 +695,7 @@ 6DEB4BC1254FB98300E9F9AA /* Shared */ = { isa = PBXGroup; children = ( - B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */, - 6D2AA8062568B8E50090B089 /* Fiat */, 6DEB4DD82552260200E9F9AA /* Views */, - 6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */, - 6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */, - 6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */, - 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */, - 6DEB4BFA254FBA0E00E9F9AA /* Models.swift */, - 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */, - 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */, 6D4AF18225D215D0009DD853 /* BlueWalletWatch-Bridging-Header.h */, B40FC3F829CCD1AC0007EBAC /* SwiftTCPClient.swift */, ); @@ -655,6 +716,7 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + B44033C82BCC34AC00162242 /* Shared */, B41C2E552BB3DCB8000FE097 /* PrivacyInfo.xcprivacy */, B4549F2E2B80FEA1002E3153 /* ci_scripts */, 13B07FAE1A68108700A75B9A /* BlueWallet */, @@ -762,10 +824,35 @@ B43D0377225847C500FBAA95 /* WalletInformation.swift */, B43D0373225847C500FBAA95 /* WatchDataSource.swift */, 849047C92702A32A008EE567 /* Handoff.swift */, + B44033BE2BCC32F800162242 /* BitcoinUnit.swift */, + B44033C32BCC332400162242 /* CurrencyConverter.swift */, ); path = Objects; sourceTree = ""; }; + B44033C82BCC34AC00162242 /* Shared */ = { + isa = PBXGroup; + children = ( + 6D2AA8062568B8E50090B089 /* Fiat */, + 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */, + 6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */, + B44033C92BCC350A00162242 /* Currency.swift */, + 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */, + 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */, + 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */, + B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */, + B44033DC2BCC36C300162242 /* LatestTransaction.swift */, + B44033E32BCC36FF00162242 /* WalletData.swift */, + B44033E82BCC371A00162242 /* MarketData.swift */, + B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */, + B44033F32BCC377F00162242 /* WidgetData.swift */, + B44033F82BCC379200162242 /* WidgetDataStore.swift */, + B44033FF2BCC37F800162242 /* Bundle+decode.swift */, + 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */, + ); + path = Shared; + sourceTree = ""; + }; B4549F2E2B80FEA1002E3153 /* ci_scripts */ = { isa = PBXGroup; children = ( @@ -1037,7 +1124,7 @@ ); mainGroup = 83CBB9F61A601CBA00E9B192; packageReferences = ( - 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */, + 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */, B41B76832B66B2FF002C48D5 /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */, ); productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; @@ -1061,6 +1148,7 @@ buildActionMask = 2147483647; files = ( 6DF25A9F249DB97E001D06F5 /* LaunchScreen.storyboard in Resources */, + B440340F2BCC40A400162242 /* fiatUnits.json in Resources */, 84E05A842721191B001A0D3A /* Settings.bundle in Resources */, B4549F362B82B10D002E3153 /* ci_post_clone.sh in Resources */, B41C2E562BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */, @@ -1081,8 +1169,8 @@ buildActionMask = 2147483647; files = ( B41C2E582BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */, + B44034112BCC40A400162242 /* fiatUnits.json in Resources */, 6DD410B7266CAF5C0087DE03 /* Assets.xcassets in Resources */, - 6DD410AE266CAF1F0087DE03 /* fiatUnits.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1091,7 +1179,6 @@ buildActionMask = 2147483647; files = ( B40D4E36225841ED00428FCC /* Assets.xcassets in Resources */, - E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */, B40D4E34225841EC00428FCC /* Interface.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1101,8 +1188,8 @@ buildActionMask = 2147483647; files = ( B41C2E572BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */, + B44034102BCC40A400162242 /* fiatUnits.json in Resources */, B4EE583C226703320003363C /* Assets.xcassets in Resources */, - E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1118,6 +1205,7 @@ buildActionMask = 2147483647; files = ( B41C2E592BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */, + B44034122BCC40A400162242 /* fiatUnits.json in Resources */, B4A29A352B55C990002A67DF /* LaunchScreen.storyboard in Resources */, B4A29A372B55C990002A67DF /* Images.xcassets in Resources */, ); @@ -1420,12 +1508,30 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B44033E92BCC371A00162242 /* MarketData.swift in Sources */, + B44033CA2BCC350A00162242 /* Currency.swift in Sources */, B4AB21092B61DC3F0080440C /* SplashScreen.m in Sources */, + B44033EE2BCC374500162242 /* Numeric+abbreviated.swift in Sources */, B4AB21072B61D8CA0080440C /* SplashScreen.swift in Sources */, + B44033DD2BCC36C300162242 /* LatestTransaction.swift in Sources */, 6D32C5C62596CE3A008C077C /* EventEmitter.m in Sources */, + B44033FE2BCC37D700162242 /* MarketAPI.swift in Sources */, + B44033CE2BCC352900162242 /* UserDefaultsGroup.swift in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, B461B852299599F800E431AA /* AppDelegate.mm in Sources */, + B44033F42BCC377F00162242 /* WidgetData.swift in Sources */, + B44033C42BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44034072BCC38A000162242 /* FiatUnit.swift in Sources */, + B44034002BCC37F800162242 /* Bundle+decode.swift in Sources */, + B44033E22BCC36CB00162242 /* Placeholders.swift in Sources */, + B44033DA2BCC369A00162242 /* Colors.swift in Sources */, + B44033D32BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */, 32B5A32A2334450100F8D608 /* Bridge.swift in Sources */, + B44033D82BCC369500162242 /* UserDefaultsExtension.swift in Sources */, + B44033E42BCC36FF00162242 /* WalletData.swift in Sources */, + B44033BF2BCC32F800162242 /* BitcoinUnit.swift in Sources */, + B44034052BCC389200162242 /* XMLParserDelegate.swift in Sources */, + B44033F92BCC379200162242 /* WidgetDataStore.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1434,22 +1540,32 @@ buildActionMask = 2147483647; files = ( 6DD410BE266CAF5C0087DE03 /* SendReceiveButtons.swift in Sources */, - 6DD410B4266CAF5C0087DE03 /* WidgetAPI.swift in Sources */, + 6DD410B4266CAF5C0087DE03 /* MarketAPI.swift in Sources */, B40FC3FA29CCD1D00007EBAC /* SwiftTCPClient.swift in Sources */, 6DD410A1266CADF10087DE03 /* Widgets.swift in Sources */, 6DD410AC266CAE470087DE03 /* PriceWidget.swift in Sources */, + B44033D52BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */, 6DD410B2266CAF5C0087DE03 /* WalletInformationView.swift in Sources */, + B44034022BCC37F800162242 /* Bundle+decode.swift in Sources */, + B44033CC2BCC350A00162242 /* Currency.swift in Sources */, 6DD410B6266CAF5C0087DE03 /* PriceView.swift in Sources */, 6DD410B3266CAF5C0087DE03 /* Colors.swift in Sources */, + B44033C12BCC32F800162242 /* BitcoinUnit.swift in Sources */, 6DD410BB266CAF5C0087DE03 /* MarketView.swift in Sources */, - 6DD410B5266CAF5C0087DE03 /* WidgetDataStore.swift in Sources */, + B44033F02BCC374500162242 /* Numeric+abbreviated.swift in Sources */, + B44033DF2BCC36C300162242 /* LatestTransaction.swift in Sources */, 6DD410C0266CB1460087DE03 /* MarketWidget.swift in Sources */, B4AB225E2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */, + B44033F62BCC377F00162242 /* WidgetData.swift in Sources */, 6DD410BA266CAF5C0087DE03 /* FiatUnit.swift in Sources */, + B44033FB2BCC379200162242 /* WidgetDataStore.swift in Sources */, + B44033EB2BCC371A00162242 /* MarketData.swift in Sources */, 6DD410AF266CAF5C0087DE03 /* WalletInformationAndMarketWidget.swift in Sources */, - 6DD410BF266CB13D0087DE03 /* Models.swift in Sources */, + B44033C62BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44033E62BCC36FF00162242 /* WalletData.swift in Sources */, + 6DD410BF266CB13D0087DE03 /* Placeholders.swift in Sources */, 6DD410B0266CAF5C0087DE03 /* WalletInformationWidget.swift in Sources */, - 6DD410B1266CAF5C0087DE03 /* WidgetAPI+Electrum.swift in Sources */, + 6DD410B1266CAF5C0087DE03 /* MarketAPI+Electrum.swift in Sources */, 6DD410B9266CAF5C0087DE03 /* UserDefaultsGroup.swift in Sources */, 6DD410B8266CAF5C0087DE03 /* UserDefaultsExtension.swift in Sources */, ); @@ -1465,23 +1581,35 @@ 32F0A29A2311DBB20095C559 /* ComplicationController.swift in Sources */, B40D4E602258425500428FCC /* SpecifyInterfaceController.swift in Sources */, B43D0379225847C500FBAA95 /* WatchDataSource.swift in Sources */, + B44033D42BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */, + B44034012BCC37F800162242 /* Bundle+decode.swift in Sources */, 849047CA2702A32A008EE567 /* Handoff.swift in Sources */, - 6D4AF16325D21185009DD853 /* WidgetDataStore.swift in Sources */, + B44033EA2BCC371A00162242 /* MarketData.swift in Sources */, + B44033CB2BCC350A00162242 /* Currency.swift in Sources */, 6DFC807224EA2FA9007B8700 /* ViewQRCodefaceController.swift in Sources */, B40D4E46225841ED00428FCC /* NotificationController.swift in Sources */, B40D4E5D2258425500428FCC /* InterfaceController.swift in Sources */, + B44033FA2BCC379200162242 /* WidgetDataStore.swift in Sources */, + B44033DE2BCC36C300162242 /* LatestTransaction.swift in Sources */, B43D037B225847C500FBAA95 /* TransactionTableRow.swift in Sources */, B43D037D225847C500FBAA95 /* WalletInformation.swift in Sources */, - 6D4AF15925D21172009DD853 /* WidgetAPI.swift in Sources */, + 6D4AF15925D21172009DD853 /* MarketAPI.swift in Sources */, B40D4E642258425500428FCC /* WalletDetailsInterfaceController.swift in Sources */, B40D4E44225841ED00428FCC /* ExtensionDelegate.swift in Sources */, B40D4E682258426B00428FCC /* KeychainSwiftDistrib.swift in Sources */, - 6D4AF16D25D21192009DD853 /* Models.swift in Sources */, + 6D4AF16D25D21192009DD853 /* Placeholders.swift in Sources */, + B44033DB2BCC369B00162242 /* Colors.swift in Sources */, B40D4E632258425500428FCC /* ReceiveInterfaceController.swift in Sources */, B43D0378225847C500FBAA95 /* WalletGradient.swift in Sources */, + B44033C02BCC32F800162242 /* BitcoinUnit.swift in Sources */, + B44033E52BCC36FF00162242 /* WalletData.swift in Sources */, + B44033EF2BCC374500162242 /* Numeric+abbreviated.swift in Sources */, + B44033D02BCC352F00162242 /* UserDefaultsGroup.swift in Sources */, + B44033C52BCC332400162242 /* CurrencyConverter.swift in Sources */, 6D4AF18425D215D1009DD853 /* UserDefaultsExtension.swift in Sources */, B4AB225D2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */, B40D4E5E2258425500428FCC /* NumericKeypadInterfaceController.swift in Sources */, + B44033F52BCC377F00162242 /* WidgetData.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1498,10 +1626,28 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B44033D72BCC369400162242 /* UserDefaultsExtension.swift in Sources */, + B44033F72BCC377F00162242 /* WidgetData.swift in Sources */, + B44033E12BCC36CA00162242 /* Placeholders.swift in Sources */, + B44033E72BCC36FF00162242 /* WalletData.swift in Sources */, + B44033E02BCC36C300162242 /* LatestTransaction.swift in Sources */, + B44033D92BCC369900162242 /* Colors.swift in Sources */, B4A29A2C2B55C990002A67DF /* EventEmitter.m in Sources */, + B44033D62BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */, + B44033FD2BCC37D600162242 /* MarketAPI.swift in Sources */, B4A29A2D2B55C990002A67DF /* main.m in Sources */, B4A29A2E2B55C990002A67DF /* AppDelegate.mm in Sources */, + B44033C72BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44033FC2BCC379200162242 /* WidgetDataStore.swift in Sources */, + B44033C22BCC32F800162242 /* BitcoinUnit.swift in Sources */, + B44033F12BCC374500162242 /* Numeric+abbreviated.swift in Sources */, + B44034032BCC37F800162242 /* Bundle+decode.swift in Sources */, + B44033CD2BCC350A00162242 /* Currency.swift in Sources */, + B44034062BCC389F00162242 /* FiatUnit.swift in Sources */, + B44033CF2BCC352C00162242 /* UserDefaultsGroup.swift in Sources */, B4A29A2F2B55C990002A67DF /* Bridge.swift in Sources */, + B44034042BCC389100162242 /* XMLParserDelegate.swift in Sources */, + B44033EC2BCC371A00162242 /* MarketData.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2074,7 +2220,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Debug; }; @@ -2123,7 +2269,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Release; }; @@ -2170,7 +2316,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Debug; }; @@ -2217,7 +2363,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Release; }; @@ -2495,7 +2641,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */ = { + 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/EFPrefix/EFQRCode.git"; requirement = { @@ -2516,7 +2662,7 @@ /* Begin XCSwiftPackageProductDependency section */ 6DFC806F24EA0B6C007B8700 /* EFQRCode */ = { isa = XCSwiftPackageProductDependency; - package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */; + package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */; productName = EFQRCode; }; B41B76842B66B2FF002C48D5 /* Bugsnag */ = { diff --git a/ios/BlueWallet.xcodeproj/xcshareddata/xcschemes/PriceWidget.xcscheme b/ios/BlueWallet.xcodeproj/xcshareddata/xcschemes/PriceWidget.xcscheme index 606f23bf8..44aca4f49 100644 --- a/ios/BlueWallet.xcodeproj/xcshareddata/xcschemes/PriceWidget.xcscheme +++ b/ios/BlueWallet.xcodeproj/xcshareddata/xcschemes/PriceWidget.xcscheme @@ -102,7 +102,7 @@ diff --git a/ios/BlueWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/BlueWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved index 74d0a79b6..23bedbaa3 100644 --- a/ios/BlueWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/BlueWallet.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -29,5 +29,5 @@ } } ], - "version" : 2 + "version" : 3 } diff --git a/ios/BlueWalletWatch Extension/ExtensionDelegate.swift b/ios/BlueWalletWatch Extension/ExtensionDelegate.swift index 1947123ae..7eeecdcd5 100644 --- a/ios/BlueWalletWatch Extension/ExtensionDelegate.swift +++ b/ios/BlueWalletWatch Extension/ExtensionDelegate.swift @@ -36,7 +36,7 @@ class ExtensionDelegate: NSObject, WKExtensionDelegate { } private func updateMarketData(for fiatUnit: FiatUnit) { - WidgetAPI.fetchPrice(currency: fiatUnit.endPointKey) { (data, error) in + MarketAPI.fetchPrice(currency: fiatUnit.endPointKey) { (data, error) in guard let data = data, let encodedData = try? PropertyListEncoder().encode(data) else { return } let groupUserDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue) groupUserDefaults?.set(encodedData, forKey: MarketData.string) diff --git a/ios/BlueWalletWatch Extension/Objects/BitcoinUnit.swift b/ios/BlueWalletWatch Extension/Objects/BitcoinUnit.swift new file mode 100644 index 000000000..7991da823 --- /dev/null +++ b/ios/BlueWalletWatch Extension/Objects/BitcoinUnit.swift @@ -0,0 +1,15 @@ +// +// BitcoinUnit.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +enum BitcoinUnit: String { + case BTC = "BTC" + case SATS = "SATS" + case LOCAL_CURRENCY = "LOCAL_CURRENCY" +} diff --git a/ios/BlueWalletWatch Extension/Objects/CurrencyConverter.swift b/ios/BlueWalletWatch Extension/Objects/CurrencyConverter.swift new file mode 100644 index 000000000..6d5d225cb --- /dev/null +++ b/ios/BlueWalletWatch Extension/Objects/CurrencyConverter.swift @@ -0,0 +1,35 @@ +import Foundation + +class Balance { + static func formatBalance(_ balance: Decimal, toUnit: BitcoinUnit, withFormatting: Bool = false, completion: @escaping (String) -> Void) { + switch toUnit { + case .BTC: + let value = balance / Decimal(100_000_000) + completion("\(value) BTC") // Localize unit names as needed. + case .SATS: + if withFormatting { + completion(NumberFormatter.localizedString(from: balance as NSNumber, number: .decimal) + " SATS") + } else { + completion("\(balance) SATS") + } + case .LOCAL_CURRENCY: + fetchLocalCurrencyEquivalent(satoshi: balance, completion: completion) + } + } + + private static func fetchLocalCurrencyEquivalent(satoshi: Decimal, completion: @escaping (String) -> Void) { + + let currency = Currency.getUserPreferredCurrency() // Ensure this method retrieves the correct currency code. + MarketAPI.fetchPrice(currency: currency) { dataStore, error in + DispatchQueue.main.async { + guard let dataStore = dataStore, error == nil else { + completion("Error: \(error?.localizedDescription ?? "Unknown error")") + return + } + let rate = Decimal(string: dataStore.rate) ?? Decimal(0) + let convertedAmount = (satoshi / Decimal(100_000_000)) * rate + completion("\(convertedAmount) \(currency)") + } + } + } +} diff --git a/ios/Widgets/Shared/Fiat/FiatUnit.swift b/ios/Shared/Bundle+decode.swift similarity index 79% rename from ios/Widgets/Shared/Fiat/FiatUnit.swift rename to ios/Shared/Bundle+decode.swift index eaf2c73e8..0eec91ecc 100644 --- a/ios/Widgets/Shared/Fiat/FiatUnit.swift +++ b/ios/Shared/Bundle+decode.swift @@ -1,24 +1,13 @@ // -// FiatUnit.swift +// Bundle+decode.swift // BlueWallet // -// Created by Marcos Rodriguez on 11/20/20. -// Copyright © 2020 BlueWallet. All rights reserved. +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. // + import Foundation -struct FiatUnit: Codable { - let endPointKey: String - let symbol: String - let locale: String - let source: String - -} - -func fiatUnit(currency: String) -> FiatUnit? { - return Bundle.main.decode([String: FiatUnit].self, from: "fiatUnits.json").first(where: {$1.endPointKey == currency})?.value -} - extension Bundle { func decode(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T { guard let url = self.url(forResource: file, withExtension: nil) else { diff --git a/ios/Widgets/Shared/Colors.swift b/ios/Shared/Colors.swift similarity index 100% rename from ios/Widgets/Shared/Colors.swift rename to ios/Shared/Colors.swift diff --git a/ios/Shared/Currency.swift b/ios/Shared/Currency.swift new file mode 100644 index 000000000..5748da87d --- /dev/null +++ b/ios/Shared/Currency.swift @@ -0,0 +1,57 @@ +// +// Currency.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +struct CurrencyError: LocalizedError { + var errorDescription: String = "Failed to parse response" +} + +class Currency { + + static func getUserPreferredCurrency() -> String { + + guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), + let preferredCurrency = userDefaults.string(forKey: "preferredCurrency") + else { + return "USD" + } + + if preferredCurrency != Currency.getLastSelectedCurrency() { + UserDefaults.standard.removeObject(forKey: WidgetData.WidgetCachedDataStoreKey) + UserDefaults.standard.removeObject(forKey: WidgetData.WidgetDataStoreKey) + UserDefaults.standard.synchronize() + } + + return preferredCurrency + } + + static func getUserPreferredCurrencyLocale() -> String { + guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), + let preferredCurrency = userDefaults.string(forKey: "preferredCurrencyLocale") + else { + return "en_US" + } + return preferredCurrency + } + + static func getLastSelectedCurrency() -> String { + guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), let dataStore = userDefaults.string(forKey: "currency") else { + return "USD" + } + + return dataStore + } + + static func saveNewSelectedCurrency() { + UserDefaults.standard.setValue(Currency.getUserPreferredCurrency(), forKey: "currency") + } + + +} + diff --git a/ios/Shared/Fiat/FiatUnit.swift b/ios/Shared/Fiat/FiatUnit.swift new file mode 100644 index 000000000..4cf120985 --- /dev/null +++ b/ios/Shared/Fiat/FiatUnit.swift @@ -0,0 +1,20 @@ +// +// FiatUnit.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 11/20/20. +// Copyright © 2020 BlueWallet. All rights reserved. +// +import Foundation + +struct FiatUnit: Codable { + let endPointKey: String + let symbol: String + let locale: String + let source: String + +} + +func fiatUnit(currency: String) -> FiatUnit? { + return Bundle.main.decode([String: FiatUnit].self, from: "fiatUnits.json").first(where: {$1.endPointKey == currency})?.value +} diff --git a/ios/Widgets/Shared/XMLParserDelegate.swift b/ios/Shared/Fiat/XMLParserDelegate.swift similarity index 100% rename from ios/Widgets/Shared/XMLParserDelegate.swift rename to ios/Shared/Fiat/XMLParserDelegate.swift diff --git a/ios/Shared/LatestTransaction.swift b/ios/Shared/LatestTransaction.swift new file mode 100644 index 000000000..5a100bc96 --- /dev/null +++ b/ios/Shared/LatestTransaction.swift @@ -0,0 +1,14 @@ +// +// LatestTransaction.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +struct LatestTransaction { + let isUnconfirmed: Bool? + let epochValue: Int? +} diff --git a/ios/Widgets/Shared/WidgetAPI+Electrum.swift b/ios/Shared/MarketAPI+Electrum.swift similarity index 96% rename from ios/Widgets/Shared/WidgetAPI+Electrum.swift rename to ios/Shared/MarketAPI+Electrum.swift index 1b12a04e7..85dc5fa7d 100644 --- a/ios/Widgets/Shared/WidgetAPI+Electrum.swift +++ b/ios/Shared/MarketAPI+Electrum.swift @@ -12,7 +12,7 @@ struct APIError: LocalizedError { var errorDescription: String = "Failed to fetch Electrum data..." } -extension WidgetAPI { +extension MarketAPI { static func fetchNextBlockFee(completion: @escaping ((MarketData?, Error?) -> Void), userElectrumSettings: UserDefaultsElectrumSettings = UserDefaultsGroup.getElectrumSettings()) { let settings = userElectrumSettings @@ -73,12 +73,12 @@ extension WidgetAPI { static func fetchMarketData(currency: String, completion: @escaping ((MarketData?, Error?) -> Void)) { var marketDataEntry = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0) - WidgetAPI.fetchPrice(currency: currency, completion: { (result, error) in + MarketAPI.fetchPrice(currency: currency, completion: { (result, error) in if let result = result { marketDataEntry.rate = result.rateDouble marketDataEntry.price = result.formattedRate ?? "!" } - WidgetAPI.fetchNextBlockFee { (marketData, error) in + MarketAPI.fetchNextBlockFee { (marketData, error) in if let nextBlock = marketData?.nextBlock { marketDataEntry.nextBlock = nextBlock } else { diff --git a/ios/Shared/MarketAPI.swift b/ios/Shared/MarketAPI.swift new file mode 100644 index 000000000..70580c73d --- /dev/null +++ b/ios/Shared/MarketAPI.swift @@ -0,0 +1,199 @@ +// +// WidgetAPI.swift +// TodayExtension +// +// Created by Marcos Rodriguez on 11/2/19. + +// + +import Foundation + +var numberFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.maximumFractionDigits = 0 + formatter.locale = Locale.current + return formatter +} + +class MarketAPI { + + private static func buildURLString(source: String, endPointKey: String) -> String { + switch source { + case "Yadio": + return "https://api.yadio.io/json/\(endPointKey)" + case "YadioConvert": + return "https://api.yadio.io/convert/1/BTC/\(endPointKey)" + case "Exir": + return "https://api.exir.io/v1/ticker?symbol=btc-irt" + case "wazirx": + return "https://api.wazirx.com/api/v2/tickers/btcinr" + case "Bitstamp": + return "https://www.bitstamp.net/api/v2/ticker/btc\(endPointKey.lowercased())" + case "Coinbase": + return "https://api.coinbase.com/v2/prices/BTC-\(endPointKey.uppercased())/buy" + case "CoinGecko": + return "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=\(endPointKey.lowercased())" + case "BNR": + return "https://www.bnr.ro/nbrfxrates.xml" + default: + return "https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json" + } + } + + private static func handleDefaultData(data: Data, source: String, endPointKey: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) { + guard let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? Dictionary else { + completion(nil, CurrencyError(errorDescription: "JSON parsing error.")) + return + } + + // Parse the JSON based on the source and format the response + parseJSONBasedOnSource(json: json, source: source, endPointKey: endPointKey, completion: completion) + } + + private static func parseJSONBasedOnSource(json: Dictionary, source: String, endPointKey: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) { + var latestRateDataStore: WidgetDataStore? + + switch source { + case "Yadio": + if let rateDict = json[endPointKey] as? [String: Any], + let rateDouble = rateDict["price"] as? Double, + let lastUpdated = rateDict["timestamp"] as? Int { + let unix = Double(lastUpdated / 1_000) + let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix)) + latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)")) + } + case "YadioConvert": + guard let rateDouble = json["rate"] as? Double, + let lastUpdated = json["timestamp"] as? Int + else { break } + let unix = Double(lastUpdated / 1_000) + let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix)) + latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + case "CoinGecko": + if let bitcoinDict = json["bitcoin"] as? [String: Any], + let rateDouble = bitcoinDict[endPointKey.lowercased()] as? Double { + let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) + latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)")) + } + + case "Exir": + if let rateDouble = json["last"] as? Double { + let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) + latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)")) + } + + case "Bitstamp": + if let rateString = json["last"] as? String, let rateDouble = Double(rateString) { + let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) + latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)")) + } + + case "wazirx": + if let tickerDict = json["ticker"] as? [String: Any], + let rateString = tickerDict["buy"] as? String, + let rateDouble = Double(rateString) { + let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) + latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)")) + } + + case "Coinbase": + if let data = json["data"] as? [String: Any], + let rateString = data["amount"] as? String, + let rateDouble = Double(rateString) { + let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) + latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)")) + } + + case "BNR": + // Handle BNR source differently if needed, perhaps requiring XML parsing + // Placeholder for potential XML parsing logic or alternative JSON structure + completion(nil, CurrencyError(errorDescription: "BNR data source is not yet implemented")) + + default: + completion(nil, CurrencyError(errorDescription: "Unsupported data source \(source)")) + } + } + + // Handles XML data for BNR source + private static func handleBNRData(data: Data, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) { + let parser = XMLParser(data: data) + let delegate = BNRXMLParserDelegate() + parser.delegate = delegate + if parser.parse(), let usdToRonRate = delegate.usdRate { + let coinGeckoUrl = URL(string: "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")! + URLSession.shared.dataTask(with: coinGeckoUrl) { data, _, error in + guard let data = data, error == nil else { + completion(nil, error ?? CurrencyError()) + return + } + + do { + if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], + let bitcoinDict = json["bitcoin"] as? [String: Double], + let btcToUsdRate = bitcoinDict["usd"] { + let btcToRonRate = btcToUsdRate * usdToRonRate + let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) + let latestRateDataStore = WidgetDataStore(rate: String(btcToRonRate), lastUpdate: lastUpdatedString, rateDouble: btcToRonRate) + completion(latestRateDataStore, nil) + } else { + completion(nil, CurrencyError()) + } + } catch { + completion(nil, error) + } + }.resume() + } else { + completion(nil, CurrencyError(errorDescription: "XML parsing error.")) + } + } + + static func fetchPrice(currency: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) { + let currencyToFiatUnit = fiatUnit(currency: currency) + guard let source = currencyToFiatUnit?.source, let endPointKey = currencyToFiatUnit?.endPointKey else { + completion(nil, CurrencyError(errorDescription: "Invalid currency unit or endpoint.")) + return + } + + let urlString = buildURLString(source: source, endPointKey: endPointKey) + guard let url = URL(string: urlString) else { + completion(nil, CurrencyError(errorDescription: "Invalid URL.")) + return + } + + URLSession.shared.dataTask(with: url) { data, response, error in + guard let data = data, error == nil else { + completion(nil, error ?? CurrencyError(errorDescription: "Network error or data not found.")) + return + } + + if source == "BNR" { + handleBNRData(data: data, completion: completion) + } else { + handleDefaultData(data: data, source: source, endPointKey: endPointKey, completion: completion) + } + }.resume() + } + +} + + diff --git a/ios/Shared/MarketData.swift b/ios/Shared/MarketData.swift new file mode 100644 index 000000000..7cef555ca --- /dev/null +++ b/ios/Shared/MarketData.swift @@ -0,0 +1,37 @@ +// +// MarketData.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +struct MarketData:Codable { + var nextBlock: String + var sats: String + var price: String + var rate: Double + var formattedNextBlock: String { + return nextBlock == "..." ? "..." : #"\#(nextBlock) sat/b"# + } + var dateString: String = "" + var formattedDate: String? { + let isoDateFormatter = ISO8601DateFormatter() + let dateFormatter = DateFormatter() + dateFormatter.locale = Locale.current + dateFormatter.timeStyle = .short + + if let date = isoDateFormatter.date(from: dateString) { + return dateFormatter.string(from: date) + } + return nil + } + static let string = "MarketData" +} + +enum MarketDataTimeline: String { + case Previous = "previous" + case Current = "current" +} diff --git a/ios/Shared/Numeric+abbreviated.swift b/ios/Shared/Numeric+abbreviated.swift new file mode 100644 index 000000000..7f0a83934 --- /dev/null +++ b/ios/Shared/Numeric+abbreviated.swift @@ -0,0 +1,27 @@ +// +// Numeric+abbreviated.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +extension Numeric { + + var abbreviated: String { + let bytecountFormatter = ByteCountFormatter() + bytecountFormatter.zeroPadsFractionDigits = true + bytecountFormatter.countStyle = .decimal + bytecountFormatter.isAdaptive = false + let bytesString = bytecountFormatter.string(fromByteCount: (self as! NSNumber).int64Value) + + let numericString = bytesString + .replacingOccurrences(of: "bytes", with: "") + .replacingOccurrences(of: "B", with: "") // removes B (bytes) in 'KB'/'MB'/'GB' + .replacingOccurrences(of: "G", with: "B") // replace G (Giga) to just B (billions) + return numericString.replacingOccurrences(of: " ", with: "") + } + +} diff --git a/ios/Shared/Placeholders.swift b/ios/Shared/Placeholders.swift new file mode 100644 index 000000000..c4789ee81 --- /dev/null +++ b/ios/Shared/Placeholders.swift @@ -0,0 +1,16 @@ +// +// Models.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 11/1/20. +// Copyright © 2020 BlueWallet. All rights reserved. +// + +import Foundation + + + +let emptyMarketData = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0) +let emptyWalletData = WalletData(balance: 0, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: Int(Date().timeIntervalSince1970))) + + diff --git a/ios/Widgets/Shared/UserDefaultsExtension.swift b/ios/Shared/UserDefaultsExtension.swift similarity index 100% rename from ios/Widgets/Shared/UserDefaultsExtension.swift rename to ios/Shared/UserDefaultsExtension.swift diff --git a/ios/Widgets/Shared/UserDefaultsGroup.swift b/ios/Shared/UserDefaultsGroup.swift similarity index 100% rename from ios/Widgets/Shared/UserDefaultsGroup.swift rename to ios/Shared/UserDefaultsGroup.swift diff --git a/ios/Shared/UserDefaultsGroupKey.swift b/ios/Shared/UserDefaultsGroupKey.swift new file mode 100644 index 000000000..bf73caa11 --- /dev/null +++ b/ios/Shared/UserDefaultsGroupKey.swift @@ -0,0 +1,20 @@ +// +// UserDefaultsGroupKeys.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +enum UserDefaultsGroupKey: String { + case GroupName = "group.io.bluewallet.bluewallet" + case PreferredCurrency = "preferredCurrency" + case ElectrumSettingsHost = "electrum_host" + case ElectrumSettingsTCPPort = "electrum_tcp_port" + case ElectrumSettingsSSLPort = "electrum_ssl_port" + case AllWalletsBalance = "WidgetCommunicationAllWalletsSatoshiBalance" + case AllWalletsLatestTransactionTime = "WidgetCommunicationAllWalletsLatestTransactionTime" + case LatestTransactionIsUnconfirmed = "\"WidgetCommunicationLatestTransactionIsUnconfirmed\"" +} diff --git a/ios/Shared/WalletData.swift b/ios/Shared/WalletData.swift new file mode 100644 index 000000000..96fc165de --- /dev/null +++ b/ios/Shared/WalletData.swift @@ -0,0 +1,27 @@ +// +// WalletData.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +struct WalletData { + var balance: Double + var latestTransactionTime: LatestTransaction = LatestTransaction(isUnconfirmed: false, epochValue: 0) + var formattedBalanceBTC: String { + let formatter = NumberFormatter() + formatter.numberStyle = .none + formatter.usesSignificantDigits = true + formatter.maximumSignificantDigits = 9 + formatter.roundingMode = .up + let value = NSNumber(value: balance / 100000000); + if let valueString = formatter.string(from: value) { + return "\(String(describing: valueString)) \(BitcoinUnit.BTC.rawValue)" + } else { + return "0 \(BitcoinUnit.BTC.rawValue)" + } + } +} diff --git a/ios/Shared/WidgetData.swift b/ios/Shared/WidgetData.swift new file mode 100644 index 000000000..d740adccf --- /dev/null +++ b/ios/Shared/WidgetData.swift @@ -0,0 +1,22 @@ +// +// WidgetData.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + +class WidgetData { + + static let WidgetDataStoreKey = "WidgetDataStoreKey" + static let WidgetCachedDataStoreKey = "WidgetCachedDataStoreKey" + + static func savePriceRateAndLastUpdate(rate: String, lastUpdate: String) { + guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue) else { return } + userDefaults.setValue(["rate": rate, "lastUpdate": lastUpdate], forKey: WidgetDataStoreKey) + userDefaults.synchronize() + } + +} diff --git a/ios/Shared/WidgetDataStore.swift b/ios/Shared/WidgetDataStore.swift new file mode 100644 index 000000000..45104ebf6 --- /dev/null +++ b/ios/Shared/WidgetDataStore.swift @@ -0,0 +1,62 @@ +// +// WidgetDataStore.swift +// BlueWallet +// +// Created by Marcos Rodriguez on 4/14/24. +// Copyright © 2024 BlueWallet. All rights reserved. +// + +import Foundation + + +struct WidgetDataStore: Codable { + let rate: String + let lastUpdate: String + let rateDouble: Double + var formattedRate: String? { + let numberFormatter = NumberFormatter() + numberFormatter.locale = Locale(identifier: Currency.getUserPreferredCurrencyLocale()) + numberFormatter.numberStyle = .currency + numberFormatter.maximumFractionDigits = 0 + numberFormatter.minimumFractionDigits = 0 + if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) { + return rateString + } + return rate + } + var formattedRateForSmallComplication: String? { + return rateDouble.abbreviated + } + + var formattedRateForComplication: String? { + let numberFormatter = NumberFormatter() + numberFormatter.locale = Locale(identifier: Currency.getUserPreferredCurrencyLocale()) + numberFormatter.numberStyle = .currency + numberFormatter.currencySymbol = "" + if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) { + return rateString + } + return rate + } + + var date: Date? { + let isoDateFormatter = ISO8601DateFormatter() + let dateFormatter = DateFormatter() + dateFormatter.locale = Locale.current + dateFormatter.timeStyle = .short + + return isoDateFormatter.date(from: lastUpdate) + } + var formattedDate: String? { + let isoDateFormatter = ISO8601DateFormatter() + let dateFormatter = DateFormatter() + dateFormatter.locale = Locale.current + dateFormatter.timeStyle = .short + + if let date = isoDateFormatter.date(from: lastUpdate) { + return dateFormatter.string(from: date) + } + return nil + } +} + diff --git a/ios/WalletInformationWidget/WalletInformationWidget.swift b/ios/WalletInformationWidget/WalletInformationWidget.swift index 2ec8221b3..97270786f 100644 --- a/ios/WalletInformationWidget/WalletInformationWidget.swift +++ b/ios/WalletInformationWidget/WalletInformationWidget.swift @@ -29,10 +29,10 @@ struct WalletInformationWidgetProvider: TimelineProvider { func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { var entries: [WalletInformationWidgetEntry] = [] - let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency() + let userPreferredCurrency = Currency.getUserPreferredCurrency() let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime()) - WidgetAPI.fetchPrice(currency: userPreferredCurrency) { (result, error) in + MarketAPI.fetchPrice(currency: userPreferredCurrency) { (result, error) in let entry: WalletInformationWidgetEntry if let result = result { diff --git a/ios/Widgets/MarketWidget/MarketWidget.swift b/ios/Widgets/MarketWidget/MarketWidget.swift index a82dc6bb9..578871ba8 100644 --- a/ios/Widgets/MarketWidget/MarketWidget.swift +++ b/ios/Widgets/MarketWidget/MarketWidget.swift @@ -34,8 +34,8 @@ struct MarketWidgetProvider: TimelineProvider { let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } else { - let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency() - WidgetAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in + let userPreferredCurrency = Currency.getUserPreferredCurrency() + MarketAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in let entry: MarketWidgetEntry if let result = result { diff --git a/ios/Widgets/PriceWidget/PriceWidget.swift b/ios/Widgets/PriceWidget/PriceWidget.swift index 8133a947f..b108e631f 100644 --- a/ios/Widgets/PriceWidget/PriceWidget.swift +++ b/ios/Widgets/PriceWidget/PriceWidget.swift @@ -36,14 +36,14 @@ struct PriceWidgetProvider: TimelineProvider { let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } else { - let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency() - if userPreferredCurrency != WidgetAPI.getLastSelectedCurrency() { + let userPreferredCurrency = Currency.getUserPreferredCurrency() + if userPreferredCurrency != Currency.getLastSelectedCurrency() { marketData[.Current] = nil marketData[.Previous] = nil - WidgetAPI.saveNewSelectedCurrency() + Currency.saveNewSelectedCurrency() } - WidgetAPI.fetchPrice(currency: userPreferredCurrency) { (data, error) in + MarketAPI.fetchPrice(currency: userPreferredCurrency) { (data, error) in let entry: PriceWidgetEntry if let data = data, let formattedRate = data.formattedRate { diff --git a/ios/Widgets/Shared/Models.swift b/ios/Widgets/Shared/Models.swift deleted file mode 100644 index 25a600d51..000000000 --- a/ios/Widgets/Shared/Models.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// Models.swift -// BlueWallet -// -// Created by Marcos Rodriguez on 11/1/20. -// Copyright © 2020 BlueWallet. All rights reserved. -// - -import Foundation - -struct MarketData:Codable { - var nextBlock: String - var sats: String - var price: String - var rate: Double - var formattedNextBlock: String { - return nextBlock == "..." ? "..." : #"\#(nextBlock) sat/b"# - } - var dateString: String = "" - var formattedDate: String? { - let isoDateFormatter = ISO8601DateFormatter() - let dateFormatter = DateFormatter() - dateFormatter.locale = Locale.current - dateFormatter.timeStyle = .short - - if let date = isoDateFormatter.date(from: dateString) { - return dateFormatter.string(from: date) - } - return nil - } - static let string = "MarketData" -} - -struct WalletData { - var balance: Double - var latestTransactionTime: LatestTransaction = LatestTransaction(isUnconfirmed: false, epochValue: 0) - var formattedBalanceBTC: String { - let formatter = NumberFormatter() - formatter.numberStyle = .none - formatter.usesSignificantDigits = true - formatter.maximumSignificantDigits = 9 - formatter.roundingMode = .up - let value = NSNumber(value: balance / 100000000); - if let valueString = formatter.string(from: value) { - return "\(String(describing: valueString)) BTC" - } else { - return "0 BTC" - } - } - -} - -struct LatestTransaction { - let isUnconfirmed: Bool? - let epochValue: Int? -} -let emptyMarketData = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0) -let emptyWalletData = WalletData(balance: 0, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: Int(Date().timeIntervalSince1970))) - -enum MarketDataTimeline: String { - case Previous = "previous" - case Current = "current" -} - -enum UserDefaultsGroupKey: String { - case GroupName = "group.io.bluewallet.bluewallet" - case PreferredCurrency = "preferredCurrency" - case ElectrumSettingsHost = "electrum_host" - case ElectrumSettingsTCPPort = "electrum_tcp_port" - case ElectrumSettingsSSLPort = "electrum_ssl_port" - case AllWalletsBalance = "WidgetCommunicationAllWalletsSatoshiBalance" - case AllWalletsLatestTransactionTime = "WidgetCommunicationAllWalletsLatestTransactionTime" - case LatestTransactionIsUnconfirmed = "\"WidgetCommunicationLatestTransactionIsUnconfirmed\"" -} diff --git a/ios/Widgets/Shared/Views/MarketView.swift b/ios/Widgets/Shared/Views/MarketView.swift index ca7f72dbc..2e3ec21ab 100644 --- a/ios/Widgets/Shared/Views/MarketView.swift +++ b/ios/Widgets/Shared/Views/MarketView.swift @@ -28,7 +28,7 @@ struct MarketView: View { Spacer() HStack(alignment: .center, spacing: 0, content: { - Text("Sats/\(WidgetAPI.getUserPreferredCurrency())").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor) + Text("Sats/\(Currency.getUserPreferredCurrency())").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor) Spacer() Text(marketData.sats == "..." ? "..." : marketData.sats).padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)).lineLimit(1).minimumScaleFactor(0.1).foregroundColor(.widgetBackground).font(Font.system(size:11, weight: .semibold, design: .default)).background(Color(red: 0.97, green: 0.21, blue: 0.38)).overlay( RoundedRectangle(cornerRadius: 4.0) diff --git a/ios/Widgets/Shared/Views/WalletInformationView.swift b/ios/Widgets/Shared/Views/WalletInformationView.swift index 24c16f2b9..cb00ed0aa 100644 --- a/ios/Widgets/Shared/Views/WalletInformationView.swift +++ b/ios/Widgets/Shared/Views/WalletInformationView.swift @@ -16,7 +16,7 @@ struct WalletInformationView: View { var formattedBalance: String { let numberFormatter = NumberFormatter() - numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale()) + numberFormatter.locale = Locale(identifier: Currency.getUserPreferredCurrencyLocale()) numberFormatter.numberStyle = .currency let amount = numberFormatter.string(from: NSNumber(value: ((allWalletsBalance.balance / 100000000) * marketData.rate))) ?? "" return amount diff --git a/ios/Widgets/Shared/WidgetAPI.swift b/ios/Widgets/Shared/WidgetAPI.swift deleted file mode 100644 index 65de410ba..000000000 --- a/ios/Widgets/Shared/WidgetAPI.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// WidgetAPI.swift -// TodayExtension -// -// Created by Marcos Rodriguez on 11/2/19. - -// - -import Foundation - -struct CurrencyError: LocalizedError { - var errorDescription: String = "Failed to parse response" -} - -var numberFormatter: NumberFormatter { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 0 - formatter.locale = Locale.current - return formatter -} - -class WidgetAPI { - static func fetchPrice(currency: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) { - let currencyToFiatUnit = fiatUnit(currency: currency) - guard let source = currencyToFiatUnit?.source, let endPointKey = currencyToFiatUnit?.endPointKey else { return } - - var urlString: String - switch source { - case "Yadio": - urlString = "https://api.yadio.io/json/\(endPointKey)" - case "YadioConvert": - urlString = "https://api.yadio.io/convert/1/BTC/\(endPointKey)" - case "Exir": - urlString = "https://api.exir.io/v1/ticker?symbol=btc-irt" - case "wazirx": - urlString = "https://api.wazirx.com/api/v2/tickers/btcinr" - case "Bitstamp": - urlString = "https://www.bitstamp.net/api/v2/ticker/btc\(endPointKey.lowercased())" - case "Coinbase": - urlString = "https://api.coinbase.com/v2/prices/BTC-\(endPointKey.uppercased())/buy" - case "CoinGecko": - urlString = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=\(endPointKey.lowercased())" - case "BNR": - urlString = "https://www.bnr.ro/nbrfxrates.xml" - default: - urlString = "https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json" - } - - guard let url = URL(string:urlString) else { return } - - if source == "BNR" { - URLSession.shared.dataTask(with: url) { (data, response, error) in - if let error = error { - print("Error fetching data: \(error.localizedDescription)") - completion(nil, error) - return - } - - guard let data = data else { - print("No data received") - completion(nil, nil) - return - } - - // Parse XML data for USD to RON rate - let parser = XMLParser(data: data) - let delegate = BNRXMLParserDelegate() - parser.delegate = delegate - if parser.parse(), let usdToRonRate = delegate.usdRate { - // Fetch BTC to USD rate using CoinGecko - let coinGeckoUrl = URL(string: "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")! - URLSession.shared.dataTask(with: coinGeckoUrl) { (data, _, error) in - guard let data = data, error == nil else { - completion(nil, error ?? CurrencyError()) - return - } - - do { - if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], - let bitcoinDict = json["bitcoin"] as? [String: Double], - let btcToUsdRate = bitcoinDict["usd"] { - let btcToRonRate = btcToUsdRate * usdToRonRate - let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) - let latestRateDataStore = WidgetDataStore(rate: String(btcToRonRate), lastUpdate: lastUpdatedString, rateDouble: btcToRonRate) - completion(latestRateDataStore, nil) - } else { - completion(nil, CurrencyError()) - } - } catch { - completion(nil, error) - } - }.resume() - } else { - print("Error parsing XML") - completion(nil, CurrencyError()) - } - }.resume() - } else { - URLSession.shared.dataTask(with: url) { (data, response, error) in - guard let dataResponse = data, - let json = (try? JSONSerialization.jsonObject(with: dataResponse, options: .mutableContainers) as? Dictionary), - error == nil - else { - print(error?.localizedDescription ?? "Response Error") - completion(nil, error) - return - } - - var latestRateDataStore: WidgetDataStore? - switch source { - case "Yadio": - guard let rateDict = json[endPointKey] as? [String: Any], - let rateDouble = rateDict["price"] as? Double, - let lastUpdated = json["timestamp"] as? Int - else { break } - let unix = Double(lastUpdated / 1_000) - let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix)) - latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) - case "CoinGecko": - guard let rateDict = json["bitcoin"] as? [String: Any], - let rateDouble = rateDict[endPointKey.lowercased()] as? Double - else { break } - let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) - latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) - case "YadioConvert": - guard let rateDict = json as? [String: Any], - let rateDouble = rateDict["rate"] as? Double, - let lastUpdated = json["timestamp"] as? Int - else { break } - let unix = Double(lastUpdated / 1_000) - let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix)) - latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble) - case "Exir": - guard let rateDouble = json["last"] as? Double else { break } - let rateString = String(rateDouble) - let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) - latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) - case "Bitstamp": - guard let rateString = json["last"] as? String, let rateDouble = Double(rateString) else { break } - let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) - latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) - case "wazirx": - guard let tickerDict = json["ticker"] as? [String: Any], - let rateString = tickerDict["buy"] as? String, - let rateDouble = Double(rateString) - else { break } - let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) - latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) - case "Coinbase": - guard let data = json["data"] as? Dictionary, - let rateString = data["amount"] as? String, - let rateDouble = Double(rateString) - else { break } - let lastUpdatedString = ISO8601DateFormatter().string(from: Date()) - latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) - default: - guard let bpi = json["bpi"] as? Dictionary, - let preferredCurrency = bpi[endPointKey] as? Dictionary, - let rateString = preferredCurrency["rate"] as? String, - let rateDouble = preferredCurrency["rate_float"] as? Double, - let time = json["time"] as? Dictionary, - let lastUpdatedString = time["updatedISO"] as? String - else { break } - latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble) - } - - if (latestRateDataStore == nil) { - completion(nil, CurrencyError()) - return - } - - completion(latestRateDataStore, nil) - }.resume() - } - } - - static func getUserPreferredCurrency() -> String { - - guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), - let preferredCurrency = userDefaults.string(forKey: "preferredCurrency") - else { - return "USD" - } - - if preferredCurrency != WidgetAPI.getLastSelectedCurrency() { - UserDefaults.standard.removeObject(forKey: WidgetData.WidgetCachedDataStoreKey) - UserDefaults.standard.removeObject(forKey: WidgetData.WidgetDataStoreKey) - UserDefaults.standard.synchronize() - } - - return preferredCurrency - } - - static func getUserPreferredCurrencyLocale() -> String { - guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), - let preferredCurrency = userDefaults.string(forKey: "preferredCurrencyLocale") - else { - return "en_US" - } - return preferredCurrency - } - - static func getLastSelectedCurrency() -> String { - guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), let dataStore = userDefaults.string(forKey: "currency") else { - return "USD" - } - - return dataStore - } - - static func saveNewSelectedCurrency() { - UserDefaults.standard.setValue(WidgetAPI.getUserPreferredCurrency(), forKey: "currency") - } - -} - - diff --git a/ios/Widgets/Shared/WidgetDataStore.swift b/ios/Widgets/Shared/WidgetDataStore.swift deleted file mode 100644 index 50acfa68f..000000000 --- a/ios/Widgets/Shared/WidgetDataStore.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// Created by Marcos Rodriguez on 11/3/19. -// - -import Foundation - -extension Numeric { - - var abbreviated: String { - let bytecountFormatter = ByteCountFormatter() - bytecountFormatter.zeroPadsFractionDigits = true - bytecountFormatter.countStyle = .decimal - bytecountFormatter.isAdaptive = false - let bytesString = bytecountFormatter.string(fromByteCount: (self as! NSNumber).int64Value) - - let numericString = bytesString - .replacingOccurrences(of: "bytes", with: "") - .replacingOccurrences(of: "B", with: "") // removes B (bytes) in 'KB'/'MB'/'GB' - .replacingOccurrences(of: "G", with: "B") // replace G (Giga) to just B (billions) - return numericString.replacingOccurrences(of: " ", with: "") - } -} - -struct WidgetDataStore: Codable { - let rate: String - let lastUpdate: String - let rateDouble: Double - var formattedRate: String? { - let numberFormatter = NumberFormatter() - numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale()) - numberFormatter.numberStyle = .currency - numberFormatter.maximumFractionDigits = 0 - numberFormatter.minimumFractionDigits = 0 - if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) { - return rateString - } - return rate - } - var formattedRateForSmallComplication: String? { - return rateDouble.abbreviated - } - - var formattedRateForComplication: String? { - let numberFormatter = NumberFormatter() - numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale()) - numberFormatter.numberStyle = .currency - numberFormatter.currencySymbol = "" - if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) { - return rateString - } - return rate - } - - var date: Date? { - let isoDateFormatter = ISO8601DateFormatter() - let dateFormatter = DateFormatter() - dateFormatter.locale = Locale.current - dateFormatter.timeStyle = .short - - return isoDateFormatter.date(from: lastUpdate) - } - var formattedDate: String? { - let isoDateFormatter = ISO8601DateFormatter() - let dateFormatter = DateFormatter() - dateFormatter.locale = Locale.current - dateFormatter.timeStyle = .short - - if let date = isoDateFormatter.date(from: lastUpdate) { - return dateFormatter.string(from: date) - } - return nil - } -} - -class WidgetData { - - static let WidgetDataStoreKey = "WidgetDataStoreKey" - static let WidgetCachedDataStoreKey = "WidgetCachedDataStoreKey" - - static func savePriceRateAndLastUpdate(rate: String, lastUpdate: String) { - guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue) else { return } - userDefaults.setValue(["rate": rate, "lastUpdate": lastUpdate], forKey: WidgetDataStoreKey) - userDefaults.synchronize() - } - -} diff --git a/ios/Widgets/WalletInformationAndMarketWidget/WalletInformationAndMarketWidget.swift b/ios/Widgets/WalletInformationAndMarketWidget/WalletInformationAndMarketWidget.swift index 51f5aa779..967933d5a 100644 --- a/ios/Widgets/WalletInformationAndMarketWidget/WalletInformationAndMarketWidget.swift +++ b/ios/Widgets/WalletInformationAndMarketWidget/WalletInformationAndMarketWidget.swift @@ -35,10 +35,10 @@ struct WalletInformationAndMarketWidgetProvider: TimelineProvider { let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } else { - let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency() + let userPreferredCurrency = Currency.getUserPreferredCurrency() let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime()) - WidgetAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in + MarketAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in let entry: WalletInformationAndMarketWidgetEntry if let result = result { From cc1fec9ddbbd054dc5771a783a64f9d47e76a5b0 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 14 Apr 2024 18:54:10 -0400 Subject: [PATCH 2/2] REF: Move files --- ios/BlueWallet.xcodeproj/project.pbxproj | 36 ++++++------------- .../Balance.swift} | 0 .../Objects => Shared}/BitcoinUnit.swift | 0 3 files changed, 11 insertions(+), 25 deletions(-) rename ios/{BlueWalletWatch Extension/Objects/CurrencyConverter.swift => Shared/Balance.swift} (100%) rename ios/{BlueWalletWatch Extension/Objects => Shared}/BitcoinUnit.swift (100%) diff --git a/ios/BlueWallet.xcodeproj/project.pbxproj b/ios/BlueWallet.xcodeproj/project.pbxproj index c1a368b37..fd405f78e 100644 --- a/ios/BlueWallet.xcodeproj/project.pbxproj +++ b/ios/BlueWallet.xcodeproj/project.pbxproj @@ -76,10 +76,10 @@ B44033C02BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; B44033C12BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; B44033C22BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; }; - B44033C42BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; - B44033C52BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; - B44033C62BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; - B44033C72BCC332400162242 /* CurrencyConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* CurrencyConverter.swift */; }; + B44033C42BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; }; + B44033C52BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; }; + B44033C62BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; }; + B44033C72BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; }; B44033CA2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; B44033CB2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; B44033CC2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; }; @@ -210,13 +210,6 @@ remoteGlobalIDString = B4A29A212B55C990002A67DF; remoteInfo = "BlueWallet-NoLDK"; }; - B4A29A232B55C990002A67DF /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; - proxyType = 1; - remoteGlobalIDString = B40D4E2F225841EC00428FCC; - remoteInfo = BlueWalletWatch; - }; B4A29A252B55C990002A67DF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; @@ -433,7 +426,7 @@ B43D0377225847C500FBAA95 /* WalletInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletInformation.swift; sourceTree = ""; }; B43D046E22584C1B00FBAA95 /* libRNWatch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRNWatch.a; sourceTree = BUILT_PRODUCTS_DIR; }; B44033BE2BCC32F800162242 /* BitcoinUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinUnit.swift; sourceTree = ""; }; - B44033C32BCC332400162242 /* CurrencyConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyConverter.swift; sourceTree = ""; }; + B44033C32BCC332400162242 /* Balance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Balance.swift; sourceTree = ""; }; B44033C92BCC350A00162242 /* Currency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = ""; }; B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroupKey.swift; sourceTree = ""; }; B44033DC2BCC36C300162242 /* LatestTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestTransaction.swift; sourceTree = ""; }; @@ -824,8 +817,6 @@ B43D0377225847C500FBAA95 /* WalletInformation.swift */, B43D0373225847C500FBAA95 /* WatchDataSource.swift */, 849047C92702A32A008EE567 /* Handoff.swift */, - B44033BE2BCC32F800162242 /* BitcoinUnit.swift */, - B44033C32BCC332400162242 /* CurrencyConverter.swift */, ); path = Objects; sourceTree = ""; @@ -849,6 +840,8 @@ B44033F82BCC379200162242 /* WidgetDataStore.swift */, B44033FF2BCC37F800162242 /* Bundle+decode.swift */, 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */, + B44033BE2BCC32F800162242 /* BitcoinUnit.swift */, + B44033C32BCC332400162242 /* Balance.swift */, ); path = Shared; sourceTree = ""; @@ -1038,7 +1031,6 @@ buildRules = ( ); dependencies = ( - B4A29A222B55C990002A67DF /* PBXTargetDependency */, B4A29A242B55C990002A67DF /* PBXTargetDependency */, B4A29A262B55C990002A67DF /* PBXTargetDependency */, B4A29A282B55C990002A67DF /* PBXTargetDependency */, @@ -1520,7 +1512,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */, B461B852299599F800E431AA /* AppDelegate.mm in Sources */, B44033F42BCC377F00162242 /* WidgetData.swift in Sources */, - B44033C42BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44033C42BCC332400162242 /* Balance.swift in Sources */, B44034072BCC38A000162242 /* FiatUnit.swift in Sources */, B44034002BCC37F800162242 /* Bundle+decode.swift in Sources */, B44033E22BCC36CB00162242 /* Placeholders.swift in Sources */, @@ -1561,7 +1553,7 @@ B44033FB2BCC379200162242 /* WidgetDataStore.swift in Sources */, B44033EB2BCC371A00162242 /* MarketData.swift in Sources */, 6DD410AF266CAF5C0087DE03 /* WalletInformationAndMarketWidget.swift in Sources */, - B44033C62BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44033C62BCC332400162242 /* Balance.swift in Sources */, B44033E62BCC36FF00162242 /* WalletData.swift in Sources */, 6DD410BF266CB13D0087DE03 /* Placeholders.swift in Sources */, 6DD410B0266CAF5C0087DE03 /* WalletInformationWidget.swift in Sources */, @@ -1605,7 +1597,7 @@ B44033E52BCC36FF00162242 /* WalletData.swift in Sources */, B44033EF2BCC374500162242 /* Numeric+abbreviated.swift in Sources */, B44033D02BCC352F00162242 /* UserDefaultsGroup.swift in Sources */, - B44033C52BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44033C52BCC332400162242 /* Balance.swift in Sources */, 6D4AF18425D215D1009DD853 /* UserDefaultsExtension.swift in Sources */, B4AB225D2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */, B40D4E5E2258425500428FCC /* NumericKeypadInterfaceController.swift in Sources */, @@ -1637,7 +1629,7 @@ B44033FD2BCC37D600162242 /* MarketAPI.swift in Sources */, B4A29A2D2B55C990002A67DF /* main.m in Sources */, B4A29A2E2B55C990002A67DF /* AppDelegate.mm in Sources */, - B44033C72BCC332400162242 /* CurrencyConverter.swift in Sources */, + B44033C72BCC332400162242 /* Balance.swift in Sources */, B44033FC2BCC379200162242 /* WidgetDataStore.swift in Sources */, B44033C22BCC32F800162242 /* BitcoinUnit.swift in Sources */, B44033F12BCC374500162242 /* Numeric+abbreviated.swift in Sources */, @@ -1690,12 +1682,6 @@ target = B4A29A212B55C990002A67DF /* BlueWallet-NoLDK */; targetProxy = B49038D62B8FBA2500A8164A /* PBXContainerItemProxy */; }; - B4A29A222B55C990002A67DF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - platformFilter = ios; - target = B40D4E2F225841EC00428FCC /* BlueWalletWatch */; - targetProxy = B4A29A232B55C990002A67DF /* PBXContainerItemProxy */; - }; B4A29A242B55C990002A67DF /* PBXTargetDependency */ = { isa = PBXTargetDependency; targetProxy = B4A29A252B55C990002A67DF /* PBXContainerItemProxy */; diff --git a/ios/BlueWalletWatch Extension/Objects/CurrencyConverter.swift b/ios/Shared/Balance.swift similarity index 100% rename from ios/BlueWalletWatch Extension/Objects/CurrencyConverter.swift rename to ios/Shared/Balance.swift diff --git a/ios/BlueWalletWatch Extension/Objects/BitcoinUnit.swift b/ios/Shared/BitcoinUnit.swift similarity index 100% rename from ios/BlueWalletWatch Extension/Objects/BitcoinUnit.swift rename to ios/Shared/BitcoinUnit.swift