diff --git a/.gitignore b/.gitignore index d41a04e..458024a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,23 @@ FrostSwiftFFI/Package.swift ### Xcodebuild gitignore Examples/FrostCompanion/build/ + + +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +*.xcuserdatad +xcuserdata/ +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +*/project.xcworkspace/xcuserdata/ diff --git a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.pbxproj b/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.pbxproj index a7e2456..212bc61 100644 --- a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.pbxproj +++ b/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.pbxproj @@ -8,13 +8,30 @@ /* Begin PBXBuildFile section */ 0D50A3412C0E6ED200B921E1 /* FrostCompanionApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D50A3402C0E6ED200B921E1 /* FrostCompanionApp.swift */; }; - 0D50A3432C0E6ED200B921E1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D50A3422C0E6ED200B921E1 /* ContentView.swift */; }; + 0D50A3432C0E6ED200B921E1 /* MainScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D50A3422C0E6ED200B921E1 /* MainScreenView.swift */; }; 0D50A3452C0E6ED300B921E1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D50A3442C0E6ED300B921E1 /* Assets.xcassets */; }; 0D50A3492C0E6ED300B921E1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0D50A3482C0E6ED300B921E1 /* Preview Assets.xcassets */; }; 0D50A3532C0E6ED300B921E1 /* FrostCompanionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D50A3522C0E6ED300B921E1 /* FrostCompanionTests.swift */; }; 0D50A35D2C0E6ED300B921E1 /* FrostCompanionUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D50A35C2C0E6ED300B921E1 /* FrostCompanionUITests.swift */; }; 0D50A35F2C0E6ED300B921E1 /* FrostCompanionUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D50A35E2C0E6ED300B921E1 /* FrostCompanionUITestsLaunchTests.swift */; }; 0D50A36D2C0E701500B921E1 /* FrostSwiftFFI in Frameworks */ = {isa = PBXBuildFile; productRef = 0D50A36C2C0E701500B921E1 /* FrostSwiftFFI */; }; + 0D5110762C80B3AA006E55DE /* AppFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D5110752C80B3AA006E55DE /* AppFeature.swift */; }; + 0D5110782C80B3E3006E55DE /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D5110772C80B3E3006E55DE /* AppView.swift */; }; + 0D51107A2C810907006E55DE /* NewTrustedDealerSchemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D5110792C810907006E55DE /* NewTrustedDealerSchemeView.swift */; }; + 0DB77E062C78F9ED0011DDCB /* ParticipanFeatureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB77E052C78F9ED0011DDCB /* ParticipanFeatureTests.swift */; }; + 0DDAB7AF2C768320009FA521 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 0DDAB7AE2C768320009FA521 /* ComposableArchitecture */; }; + 0DDAB7B12C7683A6009FA521 /* MainScreenReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDAB7B02C7683A6009FA521 /* MainScreenReducer.swift */; }; + 0DDAB7B42C7691D3009FA521 /* ParticipantImportFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDAB7B32C7691D3009FA521 /* ParticipantImportFeature.swift */; }; + 0DDAB7B82C769345009FA521 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDAB7B72C769345009FA521 /* Model.swift */; }; + 0DDAB7BB2C76A5A4009FA521 /* ParticipantImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDAB7BA2C76A5A4009FA521 /* ParticipantImportView.swift */; }; + 0DFAD1382C7F4B8B00072EF7 /* ParticipantDetailFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD1372C7F4B8B00072EF7 /* ParticipantDetailFeature.swift */; }; + 0DFAD13A2C7F4CDB00072EF7 /* ParticipantDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD1392C7F4CDB00072EF7 /* ParticipantDetailView.swift */; }; + 0DFAD13D2C7F517200072EF7 /* TrustedDealerFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD13C2C7F517200072EF7 /* TrustedDealerFeature.swift */; }; + 0DFAD13F2C7F523900072EF7 /* NewTrustedDealerSchemeFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD13E2C7F523900072EF7 /* NewTrustedDealerSchemeFeature.swift */; }; + 0DFAD1412C7FB74900072EF7 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD1402C7FB74900072EF7 /* Errors.swift */; }; + 0DFAD1432C7FBA7700072EF7 /* NewTrustedScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD1422C7FBA7700072EF7 /* NewTrustedScheme.swift */; }; + 0DFAD1462C7FD72600072EF7 /* PublicKeyPackageFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD1452C7FD72600072EF7 /* PublicKeyPackageFeature.swift */; }; + 0DFAD1482C7FD78800072EF7 /* PublicKeyPackageDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAD1472C7FD78800072EF7 /* PublicKeyPackageDetail.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -37,7 +54,7 @@ /* Begin PBXFileReference section */ 0D50A33D2C0E6ED200B921E1 /* FrostCompanion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FrostCompanion.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D50A3402C0E6ED200B921E1 /* FrostCompanionApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrostCompanionApp.swift; sourceTree = ""; }; - 0D50A3422C0E6ED200B921E1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 0D50A3422C0E6ED200B921E1 /* MainScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainScreenView.swift; sourceTree = ""; }; 0D50A3442C0E6ED300B921E1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0D50A3462C0E6ED300B921E1 /* FrostCompanion.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FrostCompanion.entitlements; sourceTree = ""; }; 0D50A3482C0E6ED300B921E1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; @@ -46,6 +63,22 @@ 0D50A3582C0E6ED300B921E1 /* FrostCompanionUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FrostCompanionUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0D50A35C2C0E6ED300B921E1 /* FrostCompanionUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrostCompanionUITests.swift; sourceTree = ""; }; 0D50A35E2C0E6ED300B921E1 /* FrostCompanionUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrostCompanionUITestsLaunchTests.swift; sourceTree = ""; }; + 0D5110752C80B3AA006E55DE /* AppFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppFeature.swift; sourceTree = ""; }; + 0D5110772C80B3E3006E55DE /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = ""; }; + 0D5110792C810907006E55DE /* NewTrustedDealerSchemeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTrustedDealerSchemeView.swift; sourceTree = ""; }; + 0DB77E052C78F9ED0011DDCB /* ParticipanFeatureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipanFeatureTests.swift; sourceTree = ""; }; + 0DDAB7B02C7683A6009FA521 /* MainScreenReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainScreenReducer.swift; sourceTree = ""; }; + 0DDAB7B32C7691D3009FA521 /* ParticipantImportFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantImportFeature.swift; sourceTree = ""; }; + 0DDAB7B72C769345009FA521 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; + 0DDAB7BA2C76A5A4009FA521 /* ParticipantImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantImportView.swift; sourceTree = ""; }; + 0DFAD1372C7F4B8B00072EF7 /* ParticipantDetailFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantDetailFeature.swift; sourceTree = ""; }; + 0DFAD1392C7F4CDB00072EF7 /* ParticipantDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantDetailView.swift; sourceTree = ""; }; + 0DFAD13C2C7F517200072EF7 /* TrustedDealerFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrustedDealerFeature.swift; sourceTree = ""; }; + 0DFAD13E2C7F523900072EF7 /* NewTrustedDealerSchemeFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTrustedDealerSchemeFeature.swift; sourceTree = ""; }; + 0DFAD1402C7FB74900072EF7 /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; + 0DFAD1422C7FBA7700072EF7 /* NewTrustedScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTrustedScheme.swift; sourceTree = ""; }; + 0DFAD1452C7FD72600072EF7 /* PublicKeyPackageFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicKeyPackageFeature.swift; sourceTree = ""; }; + 0DFAD1472C7FD78800072EF7 /* PublicKeyPackageDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicKeyPackageDetail.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,6 +86,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0DDAB7AF2C768320009FA521 /* ComposableArchitecture in Frameworks */, 0D50A36D2C0E701500B921E1 /* FrostSwiftFFI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -97,11 +131,18 @@ 0D50A33F2C0E6ED200B921E1 /* FrostCompanion */ = { isa = PBXGroup; children = ( + 0DFAD1442C7FD70900072EF7 /* Public */, + 0DFAD13B2C7F514300072EF7 /* Coordinator */, + 0DDAB7B62C76931F009FA521 /* Model */, + 0DDAB7B22C7689E8009FA521 /* Participant */, 0D50A3402C0E6ED200B921E1 /* FrostCompanionApp.swift */, - 0D50A3422C0E6ED200B921E1 /* ContentView.swift */, + 0D50A3422C0E6ED200B921E1 /* MainScreenView.swift */, 0D50A3442C0E6ED300B921E1 /* Assets.xcassets */, 0D50A3462C0E6ED300B921E1 /* FrostCompanion.entitlements */, 0D50A3472C0E6ED300B921E1 /* Preview Content */, + 0DDAB7B02C7683A6009FA521 /* MainScreenReducer.swift */, + 0D5110752C80B3AA006E55DE /* AppFeature.swift */, + 0D5110772C80B3E3006E55DE /* AppView.swift */, ); path = FrostCompanion; sourceTree = ""; @@ -118,6 +159,7 @@ isa = PBXGroup; children = ( 0D50A3522C0E6ED300B921E1 /* FrostCompanionTests.swift */, + 0DB77E052C78F9ED0011DDCB /* ParticipanFeatureTests.swift */, ); path = FrostCompanionTests; sourceTree = ""; @@ -131,6 +173,46 @@ path = FrostCompanionUITests; sourceTree = ""; }; + 0DDAB7B22C7689E8009FA521 /* Participant */ = { + isa = PBXGroup; + children = ( + 0DDAB7B32C7691D3009FA521 /* ParticipantImportFeature.swift */, + 0DDAB7BA2C76A5A4009FA521 /* ParticipantImportView.swift */, + 0DFAD1372C7F4B8B00072EF7 /* ParticipantDetailFeature.swift */, + 0DFAD1392C7F4CDB00072EF7 /* ParticipantDetailView.swift */, + ); + path = Participant; + sourceTree = ""; + }; + 0DDAB7B62C76931F009FA521 /* Model */ = { + isa = PBXGroup; + children = ( + 0DDAB7B72C769345009FA521 /* Model.swift */, + 0DFAD1402C7FB74900072EF7 /* Errors.swift */, + ); + path = Model; + sourceTree = ""; + }; + 0DFAD13B2C7F514300072EF7 /* Coordinator */ = { + isa = PBXGroup; + children = ( + 0DFAD13C2C7F517200072EF7 /* TrustedDealerFeature.swift */, + 0DFAD13E2C7F523900072EF7 /* NewTrustedDealerSchemeFeature.swift */, + 0DFAD1422C7FBA7700072EF7 /* NewTrustedScheme.swift */, + 0D5110792C810907006E55DE /* NewTrustedDealerSchemeView.swift */, + ); + path = Coordinator; + sourceTree = ""; + }; + 0DFAD1442C7FD70900072EF7 /* Public */ = { + isa = PBXGroup; + children = ( + 0DFAD1452C7FD72600072EF7 /* PublicKeyPackageFeature.swift */, + 0DFAD1472C7FD78800072EF7 /* PublicKeyPackageDetail.swift */, + ); + path = Public; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -149,6 +231,7 @@ name = FrostCompanion; packageProductDependencies = ( 0D50A36C2C0E701500B921E1 /* FrostSwiftFFI */, + 0DDAB7AE2C768320009FA521 /* ComposableArchitecture */, ); productName = FrostCompanion; productReference = 0D50A33D2C0E6ED200B921E1 /* FrostCompanion.app */; @@ -224,6 +307,7 @@ mainGroup = 0D50A3342C0E6ED200B921E1; packageReferences = ( 0D50A36B2C0E701500B921E1 /* XCRemoteSwiftPackageReference "frost-uniffi-sdk" */, + 0DDAB7AD2C768320009FA521 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, ); productRefGroup = 0D50A33E2C0E6ED200B921E1 /* Products */; projectDirPath = ""; @@ -267,8 +351,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0D50A3432C0E6ED200B921E1 /* ContentView.swift in Sources */, + 0DFAD1482C7FD78800072EF7 /* PublicKeyPackageDetail.swift in Sources */, + 0DDAB7B82C769345009FA521 /* Model.swift in Sources */, + 0DDAB7B42C7691D3009FA521 /* ParticipantImportFeature.swift in Sources */, + 0D50A3432C0E6ED200B921E1 /* MainScreenView.swift in Sources */, + 0D5110782C80B3E3006E55DE /* AppView.swift in Sources */, + 0D51107A2C810907006E55DE /* NewTrustedDealerSchemeView.swift in Sources */, + 0DFAD13A2C7F4CDB00072EF7 /* ParticipantDetailView.swift in Sources */, 0D50A3412C0E6ED200B921E1 /* FrostCompanionApp.swift in Sources */, + 0D5110762C80B3AA006E55DE /* AppFeature.swift in Sources */, + 0DFAD1382C7F4B8B00072EF7 /* ParticipantDetailFeature.swift in Sources */, + 0DFAD1462C7FD72600072EF7 /* PublicKeyPackageFeature.swift in Sources */, + 0DDAB7B12C7683A6009FA521 /* MainScreenReducer.swift in Sources */, + 0DFAD1432C7FBA7700072EF7 /* NewTrustedScheme.swift in Sources */, + 0DFAD1412C7FB74900072EF7 /* Errors.swift in Sources */, + 0DFAD13D2C7F517200072EF7 /* TrustedDealerFeature.swift in Sources */, + 0DDAB7BB2C76A5A4009FA521 /* ParticipantImportView.swift in Sources */, + 0DFAD13F2C7F523900072EF7 /* NewTrustedDealerSchemeFeature.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -277,6 +376,7 @@ buildActionMask = 2147483647; files = ( 0D50A3532C0E6ED300B921E1 /* FrostCompanionTests.swift in Sources */, + 0DB77E062C78F9ED0011DDCB /* ParticipanFeatureTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -357,7 +457,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -412,7 +514,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; @@ -631,6 +735,14 @@ minimumVersion = 0.0.1; }; }; + 0DDAB7AD2C768320009FA521 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.13.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -639,6 +751,11 @@ package = 0D50A36B2C0E701500B921E1 /* XCRemoteSwiftPackageReference "frost-uniffi-sdk" */; productName = FrostSwiftFFI; }; + 0DDAB7AE2C768320009FA521 /* ComposableArchitecture */ = { + isa = XCSwiftPackageProductDependency; + package = 0DDAB7AD2C768320009FA521 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; + productName = ComposableArchitecture; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 0D50A3352C0E6ED200B921E1 /* Project object */; diff --git a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5b84138..4839d4d 100644 --- a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,15 +1,131 @@ { - "originHash" : "b992748e59d7d23f8a3fbf43833b6989ef58a466ab5e6d3e62d70703033fb93e", "pins" : [ + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "9fa31f4403da54855f1e2aeaeff478f4f0e40b13", + "version" : "1.0.2" + } + }, { "identity" : "frost-uniffi-sdk", "kind" : "remoteSourceControl", "location" : "https://github.com/pacu/frost-uniffi-sdk", "state" : { - "revision" : "f76b06af4dc5d06fb83153697242a3da4f0b9eb0", - "version" : "0.0.1" + "revision" : "95bdaf849a001beda121bc266c63d5ea870eb4cb", + "version" : "0.0.6" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "71344dd930fde41e8f3adafe260adcbb2fc2a3dc", + "version" : "1.5.4" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "b9b24b69e2adda099a1fa381cda1eeec272d5b53", + "version" : "1.0.5" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "3d2dc41a01f9e49d84f0a3925fb858bed64f702d", + "version" : "1.1.2" + } + }, + { + "identity" : "swift-composable-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-composable-architecture", + "state" : { + "revision" : "b432441cbc11a38c678312bad1a01138a7cd64e0", + "version" : "1.13.0" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "82645ec760917961cfa08c9c0c7104a57a0fa4b1", + "version" : "1.3.3" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "21660b042cd8fd0bdd45cc39050cacd4e91a63a4", + "version" : "1.3.8" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "2f5ab6e091dd032b63dacbda052405756010dc3b", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-navigation", + "state" : { + "revision" : "70321c441d51b0b893c3abbf79687f550a027fde", + "version" : "2.0.6" + } + }, + { + "identity" : "swift-perception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-perception", + "state" : { + "revision" : "1552c8f722ac256cc0b8daaf1a7073217d4fcdfb", + "version" : "1.3.4" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax", + "state" : { + "revision" : "515f79b522918f83483068d99c68daeb5116342d", + "version" : "600.0.0-prerelease-2024-08-20" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "96beb108a57f24c8476ae1f309239270772b2940", + "version" : "1.2.5" } } ], - "version" : 3 + "version" : 2 } diff --git a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcuserdata/pacu.xcuserdatad/IDEFindNavigatorScopes.plist b/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcuserdata/pacu.xcuserdatad/IDEFindNavigatorScopes.plist deleted file mode 100644 index 5dd5da8..0000000 --- a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcuserdata/pacu.xcuserdatad/IDEFindNavigatorScopes.plist +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcuserdata/pacu.xcuserdatad/UserInterfaceState.xcuserstate b/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcuserdata/pacu.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index d2b23d5..0000000 Binary files a/Examples/FrostCompanion/FrostCompanion.xcodeproj/project.xcworkspace/xcuserdata/pacu.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Examples/FrostCompanion/FrostCompanion/AppFeature.swift b/Examples/FrostCompanion/FrostCompanion/AppFeature.swift new file mode 100644 index 0000000..ad44744 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/AppFeature.swift @@ -0,0 +1,47 @@ +// +// AppFeature.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import Foundation +import ComposableArchitecture +@Reducer +struct AppFeature { + @ObservableState + struct State: Equatable { + var path = StackState() + var mainScreen = MainScreenFeature.State() + } + + enum Action { + case path(StackActionOf) + case mainScreen(MainScreenFeature.Action) + } + + @Reducer(state: .equatable) + enum Path { + case importParticipant(ParticipantImportFeature) + case coordinator(TrustedDealerFeature) + case newTrustedDealerScheme(NewTrustedScheme) + } + + var body: some ReducerOf { + Scope(state: \.mainScreen, action: \.mainScreen) { + MainScreenFeature() + } + Reduce { state, action in + switch action { +// case .path(.element(_, .coordinator(.))) + case .path: + return .none + + case .mainScreen: + return .none + } + } + .forEach(\.path, action: \.path) + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/AppView.swift b/Examples/FrostCompanion/FrostCompanion/AppView.swift new file mode 100644 index 0000000..b5c8c18 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/AppView.swift @@ -0,0 +1,44 @@ +// +// AppView.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import SwiftUI +import ComposableArchitecture +struct AppView: View { + @Bindable var store: StoreOf + var body: some View { + NavigationStack( + path: $store.scope(state: \.path, action: \.path) + ) { + MainScreenView( + store: + store.scope( + state: \.mainScreen, + action: \.mainScreen + ) + ) + } destination: { store in + switch store.case { + case let .importParticipant(importStore): + ParticipantImportView(store: importStore) + case let .coordinator(trustedDealerStore): + NewTrustedDealerSchemeView(store: trustedDealerStore) + case let .newTrustedDealerScheme(newTrustedDealerScheme): + NewTrustedDealerSchemeFeature() + } + } + } +} + +#Preview { + AppView(store: Store( + initialState: AppFeature.State() + ){ + AppFeature() + } + ) +} diff --git a/Examples/FrostCompanion/FrostCompanion/ContentView.swift b/Examples/FrostCompanion/FrostCompanion/ContentView.swift deleted file mode 100644 index 3f41166..0000000 --- a/Examples/FrostCompanion/FrostCompanion/ContentView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentView.swift -// FrostCompanion -// -// Created by Pacu on 2024-06-03. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "snow") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, FROST!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedDealerSchemeFeature.swift b/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedDealerSchemeFeature.swift new file mode 100644 index 0000000..4982cf4 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedDealerSchemeFeature.swift @@ -0,0 +1,26 @@ +// +// NewTrustedDealerSchemeFeature.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import Foundation +import ComposableArchitecture + +@Reducer +struct NewTrustedDealerSchemeFeature { + @ObservableState + struct State { + let schemeConfig: FROSTSchemeConfig + var scheme: TrustedDealerScheme? +// var path: StackState< + } + + enum Action { + case dealerSucceeded(TrustedDealerScheme) + case dealerFailed(AppErrors) + } +} + diff --git a/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedDealerSchemeView.swift b/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedDealerSchemeView.swift new file mode 100644 index 0000000..a058b6b --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedDealerSchemeView.swift @@ -0,0 +1,44 @@ +// +// NewTrustedDealerSchemeView.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import SwiftUI +import ComposableArchitecture + +struct NewTrustedDealerSchemeView: View { + static let intFormater: NumberFormatter = { + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.allowsFloats = false + formatter.maximumFractionDigits = 0 + return formatter + }() + + @Bindable var store: StoreOf + @FocusState var focus: TrustedDealerFeature.State.Field? + var body: some View { + Form { + Section { + TextField("Min Participants", value: $store.minParticipants, format: .number) + .focused($focus, equals: .minParticipants) + TextField("Max Participants", value: $store.maxParticipants, formatter: Self.intFormater) + .focused($focus, equals: .minParticipants) + Button("create scheme") { + store.send(.createSchemePressed) + } + } + .bind($store.focus, to: $focus) + } + .padding() + } +} + +#Preview { + NewTrustedDealerSchemeView(store: Store(initialState: TrustedDealerFeature.State(), reducer: { + TrustedDealerFeature() + })) +} diff --git a/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedScheme.swift b/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedScheme.swift new file mode 100644 index 0000000..7985fb0 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Coordinator/NewTrustedScheme.swift @@ -0,0 +1,48 @@ +// +// NewTrustedScheme.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import SwiftUI +import ComposableArchitecture +struct NewTrustedScheme: View { + @Bindable var store: StoreOf + var body: some View { + + if let scheme = store.scheme { + List { + ForEach(scheme.shares.keys.sorted(), id: \.self) { identifier in + NavigationLink(state: ParticipantDetailFeature.State(keyShare: scheme.shares[identifier]!)){ + Text(identifier) + } + + } + NavigationLink(state: PublicKeyPackageFeature.State(package: scheme.publicKeyPackage)) { + + Text("Public Key Package") + } + + } + .navigationTitle("Participants") + } else { + Text("❄️ FROSTING... ❄️") + } + + + } +} + +#Preview { + NewTrustedScheme( + store: Store(initialState: NewTrustedDealerSchemeFeature.State( + schemeConfig: FROSTSchemeConfig.twoOfThree, + scheme: TrustedDealerScheme.mock + ), + reducer: { + NewTrustedDealerSchemeFeature() + }) + ) +} diff --git a/Examples/FrostCompanion/FrostCompanion/Coordinator/TrustedDealerFeature.swift b/Examples/FrostCompanion/FrostCompanion/Coordinator/TrustedDealerFeature.swift new file mode 100644 index 0000000..93f5f3d --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Coordinator/TrustedDealerFeature.swift @@ -0,0 +1,43 @@ +// +// TrustedDealerFeature.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import Foundation +import ComposableArchitecture + +@Reducer +struct TrustedDealerFeature { + @ObservableState + struct State: Equatable { + var maxParticipants: Int = 3 + var minParticipants: Int = 2 + + var focus: Field? = .minParticipants + + enum Field: Hashable { + case minParticipants + case maxParticipants + } + } + + enum Action: BindableAction, Equatable { + case binding(BindingAction) + case createSchemePressed + } + + var body: some ReducerOf { + BindingReducer() + Reduce { state, action in + switch action { + case .binding: + return .none + case .createSchemePressed: + return .none + } + } + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/FrostCompanionApp.swift b/Examples/FrostCompanion/FrostCompanion/FrostCompanionApp.swift index 96d6614..60f05a5 100644 --- a/Examples/FrostCompanion/FrostCompanion/FrostCompanionApp.swift +++ b/Examples/FrostCompanion/FrostCompanion/FrostCompanionApp.swift @@ -6,12 +6,28 @@ // import SwiftUI - +import ComposableArchitecture @main struct FrostCompanionApp: App { + // NB: This is static to avoid interference with Xcode previews, which create this entry + // point each time they are run. + @MainActor + static let store = Store(initialState: AppFeature.State()) { + AppFeature() + ._printChanges() + } withDependencies: { + if ProcessInfo.processInfo.environment["UITesting"] == "true" { + $0.defaultFileStorage = .inMemory + } + } var body: some Scene { WindowGroup { - ContentView() + if _XCTIsTesting { + // NB: Don't run application in tests to avoid interference between the app and the test. + EmptyView() + } else { + AppView(store: Self.store) + } } } } diff --git a/Examples/FrostCompanion/FrostCompanion/MainScreenReducer.swift b/Examples/FrostCompanion/FrostCompanion/MainScreenReducer.swift new file mode 100644 index 0000000..67fc7d2 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/MainScreenReducer.swift @@ -0,0 +1,41 @@ +// +// MainScreenReducer.swift +// FrostCompanion +// +// Created by pacu on 21/08/2024. +// + +import Foundation +import ComposableArchitecture + + +@Reducer +struct MainScreenFeature { + + + @ObservableState + struct State: Equatable { + @Presents var destination: Destination.State? + + } + + enum Action { + } + +// .ifLet(\.$destination, action: \.destination) { +// Destination.participant(ParticipantReducer()) +// } +// .forEach(\.path, action: \.path) { +// Path() +// } + +} + + +extension MainScreenFeature { + + @Reducer(state: .equatable) + enum Destination { + case participant(ParticipantImportFeature) + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/MainScreenView.swift b/Examples/FrostCompanion/FrostCompanion/MainScreenView.swift new file mode 100644 index 0000000..31c7851 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/MainScreenView.swift @@ -0,0 +1,42 @@ +// +// ContentView.swift +// FrostCompanion +// +// Created by Pacu on 2024-06-03. +// + +import SwiftUI +import ComposableArchitecture +struct MainScreenView: View { + @Bindable var store: StoreOf + var body: some View { + VStack { + Image(systemName: "snow") + .imageScale(.large) + .foregroundStyle(.tint) + + Text("Who are you?") + VStack { + NavigationLink(state: AppFeature.Path.State.importParticipant(.init())){ + Text("Participant") + } + + NavigationLink(state: AppFeature.Path.State.coordinator(.init())) { + Text("Coordinator") + } + } + } + .padding() + + .navigationTitle("Hello, FROST! ❄️") + } + +} + +#Preview { + MainScreenView( + store: Store(initialState: MainScreenFeature.State()){ + MainScreenFeature() + } + ) +} diff --git a/Examples/FrostCompanion/FrostCompanion/Model/Errors.swift b/Examples/FrostCompanion/FrostCompanion/Model/Errors.swift new file mode 100644 index 0000000..73a29bf --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Model/Errors.swift @@ -0,0 +1,13 @@ +// +// Errors.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import Foundation + +enum AppErrors: Error { + case invalidConfiguration +} diff --git a/Examples/FrostCompanion/FrostCompanion/Model/Model.swift b/Examples/FrostCompanion/FrostCompanion/Model/Model.swift new file mode 100644 index 0000000..ebe36f3 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Model/Model.swift @@ -0,0 +1,155 @@ +// +// Model.swift +// FrostCompanion +// +// Created by pacu on 2024-08-21. +// + +import Foundation + +struct TrustedDealerScheme { + let config: FROSTSchemeConfig + let shares: [String : JSONKeyShare] + let publicKeyPackage: JSONPublicKeyPackage +} + +struct JSONPublicKeyPackage: Equatable { + let raw: String +} + +struct JSONKeyShare: Equatable { + let raw: String +} + +extension JSONKeyShare { + static let empty = JSONKeyShare( + raw: "" + ) + static let mock = JSONKeyShare( + raw: + """ + { + "header": { + "version": 0, + "ciphersuite": "FROST(Pallas, BLAKE2b-512)" + }, + "identifier": "0100000000000000000000000000000000000000000000000000000000000000", + "signing_share": "b02e5a1e43a7f305177682574ac63c1a5f7f57db644c992635d09f699e56f41e", + "commitment": [ + "4141ac3d66ff87c4d14eb14f4262b69de15f7093dfd1f411a02ea70644f0d41f", + "2eb4cd3ace283ba6bb9058ff08d0561ff6d87057ecc87b0701123979291fb082" + ] + } + """ + ) +} + + +struct FROSTSchemeConfig { + let maxParticipants: Int + let minParticipants: Int + + fileprivate init( + uncheckedMax: Int, + uncheckedMin: Int + ) { + self.maxParticipants = uncheckedMax + self.minParticipants = uncheckedMin + } + + init( + maxParticipants: Int, + minParticipants: Int + ) throws { + guard maxParticipants > minParticipants, minParticipants > 2 else { + throw AppErrors.invalidConfiguration + } + self.maxParticipants = maxParticipants + self.minParticipants = minParticipants + } +} + + +extension FROSTSchemeConfig { + static let twoOfThree = FROSTSchemeConfig( + uncheckedMax: 3, + uncheckedMin: 2 + ) +} + + +extension JSONPublicKeyPackage { + static let mock = JSONPublicKeyPackage(raw: """ + { + "header": { + "version": 0, + "ciphersuite": "FROST(Pallas, BLAKE2b-512)" + }, + "verifying_shares": { + "0100000000000000000000000000000000000000000000000000000000000000": "35a83b6ce26fd8812e7e100ff0f9557dd873080478272770745d35c2c1698fad", + "0200000000000000000000000000000000000000000000000000000000000000": "a2e91b0636456d78b4830f4c926d07638dcfa41083071ab94b87dd8d9ea22f26", + "0300000000000000000000000000000000000000000000000000000000000000": "cdca48566dd4dc57a9cd546b1ad64212eb3d53eba9c852c1a1d6f661d08d67b2" + }, + "verifying_key": "4141ac3d66ff87c4d14eb14f4262b69de15f7093dfd1f411a02ea70644f0d41f" + } + """) +} + +extension TrustedDealerScheme { + static let mock = TrustedDealerScheme( + config: .twoOfThree, + shares: Self.mockShares, + publicKeyPackage: JSONPublicKeyPackage.mock + ) + + static let mockShares = [ + "0100000000000000000000000000000000000000000000000000000000000000" : JSONKeyShare( + raw: """ + { + "header": { + "version": 0, + "ciphersuite": "FROST(Pallas, BLAKE2b-512)" + }, + "identifier": "0100000000000000000000000000000000000000000000000000000000000000", + "signing_share": "b02e5a1e43a7f305177682574ac63c1a5f7f57db644c992635d09f699e56f41e", + "commitment": [ + "4141ac3d66ff87c4d14eb14f4262b69de15f7093dfd1f411a02ea70644f0d41f", + "2eb4cd3ace283ba6bb9058ff08d0561ff6d87057ecc87b0701123979291fb082" + ] + } + """ + ), + "0200000000000000000000000000000000000000000000000000000000000000" : JSONKeyShare( + raw: """ + { + "header": { + "version": 0, + "ciphersuite": "FROST(Pallas, BLAKE2b-512)" + }, + "identifier": "0200000000000000000000000000000000000000000000000000000000000000", + "signing_share": "850da1fd0b6f609b60a0f81d0aa79986e46cee490f837a5ccf349ac9b904790b", + "commitment": [ + "4141ac3d66ff87c4d14eb14f4262b69de15f7093dfd1f411a02ea70644f0d41f", + "2eb4cd3ace283ba6bb9058ff08d0561ff6d87057ecc87b0701123979291fb082" + ] + } + """ + ), + "0300000000000000000000000000000000000000000000000000000000000000" : JSONKeyShare( + raw: """ + { + "header": { + "version": 0, + "ciphersuite": "FROST(Pallas, BLAKE2b-512)" + }, + "identifier": "", + "signing_share": "5bece7dcf52114bd877303eec5203d156a5a85b8b9b95b9269999429d5b2fd37", + "commitment": [ + "4141ac3d66ff87c4d14eb14f4262b69de15f7093dfd1f411a02ea70644f0d41f", + "2eb4cd3ace283ba6bb9058ff08d0561ff6d87057ecc87b0701123979291fb082" + ] + } + """ + ) + ] +} diff --git a/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantDetailFeature.swift b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantDetailFeature.swift new file mode 100644 index 0000000..c516724 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantDetailFeature.swift @@ -0,0 +1,29 @@ +// +// ParticipantDetail.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import Foundation +import ComposableArchitecture + +@Reducer +struct ParticipantDetailFeature { + @ObservableState + struct State: Equatable { + let keyShare: JSONKeyShare + } + enum Action { + + } + + var body: some ReducerOf { + Reduce { state, action in + switch action { + + } + } + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantDetailView.swift b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantDetailView.swift new file mode 100644 index 0000000..e9b1297 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantDetailView.swift @@ -0,0 +1,38 @@ +// +// ParticipantDetailView.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import SwiftUI +import ComposableArchitecture +struct ParticipantDetailView: View { + + @Bindable var store: StoreOf + var body: some View { + Text(verbatim: store.keyShare.raw) + .navigationTitle("Participant Detail") + .toolbar { + ToolbarItem { + Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, label: { + Image(systemName: "trash") + .foregroundColor(.red) + }) + } + } + } +} + +#Preview { + NavigationStack { + ParticipantDetailView(store: Store( + initialState: ParticipantDetailFeature.State( + keyShare: JSONKeyShare.mock + ) + ) { + ParticipantDetailFeature() + }) + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantImportFeature.swift b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantImportFeature.swift new file mode 100644 index 0000000..b93717e --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantImportFeature.swift @@ -0,0 +1,54 @@ +// +// ParticipantReducer.swift +// FrostCompanion +// +// Created by pacu on 2024-08-21. +// + +import Foundation +import ComposableArchitecture + +@Reducer +struct ParticipantImportFeature { + @ObservableState + struct State: Equatable { + var keyShare: JSONKeyShare = .empty + } + + enum Action { + case cancelButtonTapped + case delegate(Delegate) + case importButtonTapped + case setKeyShare(String) + enum Delegate: Equatable { + case cancel + case keyShareImported(JSONKeyShare) + } + } + + @Dependency(\.dismiss) var dismiss + + var body: some ReducerOf { + Reduce { state, action in + switch action { + case .cancelButtonTapped: + return .run { _ in await self.dismiss() } + case .delegate: + return .none + case .importButtonTapped: + return .run { [share = state.keyShare] send in + await send(.delegate(.keyShareImported(share))) + await self.dismiss() + } + case .setKeyShare(let keyShare): + state.keyShare = JSONKeyShare(raw: keyShare) + return .none +// case .importSuccess: +// +// case .importFailure: +// return .none + } + + } + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantImportView.swift b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantImportView.swift new file mode 100644 index 0000000..bf65b21 --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Participant/ParticipantImportView.swift @@ -0,0 +1,45 @@ +// +// ParticipantImportView.swift +// FrostCompanion +// +// Created by pacu on 2024-08-21 +// + +import SwiftUI +import ComposableArchitecture + +struct ParticipantImportView: View { + @Bindable var store: StoreOf + var body: some View { + Form { + Text("Paste your key-package.json contents") + TextEditor(text: $store.keyShare.raw.sending( + \.setKeyShare + )) + + + Button( + "Import" + ) { + store.send( + .importButtonTapped + ) + } + } + .navigationTitle( + "Import your Key-package JSON" + ) + } +} + +#Preview { + ParticipantImportView(store: Store( + initialState: ParticipantImportFeature.State( + keyShare: JSONKeyShare.mock + ) + ) { + ParticipantImportFeature() + } + ) + .padding() +} diff --git a/Examples/FrostCompanion/FrostCompanion/Public/PublicKeyPackageDetail.swift b/Examples/FrostCompanion/FrostCompanion/Public/PublicKeyPackageDetail.swift new file mode 100644 index 0000000..6ab49ed --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Public/PublicKeyPackageDetail.swift @@ -0,0 +1,37 @@ +// +// PublicKeyPackageDetail.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import SwiftUI +import ComposableArchitecture +struct PublicKeyPackageDetail: View { + let store: StoreOf + var body: some View { + Text(store.package.raw) + .multilineTextAlignment(/*@START_MENU_TOKEN@*/.leading/*@END_MENU_TOKEN@*/) + .padding() + .navigationTitle("Public Key Package") + .toolbar { + Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, label: { + Image(systemName: "square.and.arrow.up") + }) + } + } +} + +#Preview { + NavigationStack { + PublicKeyPackageDetail( + store: Store(initialState: PublicKeyPackageFeature.State( + package: .mock + ), + reducer: { + PublicKeyPackageFeature() + }) + ) + } +} diff --git a/Examples/FrostCompanion/FrostCompanion/Public/PublicKeyPackageFeature.swift b/Examples/FrostCompanion/FrostCompanion/Public/PublicKeyPackageFeature.swift new file mode 100644 index 0000000..c5e372e --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanion/Public/PublicKeyPackageFeature.swift @@ -0,0 +1,20 @@ +// +// PublicKeyPackageFeature.swift +// FrostCompanion +// +// Created by Pacu in 2024. +// + + +import Foundation +import ComposableArchitecture + +@Reducer +struct PublicKeyPackageFeature { + @ObservableState + struct State { + let package: JSONPublicKeyPackage + } + +} + diff --git a/Examples/FrostCompanion/FrostCompanionTests/FrostCompanionTests.swift b/Examples/FrostCompanion/FrostCompanionTests/FrostCompanionTests.swift index c4e7dc6..9bb45cf 100644 --- a/Examples/FrostCompanion/FrostCompanionTests/FrostCompanionTests.swift +++ b/Examples/FrostCompanion/FrostCompanionTests/FrostCompanionTests.swift @@ -6,28 +6,19 @@ // import XCTest - +import ComposableArchitecture +@testable import FrostCompanion final class FrostCompanionTests: XCTestCase { - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } + @MainActor + func testParticipantModifiesMainState() async { + let store = TestStore(initialState: MainScreenFeature.State()) { + MainScreenFeature() + } - func testPerformanceExample() throws { - // This is an example of a performance test case. - measure { - // Put the code you want to measure the time of here. + await store.send(.participantTapped) { + $0.destination = .participant(ParticipantImportFeature.State( + keyShare: JSONKeyShare.empty + )) } } } diff --git a/Examples/FrostCompanion/FrostCompanionTests/ParticipanFeatureTests.swift b/Examples/FrostCompanion/FrostCompanionTests/ParticipanFeatureTests.swift new file mode 100644 index 0000000..130f39f --- /dev/null +++ b/Examples/FrostCompanion/FrostCompanionTests/ParticipanFeatureTests.swift @@ -0,0 +1,24 @@ +// +// ParticipanFeatureTests.swift +// FrostCompanionTests +// +// Created by Pacu in 2024. +// + + +import XCTest +import ComposableArchitecture +@testable import FrostCompanion + +final class ParticipanFeatureTests: XCTestCase { + @MainActor + func testTextFieldInputInvalidInputDoesNotChangeState() async { + let store = TestStore(initialState: ParticipantImportFeature.State()) { + ParticipantImportFeature() + } + + await store.send(.setKeyShare("Hello test")) { + $0.keyShare = JSONKeyShare.empty + } + } +} diff --git a/Package.swift b/Package.swift index cc9c365..6a852b9 100644 --- a/Package.swift +++ b/Package.swift @@ -26,7 +26,7 @@ let package = Package( .target(name: "FrostSwiftFFI") ], path: "FrostSwift/Sources/FrostSwift" ), - .binaryTarget(name: "RustFramework", url: "https://github.com/pacu/frost-uniffi-sdk/releases/download/0.0.6/RustFramework.xcframework.zip", checksum: "b84677041219487bca551d563ff2993164454e6d70fd74076ed1f6309a7c9d85"), + .binaryTarget(name: "RustFramework", path: "FrostSwift/RustFramework.xcframework.zip"), .target( name: "FrostSwiftFFI", dependencies: [