diff --git a/Zircles.xcodeproj/project.pbxproj b/Zircles.xcodeproj/project.pbxproj index 72c1b4a..75a6c9d 100644 --- a/Zircles.xcodeproj/project.pbxproj +++ b/Zircles.xcodeproj/project.pbxproj @@ -14,16 +14,17 @@ 0D11D3D4249D05D800223146 /* Wedge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3D3249D05D800223146 /* Wedge.swift */; }; 0D11D3D7249D2F0B00223146 /* ZircleProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3D6249D2F0B00223146 /* ZircleProgress.swift */; }; 0D11D3D9249D51FC00223146 /* ZircleTextField_Preview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3D8249D51FC00223146 /* ZircleTextField_Preview.swift */; }; - 0D11D3DB249D5F1600223146 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3DA249D5F1600223146 /* ProgressBar.swift */; }; + 0D11D3DB249D5F1600223146 /* NeumorphicProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3DA249D5F1600223146 /* NeumorphicProgressBar.swift */; }; 0D11D3DD249D81B900223146 /* Pie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3DC249D81B900223146 /* Pie.swift */; }; 0D1366AC24991A6000F0EB54 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AB24991A6000F0EB54 /* AppDelegate.swift */; }; 0D1366AE24991A6000F0EB54 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AD24991A6000F0EB54 /* SceneDelegate.swift */; }; - 0D1366B024991A6000F0EB54 /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AF24991A6000F0EB54 /* SplashScreen.swift */; }; + 0D1366B024991A6000F0EB54 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AF24991A6000F0EB54 /* HomeScreen.swift */; }; 0D1366B224991A6100F0EB54 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D1366B124991A6100F0EB54 /* Assets.xcassets */; }; 0D1366B524991A6100F0EB54 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D1366B424991A6100F0EB54 /* Preview Assets.xcassets */; }; 0D1366B824991A6100F0EB54 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D1366B624991A6100F0EB54 /* LaunchScreen.storyboard */; }; 0D1366C324991A6200F0EB54 /* ZirclesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366C224991A6200F0EB54 /* ZirclesTests.swift */; }; 0D1366CE24991A6200F0EB54 /* ZirclesUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366CD24991A6200F0EB54 /* ZirclesUITests.swift */; }; + 0D3FB6FE24A4CD4E0034A52A /* MockEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D3FB6FD24A4CD4E0034A52A /* MockEnvironment.swift */; }; 0D5142C324A0F0B800F9AE2E /* Zboto.otf in Resources */ = {isa = PBXBuildFile; fileRef = 0D5142C224A0F0B800F9AE2E /* Zboto.otf */; }; 0D5142C624A14D0F00F9AE2E /* CreateNewZircleNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D5142C524A14D0F00F9AE2E /* CreateNewZircleNameView.swift */; }; 0D5142C824A16F9600F9AE2E /* CreateNewTypeOfZircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D5142C724A16F9600F9AE2E /* CreateNewTypeOfZircle.swift */; }; @@ -48,6 +49,11 @@ 0D6A22C7249AB36100B4E946 /* ZcashButtonBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22C6249AB36100B4E946 /* ZcashButtonBackground.swift */; }; 0D6A22C9249AB3CA00B4E946 /* ZcashButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22C8249AB3CA00B4E946 /* ZcashButton.swift */; }; 0D6A22CB249AB61200B4E946 /* Glow_Preview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22CA249AB61200B4E946 /* Glow_Preview.swift */; }; + 0DB5330F24A623AF0090D722 /* sapling-spend.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330D24A623AF0090D722 /* sapling-spend.params */; }; + 0DB5331024A623AF0090D722 /* sapling-output.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330E24A623AF0090D722 /* sapling-output.params */; }; + 0DB5331224A6413D0090D722 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB5331124A6413D0090D722 /* LazyView.swift */; }; + 0DD7278924A5532300C36D27 /* AllZirclesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7278824A5532300C36D27 /* AllZirclesView.swift */; }; + 0DD7278B24A564AF00C36D27 /* ZircleListCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */; }; 0DEE59A824A24B7300447C15 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DEE59A724A24B7300447C15 /* WelcomeView.swift */; }; 0DEE59AA24A2B90F00447C15 /* CreateNewZircleDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DEE59A924A2B90F00447C15 /* CreateNewZircleDescription.swift */; }; 450B0C2B71526C48C265CB70 /* Pods_Zircles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 897CFDF9BD39874744EF71AB /* Pods_Zircles.framework */; }; @@ -78,12 +84,12 @@ 0D11D3D3249D05D800223146 /* Wedge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wedge.swift; sourceTree = ""; }; 0D11D3D6249D2F0B00223146 /* ZircleProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleProgress.swift; sourceTree = ""; }; 0D11D3D8249D51FC00223146 /* ZircleTextField_Preview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleTextField_Preview.swift; sourceTree = ""; }; - 0D11D3DA249D5F1600223146 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; + 0D11D3DA249D5F1600223146 /* NeumorphicProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicProgressBar.swift; sourceTree = ""; }; 0D11D3DC249D81B900223146 /* Pie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pie.swift; sourceTree = ""; }; 0D1366A824991A6000F0EB54 /* Zircles.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Zircles.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D1366AB24991A6000F0EB54 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0D1366AD24991A6000F0EB54 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - 0D1366AF24991A6000F0EB54 /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreen.swift; sourceTree = ""; }; + 0D1366AF24991A6000F0EB54 /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = ""; }; 0D1366B124991A6100F0EB54 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0D1366B424991A6100F0EB54 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0D1366B724991A6100F0EB54 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -94,6 +100,7 @@ 0D1366C924991A6200F0EB54 /* ZirclesUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZirclesUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0D1366CD24991A6200F0EB54 /* ZirclesUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZirclesUITests.swift; sourceTree = ""; }; 0D1366CF24991A6200F0EB54 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0D3FB6FD24A4CD4E0034A52A /* MockEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockEnvironment.swift; sourceTree = ""; }; 0D5142C224A0F0B800F9AE2E /* Zboto.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Zboto.otf; sourceTree = ""; }; 0D5142C524A14D0F00F9AE2E /* CreateNewZircleNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateNewZircleNameView.swift; sourceTree = ""; }; 0D5142C724A16F9600F9AE2E /* CreateNewTypeOfZircle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateNewTypeOfZircle.swift; sourceTree = ""; }; @@ -118,6 +125,11 @@ 0D6A22C6249AB36100B4E946 /* ZcashButtonBackground.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashButtonBackground.swift; sourceTree = ""; }; 0D6A22C8249AB3CA00B4E946 /* ZcashButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashButton.swift; sourceTree = ""; }; 0D6A22CA249AB61200B4E946 /* Glow_Preview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glow_Preview.swift; sourceTree = ""; }; + 0DB5330D24A623AF0090D722 /* sapling-spend.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-spend.params"; sourceTree = ""; }; + 0DB5330E24A623AF0090D722 /* sapling-output.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-output.params"; sourceTree = ""; }; + 0DB5331124A6413D0090D722 /* LazyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = ""; }; + 0DD7278824A5532300C36D27 /* AllZirclesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllZirclesView.swift; sourceTree = ""; }; + 0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleListCard.swift; sourceTree = ""; }; 0DEE59A724A24B7300447C15 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; 0DEE59A924A2B90F00447C15 /* CreateNewZircleDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateNewZircleDescription.swift; sourceTree = ""; }; 5A3D0DB1D10FF551A7DE4766 /* Pods-Zircles-ZirclesUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Zircles-ZirclesUITests.release.xcconfig"; path = "Target Support Files/Pods-Zircles-ZirclesUITests/Pods-Zircles-ZirclesUITests.release.xcconfig"; sourceTree = ""; }; @@ -172,6 +184,7 @@ 0D11D3D5249D2E0400223146 /* Utils */ = { isa = PBXGroup; children = ( + 0DB5331124A6413D0090D722 /* LazyView.swift */, 0D64CEB224A3CDA90080AA4F /* BalanceUtils.swift */, 0D64CEB124A3CDA90080AA4F /* CameraAccessHelper.swift */, 0D64CEAE24A3CDA80080AA4F /* MnemonicSeedPhraseHandling.swift */, @@ -186,6 +199,7 @@ 0D6A22CA249AB61200B4E946 /* Glow_Preview.swift */, 0D64CEC024A3F2580080AA4F /* FirstScreen.swift */, 0D64CEC224A4137D0080AA4F /* ZircleData.swift */, + 0D3FB6FD24A4CD4E0034A52A /* MockEnvironment.swift */, ); path = Utils; sourceTree = ""; @@ -215,6 +229,8 @@ 0D1366AA24991A6000F0EB54 /* Zircles */ = { isa = PBXGroup; children = ( + 0DB5330E24A623AF0090D722 /* sapling-output.params */, + 0DB5330D24A623AF0090D722 /* sapling-spend.params */, 0D64CEBE24A3D3A30080AA4F /* CombineSynchronizer.swift */, 0D64CEA724A3CD040080AA4F /* Environment */, 0D5142C424A1323900F9AE2E /* Views */, @@ -262,12 +278,13 @@ 0D5142C424A1323900F9AE2E /* Views */ = { isa = PBXGroup; children = ( - 0D1366AF24991A6000F0EB54 /* SplashScreen.swift */, + 0D1366AF24991A6000F0EB54 /* HomeScreen.swift */, 0D5142C524A14D0F00F9AE2E /* CreateNewZircleNameView.swift */, 0D5142C724A16F9600F9AE2E /* CreateNewTypeOfZircle.swift */, 0DEE59A724A24B7300447C15 /* WelcomeView.swift */, 0DEE59A924A2B90F00447C15 /* CreateNewZircleDescription.swift */, 0D64CEC424A41AF30080AA4F /* AppDetails.swift */, + 0DD7278824A5532300C36D27 /* AllZirclesView.swift */, ); path = Views; sourceTree = ""; @@ -288,6 +305,7 @@ 0D6A22C6249AB36100B4E946 /* ZcashButtonBackground.swift */, 0D6A22C4249AB1FC00B4E946 /* ZcashSymbol.swift */, 0D64CEA524A3854C0080AA4F /* ZircleOptionSelector.swift */, + 0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */, ); path = Components; sourceTree = ""; @@ -295,7 +313,7 @@ 0D6A22CC249ACD6C00B4E946 /* Neumorphic */ = { isa = PBXGroup; children = ( - 0D11D3DA249D5F1600223146 /* ProgressBar.swift */, + 0D11D3DA249D5F1600223146 /* NeumorphicProgressBar.swift */, 0D11D3CD249C294E00223146 /* NeumorphicButtons.swift */, 0D11D3CF249C3AE300223146 /* Card.swift */, 0D11D3D1249CE6C800223146 /* GlowEffect.swift */, @@ -430,7 +448,9 @@ 0D1366B824991A6100F0EB54 /* LaunchScreen.storyboard in Resources */, 0D1366B524991A6100F0EB54 /* Preview Assets.xcassets in Resources */, 0D5142C324A0F0B800F9AE2E /* Zboto.otf in Resources */, + 0DB5331024A623AF0090D722 /* sapling-output.params in Resources */, 0D1366B224991A6100F0EB54 /* Assets.xcassets in Resources */, + 0DB5330F24A623AF0090D722 /* sapling-spend.params in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -574,16 +594,20 @@ 0D11D3D0249C3AE400223146 /* Card.swift in Sources */, 0D64CEB724A3CDA90080AA4F /* QRCodeGenerator.swift in Sources */, 0D64CEBF24A3D3A30080AA4F /* CombineSynchronizer.swift in Sources */, + 0DD7278B24A564AF00C36D27 /* ZircleListCard.swift in Sources */, 0D6A22CB249AB61200B4E946 /* Glow_Preview.swift in Sources */, 0D5142C624A14D0F00F9AE2E /* CreateNewZircleNameView.swift in Sources */, 0DEE59AA24A2B90F00447C15 /* CreateNewZircleDescription.swift in Sources */, + 0DD7278924A5532300C36D27 /* AllZirclesView.swift in Sources */, + 0D3FB6FE24A4CD4E0034A52A /* MockEnvironment.swift in Sources */, 0D11D3D7249D2F0B00223146 /* ZircleProgress.swift in Sources */, 0D11D3D9249D51FC00223146 /* ZircleTextField_Preview.swift in Sources */, 0D64CEC124A3F2580080AA4F /* FirstScreen.swift in Sources */, 0D64CEBA24A3CDA90080AA4F /* zECC+SwiftUI.swift in Sources */, 0D11D3D2249CE6C800223146 /* GlowEffect.swift in Sources */, 0D64CEB524A3CDA90080AA4F /* String+Zcash.swift in Sources */, - 0D11D3DB249D5F1600223146 /* ProgressBar.swift in Sources */, + 0DB5331224A6413D0090D722 /* LazyView.swift in Sources */, + 0D11D3DB249D5F1600223146 /* NeumorphicProgressBar.swift in Sources */, 0D64CEBD24A3CDA90080AA4F /* SimpleLogger.swift in Sources */, 0D64CEBC24A3CDA90080AA4F /* BalanceUtils.swift in Sources */, 0D5142C824A16F9600F9AE2E /* CreateNewTypeOfZircle.swift in Sources */, @@ -591,7 +615,7 @@ 0D64CEB424A3CDA90080AA4F /* SeedManagement.swift in Sources */, 0D64CEC324A4137D0080AA4F /* ZircleData.swift in Sources */, 0D64CEA924A3CD1B0080AA4F /* ZirclesEnvironment.swift in Sources */, - 0D1366B024991A6000F0EB54 /* SplashScreen.swift in Sources */, + 0D1366B024991A6000F0EB54 /* HomeScreen.swift in Sources */, 0DEE59A824A24B7300447C15 /* WelcomeView.swift in Sources */, 0D64CEA624A3854C0080AA4F /* ZircleOptionSelector.swift in Sources */, ); diff --git a/Zircles/Assets.xcassets/Invite.imageset/Contents.json b/Zircles/Assets.xcassets/Invite.imageset/Contents.json new file mode 100644 index 0000000..ef9b299 --- /dev/null +++ b/Zircles/Assets.xcassets/Invite.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Invite.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Zircles/Assets.xcassets/Invite.imageset/Invite.jpg b/Zircles/Assets.xcassets/Invite.imageset/Invite.jpg new file mode 100644 index 0000000..3fb5a92 Binary files /dev/null and b/Zircles/Assets.xcassets/Invite.imageset/Invite.jpg differ diff --git a/Zircles/Assets.xcassets/downchart.imageset/Contents.json b/Zircles/Assets.xcassets/downchart.imageset/Contents.json new file mode 100644 index 0000000..1b738d7 --- /dev/null +++ b/Zircles/Assets.xcassets/downchart.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "downchart.pdf", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Zircles/Assets.xcassets/downchart.imageset/downchart.pdf b/Zircles/Assets.xcassets/downchart.imageset/downchart.pdf new file mode 100644 index 0000000..eebf785 Binary files /dev/null and b/Zircles/Assets.xcassets/downchart.imageset/downchart.pdf differ diff --git a/Zircles/Assets.xcassets/join.imageset/Contents.json b/Zircles/Assets.xcassets/join.imageset/Contents.json new file mode 100644 index 0000000..0f0c778 --- /dev/null +++ b/Zircles/Assets.xcassets/join.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "join.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Zircles/Assets.xcassets/join.imageset/join.jpg b/Zircles/Assets.xcassets/join.imageset/join.jpg new file mode 100644 index 0000000..0e0394d Binary files /dev/null and b/Zircles/Assets.xcassets/join.imageset/join.jpg differ diff --git a/Zircles/Assets.xcassets/upchart.imageset/Contents.json b/Zircles/Assets.xcassets/upchart.imageset/Contents.json new file mode 100644 index 0000000..b516b89 --- /dev/null +++ b/Zircles/Assets.xcassets/upchart.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "upchart.pdf", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Zircles/Assets.xcassets/upchart.imageset/upchart.pdf b/Zircles/Assets.xcassets/upchart.imageset/upchart.pdf new file mode 100644 index 0000000..3a3e490 Binary files /dev/null and b/Zircles/Assets.xcassets/upchart.imageset/upchart.pdf differ diff --git a/Zircles/Colors+Zircles.swift b/Zircles/Colors+Zircles.swift index 06b18ac..d2cedf5 100644 --- a/Zircles/Colors+Zircles.swift +++ b/Zircles/Colors+Zircles.swift @@ -10,7 +10,7 @@ import Foundation import SwiftUI extension Color { - static let background = Color(#colorLiteral(red: 0.8931570649, green: 0.9219855666, blue: 0.9563117623, alpha: 1)) + static let background = Color(#colorLiteral(red: 0.8941176471, green: 0.9411764706, blue: 0.9568627451, alpha: 1)) static let shadowBackground = Color(#colorLiteral(red: 0.8572473526, green: 0.8862729073, blue: 0.9295067191, alpha: 1)) static let buttonBlue = Color(#colorLiteral(red: 0.2486506402, green: 0.3574069142, blue: 0.5763935447, alpha: 1)) static let buttonGray = Color(#colorLiteral(red: 0.5530887246, green: 0.622399509, blue: 0.7596352696, alpha: 1)) diff --git a/Zircles/Components/ZircleListCard.swift b/Zircles/Components/ZircleListCard.swift new file mode 100644 index 0000000..49429ed --- /dev/null +++ b/Zircles/Components/ZircleListCard.swift @@ -0,0 +1,56 @@ +// +// ZircleListCard.swift +// Zircles +// +// Created by Francisco Gindre on 6/25/20. +// Copyright © 2020 Electric Coin Company. All rights reserved. +// + +import SwiftUI + +struct ZircleListCard: View { + var name: String + var progress: Double + + @State var isPressed = false + var body: some View { + Toggle(isOn: $isPressed) { + HStack(spacing: 16) { + Toggle(isOn: $isPressed) { + if progress < 0.5 { + Image("downchart") + .renderingMode(.original) + } else { + Image("upchart") + .renderingMode(.original) + } + }.toggleStyle(SimpleToggleStyle(shape: RoundedRectangle(cornerRadius: 10, style: .continuous), padding: 16)) + VStack { + HStack { + Text(name) + .foregroundColor(.zGray) + .shadow(radius: 1) + Text("\(Int(progress))%") + .foregroundColor(.zGray) + .shadow(radius: 1) + } + NeumorphicProgressBar(progress: .constant(CGFloat(progress)), fillStyle: progress < 0.5 ? Color.red : Color.green ) + .frame(minWidth: 100, idealWidth: 100, maxWidth: .infinity, minHeight: 5, idealHeight: 5, maxHeight: 5, alignment: .center) + } + } + } + .toggleStyle(SimpleToggleStyle(shape: RoundedRectangle(cornerRadius: 10, style: .continuous),padding:16)) + } +} + +struct ZircleListCard_Previews: PreviewProvider { + static var previews: some View { + ZStack { + Color.background + Group { + ZircleListCard(name: "Hackathon Drinks", progress: 0.5) + ZircleListCard(name: "Long-term Circle", progress: 0.02) + } + } + } +} diff --git a/Zircles/Environment/ZirclesEnvironment.swift b/Zircles/Environment/ZirclesEnvironment.swift index 1fa1241..1ffb909 100644 --- a/Zircles/Environment/ZirclesEnvironment.swift +++ b/Zircles/Environment/ZirclesEnvironment.swift @@ -18,7 +18,12 @@ enum WalletState { } protocol AppEnvironment { - + func createNewWallet() throws + func nuke(abortApplication: Bool) + func getMainAddress() -> String + func getUsername() -> String + func getMainSeedPhrase() -> String + func getLatestHeight() -> Int64 } final class ZirclesEnvironment: ObservableObject { @@ -33,7 +38,7 @@ final class ZirclesEnvironment: ObservableObject { static var shared: ZirclesEnvironment = try! ZirclesEnvironment() // app can't live without this existing. @Published var state: WalletState - + var errorPublisher = PassthroughSubject() let endpoint = LightWalletEndpoint(address: ZcashSDK.isMainnet ? "lightwalletd.z.cash" : "lightwalletd.testnet.z.cash", port: 9067, secure: true) var dataDbURL: URL var cacheDbURL: URL @@ -123,6 +128,27 @@ final class ZirclesEnvironment: ObservableObject { self.synchronizer.start() } + static var appBuild: String? { + Bundle.main.infoDictionary?["CFBundleVersion"] as? String + } + + static var appVersion: String? { + Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + } + + func isValidAddress(_ address: String) -> Bool { + self.initializer.isValidShieldedAddress(address) || self.initializer.isValidTransparentAddress(address) + } + func sufficientFundsToSend(amount: Double) -> Bool { + return sufficientFunds(availableBalance: self.initializer.getVerifiedBalance(), zatoshiToSend: amount.toZatoshi()) + } + private func sufficientFunds(availableBalance: Int64, zatoshiToSend: Int64) -> Bool { + availableBalance - zatoshiToSend - Int64(ZcashSDK.MINERS_FEE_ZATOSHI) >= 0 + } + static var minerFee: Double { + Int64(ZcashSDK.MINERS_FEE_ZATOSHI).asHumanReadableZecBalance() + } + /** only for internal use */ @@ -152,6 +178,16 @@ final class ZirclesEnvironment: ObservableObject { } } + + deinit { + cancellables.forEach { + c in + c.cancel() + } + } + +} +extension Error { static func mapError(error: Error) -> ZirclesEnvironment.WalletError { if let rustError = error as? RustWeldingError { @@ -167,55 +203,50 @@ final class ZirclesEnvironment: ObservableObject { case .malformedStringInput: return ZirclesEnvironment.WalletError.genericError(message: "Malformed address or key detected") default: - return WalletError.genericError(message: "\(rustError)") + return ZirclesEnvironment.WalletError.genericError(message: "\(rustError)") } } else if let synchronizerError = error as? SynchronizerError { switch synchronizerError { case .generalError(let message): return ZirclesEnvironment.WalletError.genericError(message: message) case .initFailed(let message): - return WalletError.initializationFailed(message: "Synchronizer failed to initialize: \(message)") + return ZirclesEnvironment.WalletError.initializationFailed(message: "Synchronizer failed to initialize: \(message)") case .syncFailed: - return WalletError.genericError(message: "Synchronizing failed") + return ZirclesEnvironment.WalletError.genericError(message: "Synchronizing failed") case .connectionFailed(let message): - return WalletError.connectionFailed(message: message) + return ZirclesEnvironment.WalletError.connectionFailed(message: message) case .maxRetryAttemptsReached(attempts: let attempts): - return WalletError.maxRetriesReached(attempts: attempts) + return ZirclesEnvironment.WalletError.maxRetriesReached(attempts: attempts) case .connectionError(_, let message): - return WalletError.connectionFailed(message: message) + return ZirclesEnvironment.WalletError.connectionFailed(message: message) } } - return ZirclesEnvironment.WalletError.genericError(message: Self.genericErrorMessage) + return ZirclesEnvironment.WalletError.genericError(message: ZirclesEnvironment.genericErrorMessage) } - deinit { - cancellables.forEach { - c in - c.cancel() +} + +extension ZirclesEnvironment: AppEnvironment { + func getMainAddress() -> String { + self.initializer.getAddress(index: 0) ?? "No address!!" + } + + func getUsername() -> String { + ZircleDataStorage.default.username + } + + func getMainSeedPhrase() -> String { + guard let phrase = try? SeedManager.default.exportPhrase() else { + return "no phrase" } + return phrase } + func getLatestHeight() -> Int64 { + Int64(synchronizer.syncBlockHeight.value) + } + + } -extension ZirclesEnvironment { - static var appBuild: String? { - Bundle.main.infoDictionary?["CFBundleVersion"] as? String - } - - static var appVersion: String? { - Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String - } - - func isValidAddress(_ address: String) -> Bool { - self.initializer.isValidShieldedAddress(address) || self.initializer.isValidTransparentAddress(address) - } - func sufficientFundsToSend(amount: Double) -> Bool { - return sufficientFunds(availableBalance: self.initializer.getVerifiedBalance(), zatoshiToSend: amount.toZatoshi()) - } - private func sufficientFunds(availableBalance: Int64, zatoshiToSend: Int64) -> Bool { - availableBalance - zatoshiToSend - Int64(ZcashSDK.MINERS_FEE_ZATOSHI) >= 0 - } - static var minerFee: Double { - Int64(ZcashSDK.MINERS_FEE_ZATOSHI).asHumanReadableZecBalance() - } -} + diff --git a/Zircles/Neumorphic/NeumorphicButtons.swift b/Zircles/Neumorphic/NeumorphicButtons.swift index 8458778..1c7bfb8 100644 --- a/Zircles/Neumorphic/NeumorphicButtons.swift +++ b/Zircles/Neumorphic/NeumorphicButtons.swift @@ -1,7 +1,7 @@ import SwiftUI extension Color { - static let offWhite = Color(red: 225 / 255, green: 225 / 255, blue: 235 / 255) + static let offWhite = Color(red: 228 / 255, green: 240 / 255, blue: 250 / 255) static let darkStart = Color(red: 50 / 255, green: 60 / 255, blue: 65 / 255) static let darkEnd = Color(red: 25 / 255, green: 25 / 255, blue: 30 / 255) diff --git a/Zircles/Neumorphic/ProgressBar.swift b/Zircles/Neumorphic/NeumorphicProgressBar.swift similarity index 86% rename from Zircles/Neumorphic/ProgressBar.swift rename to Zircles/Neumorphic/NeumorphicProgressBar.swift index 29dd112..821aa81 100644 --- a/Zircles/Neumorphic/ProgressBar.swift +++ b/Zircles/Neumorphic/NeumorphicProgressBar.swift @@ -8,8 +8,9 @@ import SwiftUI -struct ProgressBar: View { +struct NeumorphicProgressBar: View { @Binding var progress: CGFloat + var fillStyle: S var body: some View { GeometryReader { geometry in @@ -29,7 +30,7 @@ struct ProgressBar: View { } .stroke(style: .init(lineWidth: geometry.size.height, lineCap: .round)) - .fill(LinearGradient.zButtonGradient) + .fill(self.fillStyle) } } @@ -45,7 +46,7 @@ struct ProgressBar_Previews: PreviewProvider { cornerRadius: 15, padding: 5 ) { - ProgressBar(progress: .constant(0.6)) + NeumorphicProgressBar(progress: .constant(0.6), fillStyle: LinearGradient.zButtonGradient) .animation(.easeInOut) .frame(height: 30) .padding(.horizontal) diff --git a/Zircles/SceneDelegate.swift b/Zircles/SceneDelegate.swift index c19e493..fed1e3d 100644 --- a/Zircles/SceneDelegate.swift +++ b/Zircles/SceneDelegate.swift @@ -18,22 +18,33 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - + _ZirclesNavigationBarLookTweaks() // Create the SwiftUI view that provides the window contents. let isInitialized = ZirclesEnvironment.isInitialized() let contentView = FirstScreen() { if isInitialized { - SplashScreen() + HomeScreen() +// AllZirclesView( +// zircles: [ +// ZircleSummary(progress: 0.5, name: "Hackathon Drinks", paymentDue: false), +// ZircleSummary(progress: 0.02, name: "Long-term Circle", paymentDue: true) +// +// ] +// ) } else { WelcomeView() } } - + if isInitialized { + try? ZirclesEnvironment.shared.initialize() + ZirclesEnvironment.shared.synchronizer.start() + } // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) self.window = window + window.makeKeyAndVisible() } } @@ -69,3 +80,33 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } + +extension UIApplication { + func endEditing() { + sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } +} + +func _ZirclesNavigationBarLookTweaks() { +//// let appearance = UINavigationBarAppearance() +//// appearance.configureWithTransparentBackground() +//// appearance.largeTitleTextAttributes = [ +//// .font : UIFont.systemFont(ofSize: 20), +//// NSAttributedString.Key.foregroundColor : UIColor.white +//// ] +//// +//// appearance.titleTextAttributes = [ +//// .font : UIFont.systemFont(ofSize: 20), +//// NSAttributedString.Key.foregroundColor : UIColor.white +//// ] +//// +// UINavigationBar.appearance().scrollEdgeAppearance = appearance +// UINavigationBar.appearance().standardAppearance = appearance +// + + let clearView = UIView() + clearView.backgroundColor = UIColor.clear + UITableViewCell.appearance().selectedBackgroundView = clearView + UITableView.appearance().backgroundColor = UIColor.clear +} + diff --git a/Zircles/Utils/LazyView.swift b/Zircles/Utils/LazyView.swift new file mode 100644 index 0000000..ec9eb05 --- /dev/null +++ b/Zircles/Utils/LazyView.swift @@ -0,0 +1,19 @@ +// +// LazyView.swift +// wallet +// +// Created by Francisco Gindre on 3/19/20. +// Copyright © 2020 Francisco Gindre. All rights reserved. +// + +import SwiftUI + +struct LazyView: View { + let build: () -> Content + init(_ build: @autoclosure @escaping () -> Content) { + self.build = build + } + var body: Content { + build() + } +} diff --git a/Zircles/Utils/MockEnvironment.swift b/Zircles/Utils/MockEnvironment.swift new file mode 100644 index 0000000..1231000 --- /dev/null +++ b/Zircles/Utils/MockEnvironment.swift @@ -0,0 +1,27 @@ +// +// MockEnvironment.swift +// Zircles +// +// Created by Francisco Gindre on 6/25/20. +// Copyright © 2020 Electric Coin Company. All rights reserved. +// + +import Foundation + +class MockAppEnvironment: AppEnvironment, ObservableObject { + func createNewWallet() throws {} + func nuke(abortApplication: Bool) {} + func getMainAddress() -> String { + "zsFakefejaefnq2rrneferjgbrauiebnfiosjebfeyetqoq3" + } + func getUsername() -> String { + "pacu" + } + func getMainSeedPhrase() -> String { + "kitchen renew wide common vague fold vacuum tilt amazing pear square gossip jewel month tree shock scan alpha just spot fluid toilet view dinner" + } + + func getLatestHeight() -> Int64 { + 999999 + } +} diff --git a/Zircles/Views/AllZirclesView.swift b/Zircles/Views/AllZirclesView.swift new file mode 100644 index 0000000..bbc50c3 --- /dev/null +++ b/Zircles/Views/AllZirclesView.swift @@ -0,0 +1,111 @@ +// +// AllZirclesView.swift +// Zircles +// +// Created by Francisco Gindre on 6/25/20. +// Copyright © 2020 Electric Coin Company. All rights reserved. +// + +import SwiftUI +import UIKit +struct ZircleSummary { + var progress: Double + var name: String + var paymentDue: Bool +} +struct AllZirclesView: View { + @State var detailsActive = false + var zircles: [ZircleSummary] + var paymentsDueLegend: String { + let paymentsDue = zircles.filter({ $0.paymentDue}).count + return "You Have \(zircles.count) \( zircles.count > 1 ? "Zircles" : "Zircle"). \(paymentsDue > 0 ? String(paymentsDue) : "No") \(paymentsDue == 1 ? "payment" : "payments") due" + } + var body: some View { + ZStack { + Color.background.edgesIgnoringSafeArea(.all) + VStack(alignment: .leading, spacing: 24) { + HStack { + + FancyLogo(progress: .constant(0.75)) + .scaleEffect(0.3) + .disabled(true) + .background(EmptyView()) + + Text(paymentsDueLegend) + .lineLimit(2) + .foregroundColor(.black) + .font(.title) + + } + .frame(height: 50) + + + List { + ForEach(0 ..< zircles.count) { index in + VStack { + ZircleListCard(summary: zircles[index]) + } + .padding(.vertical, 30) + .listRowBackground(Color.clear) + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + + + } + } + + } + + } + .onAppear() { + + UITableView.appearance().separatorStyle = .none + UITableView.appearance().backgroundColor = UIColor.clear + + } + .onDisappear() { + UITableView.appearance().separatorStyle = .singleLine + UITableView.appearance().backgroundColor = UIColor.white + + } + .navigationBarTitle("", displayMode: .inline) + .sheet(isPresented: $detailsActive) { + AppDetails(isActive: $detailsActive,appEnvironment: MockAppEnvironment()) + } + .navigationBarBackButtonHidden(true) + .navigationBarItems(trailing: Button(action: { + self.detailsActive = true + }){ + Image(systemName: "z.circle") + .frame(width: 30, height: 30, alignment: .center) + + } + .contentShape(Circle()) + ) + .sheet(isPresented: $detailsActive) { + AppDetails(isActive: $detailsActive,appEnvironment: MockAppEnvironment()) + } + + } +} + +extension ZircleListCard { + init(summary: ZircleSummary) { + self.name = summary.name + self.progress = summary.progress + } +} +struct AllZirclesView_Previews: PreviewProvider { + static var previews: some View { + NavigationView { + ZStack{ + AllZirclesView( + zircles: [ + ZircleSummary(progress: 0.5, name: "Hackathon Drinks", paymentDue: false), + ZircleSummary(progress: 0.02, name: "Long-term Circle", paymentDue: true) + + ] + ) + } + } + } +} diff --git a/Zircles/Views/AppDetails.swift b/Zircles/Views/AppDetails.swift index d243572..87da8a0 100644 --- a/Zircles/Views/AppDetails.swift +++ b/Zircles/Views/AppDetails.swift @@ -10,75 +10,126 @@ import SwiftUI struct AppDetails: View { @State var showNukeAlert = false - + @Binding var isActive: Bool + var appEnvironment: AppEnvironment var body: some View { - ZStack { - Color.background.edgesIgnoringSafeArea(.all) - - VStack { - VStack(alignment: .leading, spacing: 3) { - Text("Username") - .foregroundColor(.textLightGray) - .fontWeight(.heavy) - .font(.footnote) - .frame(alignment: .leading) - Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { - - Text(ZircleDataStorage.default.username) - .foregroundColor(Color.textDarkGray) - .font(.system(size: 14, weight: .heavy, design: .default)) - - } - }.padding(.all, 0) - VStack(alignment: .leading, spacing: 3) { - Text("App Version") - .foregroundColor(.textLightGray) - .fontWeight(.heavy) - .font(.footnote) - .frame(alignment: .leading) - Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { - - Text("Zircles v\(ZirclesEnvironment.appVersion ?? "Unknown") - Build: \(ZirclesEnvironment.appBuild ?? "Unknown")") - .foregroundColor(Color.textDarkGray) - .font(.system(size: 14, weight: .heavy, design: .default)) - - } - }.padding(.all, 0) + NavigationView { + ZStack { + Color.background.edgesIgnoringSafeArea(.all) - Button(action: { - self.showNukeAlert = true - }) { - Text("NUKE WALLET") - .foregroundColor(.red) - .zcashButtonBackground(shape: .roundedCorners(fillStyle: .outline(color: .red, lineWidth: 2))) - .frame(height: 48) - }.alert(isPresented: $showNukeAlert) { - Alert(title: Text("Delete Wallet?"), - message: Text("You are about to")+Text(" nuke your wallet. ").foregroundColor(.red) + Text("Are you sure you want to proceed?"), - primaryButton: .default( - Text("I'm not sure") - ,action: { self.showNukeAlert = false} - ), - secondaryButton: .destructive( - Text("NUKE WALLET!"), - action: { - ZirclesEnvironment.shared.nuke(abortApplication: true) - } - ) - ) + VStack(alignment: .leading, spacing: 12) { + VStack(alignment: .leading, spacing: 3) { + Text("Username") + .foregroundColor(.textLightGray) + .fontWeight(.heavy) + .font(.footnote) + .frame(alignment: .leading) + Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { + + Text(appEnvironment.getUsername()) + .foregroundColor(Color.textDarkGray) + .font(.system(size: 14, weight: .heavy, design: .default)) + + } + }.padding(.all, 0) + VStack(alignment: .leading, spacing: 3) { + Text("Main Account zAddress") + .foregroundColor(.textLightGray) + .fontWeight(.heavy) + .font(.footnote) + .frame(alignment: .leading) + Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { + + Text(appEnvironment.getMainAddress()) + .foregroundColor(Color.textDarkGray) + .font(.system(size: 14, weight: .heavy, design: .default)) + + } + }.padding(.all, 0) + VStack(alignment: .leading, spacing: 3) { + Text("Latest Downloaded Height") + .foregroundColor(.textLightGray) + .fontWeight(.heavy) + .font(.footnote) + .frame(alignment: .leading) + Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { + + Text("999999") + .foregroundColor(Color.textDarkGray) + .font(.system(size: 14, weight: .heavy, design: .default)) + + } + }.padding(.all, 0) + + VStack(alignment: .leading, spacing: 3) { + Text("Main Account Seed Phrase") + .foregroundColor(.textLightGray) + .fontWeight(.heavy) + .font(.footnote) + .frame(alignment: .leading) + Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { + + Text(appEnvironment.getMainSeedPhrase()) + .foregroundColor(Color.textDarkGray) + .font(.system(size: 14, weight: .heavy, design: .default)) + + } + }.padding(.all, 0) + VStack(alignment: .leading, spacing: 3) { + Text("App Version") + .foregroundColor(.textLightGray) + .fontWeight(.heavy) + .font(.footnote) + .frame(alignment: .leading) + Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { + + Text("Zircles v\(ZirclesEnvironment.appVersion ?? "Unknown") - Build: \(ZirclesEnvironment.appBuild ?? "Unknown")") + .foregroundColor(Color.textDarkGray) + .font(.system(size: 14, weight: .heavy, design: .default)) + + } + }.padding(.all, 0) + Spacer() + Button(action: { + self.showNukeAlert = true + }) { + Text("NUKE WALLET") + .foregroundColor(.red) + .zcashButtonBackground(shape: .roundedCorners(fillStyle: .outline(color: .red, lineWidth: 2))) + .frame(height: 48) + }.alert(isPresented: $showNukeAlert) { + Alert(title: Text("Delete Wallet?"), + message: Text("You are about to")+Text(" nuke your wallet. ").foregroundColor(.red) + Text("Are you sure you want to proceed?"), + primaryButton: .default( + Text("I'm not sure") + ,action: { self.showNukeAlert = false} + ), + secondaryButton: .destructive( + Text("NUKE WALLET!"), + action: { + ZirclesEnvironment.shared.nuke(abortApplication: true) + } + ) + ) + } } + .padding([.horizontal,.bottom], 30) } - }.navigationBarTitle(Text("Backstage")) - .navigationBarItems(trailing: Button(action:{ - - }){ - Text("close") - }) + .navigationBarTitle(Text("Backstage")) + .navigationBarItems(trailing: Button(action:{ + + }){ + Text("close") + }) + } } } + struct AppDetails_Previews: PreviewProvider { static var previews: some View { - AppDetails() + NavigationView{ + AppDetails(isActive: .constant(true), appEnvironment: MockAppEnvironment()) + } } } diff --git a/Zircles/Views/CreateNewTypeOfZircle.swift b/Zircles/Views/CreateNewTypeOfZircle.swift index 8acab1e..5817188 100644 --- a/Zircles/Views/CreateNewTypeOfZircle.swift +++ b/Zircles/Views/CreateNewTypeOfZircle.swift @@ -11,7 +11,7 @@ import SwiftUI struct CreateNewTypeOfZircle: View { var body: some View { ZStack { - Color.background + Color.background.edgesIgnoringSafeArea(.all) VStack(spacing: 32 ) { Spacer() Text("Savings Circle") @@ -33,7 +33,9 @@ struct CreateNewTypeOfZircle: View { .shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.5), radius: 25, x: 10, y: 10) .frame(height: 50) - + NavigationLink( + destination: CreateNewZircleDescription()) + { Text("Group Budget Goal") .font(.system(size: 20, weight: .bold, design: .default)) .shadow(color:Color(.sRGBLinear, red: 0.2, green: 0.2, blue: 0.2, opacity: 0.5), radius: 1, x: 0, y: 2) @@ -42,6 +44,7 @@ struct CreateNewTypeOfZircle: View { .shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.5), radius: 25, x: 10, y: 10) .frame(height: 50) + } Card(isOn: .constant(false),cornerRadius: 10, padding: 16) { ZircleProgress(progress: 0.7, stroke: .init(lineWidth: 5, lineCap: .round)) .glow(vibe: .heavy, soul: .split(left: Color.gradientPink, right: Color.gradientOrange)) @@ -59,7 +62,7 @@ struct CreateNewTypeOfZircle: View { } .padding(.horizontal, 30) .padding(.bottom, 30) - } + }.navigationBarTitle(Text("What Type of Savings Project?")) } } diff --git a/Zircles/Views/CreateNewZircleDescription.swift b/Zircles/Views/CreateNewZircleDescription.swift index 2b2da27..6a42abb 100644 --- a/Zircles/Views/CreateNewZircleDescription.swift +++ b/Zircles/Views/CreateNewZircleDescription.swift @@ -55,7 +55,7 @@ struct CreateNewZircleDescription: View { var body: some View { ZStack { - Color.background + Color.background.edgesIgnoringSafeArea(.all) VStack(spacing: 30) { VStack(alignment: .leading, spacing: 3) { Text("Name of project") diff --git a/Zircles/Views/SplashScreen.swift b/Zircles/Views/HomeScreen.swift similarity index 57% rename from Zircles/Views/SplashScreen.swift rename to Zircles/Views/HomeScreen.swift index 2b214c0..f1a552a 100644 --- a/Zircles/Views/SplashScreen.swift +++ b/Zircles/Views/HomeScreen.swift @@ -8,7 +8,16 @@ import SwiftUI -struct SplashScreen: View { +/* + Zircles:
ztestsapling16rzlnxq7wyxjctymxcnhjh2tru4hk48t2v3a32aacuyldsj3q0wgkny9w4re7n22yuemgmw8fqg + Wallet Birthday:
950000 + come exhibit fatal kid consider useless pigeon glove crawl stumble crunch left click labor curtain debris park hour raise wonder guilt upset eager order + + */ + +struct HomeScreen: View { + @State var detailsActive = false + @State var progress: Double = 0 var body: some View { ZStack { @@ -26,11 +35,15 @@ struct SplashScreen: View { .contentShape(RoundedRectangle(cornerRadius: 5)) .toggleStyle(SimpleToggleStyle(shape: RoundedRectangle(cornerRadius: 5), padding: 8)) Spacer() - FancyLogo() + FancyLogo(progress: $progress) .frame(width: 200, height: 200) + .animation(.easeInOut) + .onReceive(ZirclesEnvironment.shared.synchronizer.progress) { p in + self.progress = Double(p) + } Spacer() - VStack(spacing: 16) { - Text("Join a Zircle") + if progress < 1 { + Text("Syncing...") .font(.system(size: 20, weight: .bold, design: .default)) .shadow(color:Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.2), radius: 1, x: 0, y: 2) .foregroundColor(Color.buttonBlue) @@ -39,8 +52,25 @@ struct SplashScreen: View { .shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.3), radius: 15, x: 10, y: 15) .shadow(color: Color.white.opacity(0.5), radius: 25, x:-10, y: -10) .frame(height: 50) + } else { + VStack(spacing: 16) { + Button(action: { + + }, label: { + Text("Join a Zircle") + .font(.system(size: 20, weight: .bold, design: .default)) + .shadow(color:Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.2), radius: 1, x: 0, y: 2) + .foregroundColor(Color.buttonBlue) + .modifier(ZcashButtonBackground(buttonShape: .roundedCorners(fillStyle: .solid(color: Color.background)))) + + .shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.3), radius: 15, x: 10, y: 15) + .shadow(color: Color.white.opacity(0.5), radius: 25, x:-10, y: -10) + .frame(height: 50) + }) + - Button(action: {}) { + NavigationLink( + destination: CreateNewTypeOfZircle()) { Text("Create New") .font(.system(size: 20, weight: .bold, design: .default)) .shadow(color:Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.2), radius: 1, x: 0, y: 2) @@ -51,14 +81,31 @@ struct SplashScreen: View { .frame(height: 50) } }.padding(.all, 0) + } + }.padding(30) - }.navigationBarTitle(Text("Welcome to Zircles")) + } + .navigationBarBackButtonHidden(true) + .navigationBarTitle(Text("Welcome to Zircles")) + .navigationBarItems(trailing: Button(action: { + self.detailsActive = true + }){ + Image(systemName: "z.circle") + .frame(width: 30, height: 30, alignment: .center) + + } + .contentShape(Circle()) + ) + .sheet(isPresented: $detailsActive) { + AppDetails(isActive: $detailsActive,appEnvironment: ZirclesEnvironment.shared) + } } } struct FancyLogo: View { + @Binding var progress: Double var body: some View { ZStack { @@ -73,8 +120,9 @@ struct FancyLogo: View { } .overlay( - ZircleProgress(progress: 0.75, stroke: .init(lineWidth: 40, lineCap: .round)) + ZircleProgress(progress: progress, stroke: .init(lineWidth: 40, lineCap: .round)) .padding(23) + .animation(.easeIn) ) @@ -93,6 +141,6 @@ struct FancyLogo: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { - SplashScreen() + HomeScreen() } } diff --git a/Zircles/Views/WelcomeView.swift b/Zircles/Views/WelcomeView.swift index ecbc6c4..60132df 100644 --- a/Zircles/Views/WelcomeView.swift +++ b/Zircles/Views/WelcomeView.swift @@ -8,15 +8,20 @@ import SwiftUI import MnemonicSwift +import ZcashLightClientKit struct WelcomeView: View { @State var username: String = "" @State var seedPhrase: String = "" + @State var birthdayHeight: String = "" @State var isWelcome = false + @State var showError = false + @State var error: Error? = nil + var body: some View { ZStack { Color.background.edgesIgnoringSafeArea(.all) VStack(alignment: .leading, spacing: 16) { - Spacer() + Text("It looks like you are a new user, let's get to know you! What is your name?") .fontWeight(.heavy) .foregroundColor(Color.textDarkGray) @@ -52,6 +57,18 @@ struct WelcomeView: View { .font(.system(size: 14, weight: .heavy, design: .default)) } }.padding(.all, 0) + VStack(alignment: .leading, spacing: 4) { + Text("Birthday height") + .foregroundColor(.textLightGray) + .fontWeight(.heavy) + .font(.footnote) + .frame(alignment: .leading) + Card(isOn: .constant(true),cornerRadius: 5,padding: 8) { + TextField("Birthday height", text: $birthdayHeight) + .foregroundColor(Color.textDarkGray) + .font(.system(size: 14, weight: .heavy, design: .default)) + } + }.padding(.all, 0) Spacer() Text("The Zircles app will only send ZEC to other Zircles app.") .foregroundColor(.textLightGray) @@ -60,8 +77,11 @@ struct WelcomeView: View { .frame(alignment: .center) Spacer() Button(action: { - - self.isWelcome = true + do { + try initialize() + } catch { + ZirclesEnvironment.shared.errorPublisher.send(error) + } }) { Text("Add Wallet to Zircles") .font(.system(size: 20, weight: .bold, design: .default)) @@ -72,8 +92,9 @@ struct WelcomeView: View { .shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.5), radius: 25, x: 10, y: 10) .frame(height: 50) }.disabled(!validInput()) + .opacity(validInput() ? 1.0 : 0.6) NavigationLink( - destination: SplashScreen(), + destination: HomeScreen(), isActive: $isWelcome, label: { EmptyView() @@ -81,14 +102,34 @@ struct WelcomeView: View { } .padding([.horizontal,.bottom], 30) - - - }.navigationBarTitle(Text("Welcome")) + + } + .navigationBarTitle(Text("Welcome")) + .alert(isPresented: $showError) { + Alert( + title: Text("Error"), + message: Text( error == nil ? "It would be embarrasing if it wasn't a hackathon" : "Error: \( ZirclesEnvironment.WalletError.mapError(error: error!).localizedDescription)"), + dismissButton: .default(Text("dismiss"), action: { + self.error = nil + })) + }.onReceive(ZirclesEnvironment.shared.errorPublisher) { e in + self.error = e + self.showError = true + if let _ = e as? SeedManager.SeedManagerError { + ZirclesEnvironment.shared.nuke() + } + } } - + func initialize() throws { + ZircleDataStorage.default.saveUsername(self.username) + try self.importSeed() + try self.importBirthday() + try ZirclesEnvironment.shared.initialize() + self.isWelcome = true + } func validInput() -> Bool { - validSeedPhrase() && validName() + validSeedPhrase() && validName() && validBirthday() } func validSeedPhrase() -> Bool { @@ -98,10 +139,35 @@ struct WelcomeView: View { func validName() -> Bool { !username.isEmpty } + + func validBirthday() -> Bool { + birthdayHeight.isEmpty || Int64(birthdayHeight) != nil + } + + func validateSeed(_ seed: String) -> Bool { + MnemonicSeedProvider.default.isValid(mnemonic: seed) + } + + func importBirthday() throws { + let b = BlockHeight(self.birthdayHeight.trimmingCharacters(in: .whitespacesAndNewlines)) ?? ZcashSDK.SAPLING_ACTIVATION_HEIGHT + try SeedManager.default.importBirthday(b) + } + + func importSeed() throws { + let trimmedSeedPhrase = seedPhrase.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmedSeedPhrase.isEmpty, let seedBytes = + MnemonicSeedProvider.default.toSeed(mnemonic: trimmedSeedPhrase) else { throw ZirclesEnvironment.WalletError.createFailed + } + + try SeedManager.default.importSeed(seedBytes) + try SeedManager.default.importPhrase(bip39: trimmedSeedPhrase) + } } struct WelcomeView_Previews: PreviewProvider { static var previews: some View { + NavigationView { WelcomeView() + } } } diff --git a/Zircles/sapling-output.params b/Zircles/sapling-output.params new file mode 100644 index 0000000..01760fa Binary files /dev/null and b/Zircles/sapling-output.params differ diff --git a/Zircles/sapling-spend.params b/Zircles/sapling-spend.params new file mode 100644 index 0000000..b91cd77 Binary files /dev/null and b/Zircles/sapling-spend.params differ