Merge branch 'master' of github.com:BlueWallet/BlueWallet into refactor-app-storage

This commit is contained in:
overtorment 2024-04-16 20:52:52 +01:00
commit f65478da56
31 changed files with 762 additions and 468 deletions

View file

@ -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 /* 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 */; };
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 */
@ -151,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 */;
@ -310,21 +362,19 @@
6D641F2225525053003792DF /* WalletInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationView.swift; sourceTree = "<group>"; };
6D641F3425526311003792DF /* SendReceiveButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendReceiveButtons.swift; sourceTree = "<group>"; };
6D6CA4BC255872E3009312A5 /* PriceWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceWidget.swift; sourceTree = "<group>"; };
6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WidgetAPI+Electrum.swift"; sourceTree = "<group>"; };
6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarketAPI+Electrum.swift"; sourceTree = "<group>"; };
6D6CA5272558EC52009312A5 /* PriceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceView.swift; sourceTree = "<group>"; };
6D9946622555A660000E52E8 /* MarketWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketWidget.swift; sourceTree = "<group>"; };
6D9A2E06254BA347007B5B82 /* WalletInformationAndMarketWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationAndMarketWidget.swift; sourceTree = "<group>"; };
6D9A2E08254BA348007B5B82 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetAPI.swift; sourceTree = "<group>"; };
6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = "<group>"; };
6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketAPI.swift; sourceTree = "<group>"; };
6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroup.swift; sourceTree = "<group>"; };
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 = "<group>"; };
6DD410A4266CADF40087DE03 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6DD410AD266CAF1F0087DE03 /* fiatUnits.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = fiatUnits.json; path = ../../../../models/fiatUnits.json; sourceTree = "<group>"; };
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 = "<group>"; };
6DEB4BFA254FBA0E00E9F9AA /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; };
6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Placeholders.swift; sourceTree = "<group>"; };
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
6DF25A9E249DB97E001D06F5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
6DFC807124EA2FA9007B8700 /* ViewQRCodefaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewQRCodefaceController.swift; sourceTree = "<group>"; };
@ -375,6 +425,18 @@
B43D0376225847C500FBAA95 /* Wallet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
B43D0377225847C500FBAA95 /* WalletInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletInformation.swift; sourceTree = "<group>"; };
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 = "<group>"; };
B44033C32BCC332400162242 /* Balance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Balance.swift; sourceTree = "<group>"; };
B44033C92BCC350A00162242 /* Currency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = "<group>"; };
B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroupKey.swift; sourceTree = "<group>"; };
B44033DC2BCC36C300162242 /* LatestTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestTransaction.swift; sourceTree = "<group>"; };
B44033E32BCC36FF00162242 /* WalletData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletData.swift; sourceTree = "<group>"; };
B44033E82BCC371A00162242 /* MarketData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketData.swift; sourceTree = "<group>"; };
B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Numeric+abbreviated.swift"; sourceTree = "<group>"; };
B44033F32BCC377F00162242 /* WidgetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetData.swift; sourceTree = "<group>"; };
B44033F82BCC379200162242 /* WidgetDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = "<group>"; };
B44033FF2BCC37F800162242 /* Bundle+decode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+decode.swift"; sourceTree = "<group>"; };
B440340E2BCC40A400162242 /* fiatUnits.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = fiatUnits.json; path = ../../../models/fiatUnits.json; sourceTree = "<group>"; };
B4549F352B82B10D002E3153 /* ci_post_clone.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = ci_post_clone.sh; sourceTree = "<group>"; };
B461B850299599F800E431AA /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = BlueWallet/AppDelegate.h; sourceTree = "<group>"; };
B461B851299599F800E431AA /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = BlueWallet/AppDelegate.mm; sourceTree = "<group>"; };
@ -412,7 +474,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 +629,8 @@
6D2AA8062568B8E50090B089 /* Fiat */ = {
isa = PBXGroup;
children = (
6DD410AD266CAF1F0087DE03 /* fiatUnits.json */,
B440340E2BCC40A400162242 /* fiatUnits.json */,
B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */,
6D2AA8072568B8F40090B089 /* FiatUnit.swift */,
);
path = Fiat;
@ -625,16 +688,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 +709,7 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
B44033C82BCC34AC00162242 /* Shared */,
B41C2E552BB3DCB8000FE097 /* PrivacyInfo.xcprivacy */,
B4549F2E2B80FEA1002E3153 /* ci_scripts */,
13B07FAE1A68108700A75B9A /* BlueWallet */,
@ -766,6 +821,31 @@
path = Objects;
sourceTree = "<group>";
};
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 */,
B44033BE2BCC32F800162242 /* BitcoinUnit.swift */,
B44033C32BCC332400162242 /* Balance.swift */,
);
path = Shared;
sourceTree = "<group>";
};
B4549F2E2B80FEA1002E3153 /* ci_scripts */ = {
isa = PBXGroup;
children = (
@ -951,7 +1031,6 @@
buildRules = (
);
dependencies = (
B4A29A222B55C990002A67DF /* PBXTargetDependency */,
B4A29A242B55C990002A67DF /* PBXTargetDependency */,
B4A29A262B55C990002A67DF /* PBXTargetDependency */,
B4A29A282B55C990002A67DF /* PBXTargetDependency */,
@ -1037,7 +1116,7 @@
);
mainGroup = 83CBB9F61A601CBA00E9B192;
packageReferences = (
6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */,
6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */,
B41B76832B66B2FF002C48D5 /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */,
);
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
@ -1061,6 +1140,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 +1161,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 +1171,6 @@
buildActionMask = 2147483647;
files = (
B40D4E36225841ED00428FCC /* Assets.xcassets in Resources */,
E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */,
B40D4E34225841EC00428FCC /* Interface.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1101,8 +1180,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 +1197,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 +1500,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 /* Balance.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 +1532,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 /* Balance.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 +1573,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 /* Balance.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 +1618,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 /* Balance.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;
};
@ -1544,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 */;
@ -2074,7 +2206,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 +2255,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 +2302,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 +2349,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 +2627,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 +2648,7 @@
/* Begin XCSwiftPackageProductDependency section */
6DFC806F24EA0B6C007B8700 /* EFQRCode */ = {
isa = XCSwiftPackageProductDependency;
package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */;
package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */;
productName = EFQRCode;
};
B41B76842B66B2FF002C48D5 /* Bugsnag */ = {

View file

@ -102,7 +102,7 @@
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetFamily"
value = "systemMedium"
value = "systemSmall"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>

View file

@ -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)

35
ios/Shared/Balance.swift Normal file
View file

@ -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)")
}
}
}
}

View file

@ -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"
}

View file

@ -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<T: Decodable>(_ 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 {

57
ios/Shared/Currency.swift Normal file
View file

@ -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")
}
}

View file

@ -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
}

View file

@ -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?
}

View file

@ -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 {

199
ios/Shared/MarketAPI.swift Normal file
View file

@ -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<String, Any> 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<String, Any>, 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()
}
}

View file

@ -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"
}

View file

@ -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: "")
}
}

View file

@ -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)))

View file

@ -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\""
}

View file

@ -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)"
}
}
}

View file

@ -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()
}
}

View file

@ -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
}
}

View file

@ -29,10 +29,10 @@ struct WalletInformationWidgetProvider: TimelineProvider {
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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\""
}

View file

@ -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)

View file

@ -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

View file

@ -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<String, Any>),
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<String, Any>,
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<String, Any>,
let preferredCurrency = bpi[endPointKey] as? Dictionary<String, Any>,
let rateString = preferredCurrency["rate"] as? String,
let rateDouble = preferredCurrency["rate_float"] as? Double,
let time = json["time"] as? Dictionary<String, Any>,
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")
}
}

View file

@ -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()
}
}

View file

@ -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 {