diff --git a/example/BitsBytes.xcodeproj/project.pbxproj b/example/BitsBytes.xcodeproj/project.pbxproj new file mode 100644 index 00000000..999f5796 --- /dev/null +++ b/example/BitsBytes.xcodeproj/project.pbxproj @@ -0,0 +1,769 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 7FA82FB283C1A4E9F1A96655 /* Pods_BitsBytes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3489883CF507FA60E79F18AE /* Pods_BitsBytes.framework */; }; + E73567A62BCFAEE90001E89C /* AboutMeScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73567A52BCFAEE90001E89C /* AboutMeScreenView.swift */; }; + E73567A82BCFAF2D0001E89C /* AboutMeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73567A72BCFAF2D0001E89C /* AboutMeViewModel.swift */; }; + E73567AB2BD132B40001E89C /* LineWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73567A32BCD4FCD0001E89C /* LineWrapper.swift */; }; + E73F8BC62B98649E00E11B48 /* SignInEmailScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73F8BC52B98649E00E11B48 /* SignInEmailScreenView.swift */; }; + E73F8BC82B98659F00E11B48 /* SignInEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73F8BC72B98659F00E11B48 /* SignInEmailViewModel.swift */; }; + E73F8BCE2B99C45900E11B48 /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73F8BCD2B99C45900E11B48 /* SignInViewModel.swift */; }; + E74A46942C748BB000C739EA /* AddPhoneScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E74A46932C748BB000C739EA /* AddPhoneScreenView.swift */; }; + E74A46962C88499600C739EA /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E74A46952C88499600C739EA /* AccountModel.swift */; }; + E76A94C92C032D1700862A4B /* PasswordlessScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76A94C82C032D1700862A4B /* PasswordlessScreenView.swift */; }; + E76A94CB2C07073900862A4B /* PasswordlessViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76A94CA2C07073900862A4B /* PasswordlessViewModel.swift */; }; + E77BF0E22B94D1BB002C77C1 /* CustomRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E77BF0E12B94D1BB002C77C1 /* CustomRow.swift */; }; + E77BF0E42B94D376002C77C1 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E77BF0E32B94D376002C77C1 /* ProfileViewModel.swift */; }; + E788BCD82B8357A300C8F772 /* ConfigurationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCB32B8357A200C8F772 /* ConfigurationViewModel.swift */; }; + E788BCD92B8357A300C8F772 /* AppCoordinatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCB42B8357A200C8F772 /* AppCoordinatorView.swift */; }; + E788BCDA2B8357A300C8F772 /* FavScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCB72B8357A200C8F772 /* FavScreenView.swift */; }; + E788BCDB2B8357A300C8F772 /* HomeScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCB82B8357A200C8F772 /* HomeScreenView.swift */; }; + E788BCDC2B8357A300C8F772 /* SearchScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCB92B8357A200C8F772 /* SearchScreenView.swift */; }; + E788BCDD2B8357A300C8F772 /* CartScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCBA2B8357A200C8F772 /* CartScreenView.swift */; }; + E788BCDE2B8357A300C8F772 /* PorfileScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCBB2B8357A200C8F772 /* PorfileScreenView.swift */; }; + E788BCDF2B8357A300C8F772 /* SplashScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCBC2B8357A200C8F772 /* SplashScreenView.swift */; }; + E788BCE02B8357A300C8F772 /* ConfigurationScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCBD2B8357A200C8F772 /* ConfigurationScreenView.swift */; }; + E788BCE12B8357A300C8F772 /* TestScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCBE2B8357A200C8F772 /* TestScreenView.swift */; }; + E788BCE22B8357A300C8F772 /* SignInScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCBF2B8357A200C8F772 /* SignInScreenView.swift */; }; + E788BCE32B8357A300C8F772 /* NavigationWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCC02B8357A200C8F772 /* NavigationWrapperView.swift */; }; + E788BCE42B8357A300C8F772 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCC32B8357A200C8F772 /* CustomButton.swift */; }; + E788BCE52B8357A300C8F772 /* CustomInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCC42B8357A200C8F772 /* CustomInput.swift */; }; + E788BCE62B8357A300C8F772 /* NavBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCC52B8357A200C8F772 /* NavBar.swift */; }; + E788BCE72B8357A300C8F772 /* LoaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCC62B8357A200C8F772 /* LoaderView.swift */; }; + E788BCE82B8357A300C8F772 /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCC72B8357A200C8F772 /* CustomTabBar.swift */; }; + E788BCEA2B8357A300C8F772 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCCA2B8357A200C8F772 /* AppCoordinator.swift */; }; + E788BCEB2B8357A300C8F772 /* RoutingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCCB2B8357A200C8F772 /* RoutingManager.swift */; }; + E788BCEC2B8357A300C8F772 /* HomeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCCC2B8357A200C8F772 /* HomeCoordinator.swift */; }; + E788BCED2B8357A300C8F772 /* BitsBytesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCCD2B8357A200C8F772 /* BitsBytesApp.swift */; }; + E788BCEE2B8357A300C8F772 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E788BCCE2B8357A200C8F772 /* Assets.xcassets */; }; + E788BCEF2B8357A300C8F772 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E788BCD02B8357A200C8F772 /* Preview Assets.xcassets */; }; + E788BCF02B8357A300C8F772 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCD22B8357A200C8F772 /* AppDelegate.swift */; }; + E788BCF12B8357A300C8F772 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCD32B8357A200C8F772 /* SceneDelegate.swift */; }; + E788BCF22B8357A300C8F772 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCD42B8357A200C8F772 /* Coordinator.swift */; }; + E788BCF42B8357A300C8F772 /* GigyaService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BCD72B8357A200C8F772 /* GigyaService.swift */; }; + E788BD142B8C832E00C8F772 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = E788BD132B8C832E00C8F772 /* GoogleService-Info.plist */; }; + E788BD172B8C8B3300C8F772 /* RegisterScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BD162B8C8B3300C8F772 /* RegisterScreenView.swift */; }; + E788BD192B8CA20000C8F772 /* RegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BD182B8CA20000C8F772 /* RegisterViewModel.swift */; }; + E788BD1B2B8CCF8800C8F772 /* ProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E788BD1A2B8CCF8800C8F772 /* ProfileCoordinator.swift */; }; + E78A32F22B83436A00C892D8 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E78A32F12B83436A00C892D8 /* Launch Screen.storyboard */; }; + E7B16EB12BA05CB3005DD81E /* AppleSignInWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B16EB02BA05CB3005DD81E /* AppleSignInWrapper.swift */; }; + E7B16EB42BA1E519005DD81E /* FacebookWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B16EB22BA1AEE2005DD81E /* FacebookWrapper.swift */; }; + E7B16EB62BA304BB005DD81E /* GoogleWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B16EB52BA304BB005DD81E /* GoogleWrapper.swift */; }; + E7D318102C16FF60005B03A3 /* OtpScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7D3180F2C16FF60005B03A3 /* OtpScreenView.swift */; }; + E7D318122C171B70005B03A3 /* OtpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7D318112C171B70005B03A3 /* OtpViewModel.swift */; }; + E7FEA4D82C245343003A3973 /* ChangePasswordScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4D72C245343003A3973 /* ChangePasswordScreenView.swift */; }; + E7FEA4DA2C245497003A3973 /* ChangePasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4D92C245497003A3973 /* ChangePasswordViewModel.swift */; }; + E7FEA4DC2C246FC7003A3973 /* ResetPasswordScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4DB2C246FC7003A3973 /* ResetPasswordScreenView.swift */; }; + E7FEA4DE2C247670003A3973 /* ResetPasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4DD2C247670003A3973 /* ResetPasswordViewModel.swift */; }; + E7FEA4E02C2476DC003A3973 /* BaseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4DF2C2476DC003A3973 /* BaseViewModel.swift */; }; + E7FEA4E32C45138C003A3973 /* SignInInterruptionFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4E22C45138C003A3973 /* SignInInterruptionFlow.swift */; }; + E7FEA4E52C4CF78F003A3973 /* AccessibilityHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4E42C4CF78F003A3973 /* AccessibilityHelper.swift */; }; + E7FEA4E72C4CFC7F003A3973 /* LinkAccountScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4E62C4CFC7F003A3973 /* LinkAccountScreenView.swift */; }; + E7FEA4E92C4CFFBC003A3973 /* LinkAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4E82C4CFFBC003A3973 /* LinkAccountViewModel.swift */; }; + E7FEA4ED2C4FA8BB003A3973 /* PenddingRegistrationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4EC2C4FA8BB003A3973 /* PenddingRegistrationViewModel.swift */; }; + E7FEA4EF2C4FA9B1003A3973 /* PenddingRegistrationScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7FEA4EE2C4FA9B1003A3973 /* PenddingRegistrationScreenView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3489883CF507FA60E79F18AE /* Pods_BitsBytes.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitsBytes.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 36500EF345FAE48629CE033A /* Pods-BitsBytes.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitsBytes.debug.xcconfig"; path = "Target Support Files/Pods-BitsBytes/Pods-BitsBytes.debug.xcconfig"; sourceTree = ""; }; + 36F42C38E94EBA3902EE14F4 /* Pods-BitsBytes.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitsBytes.release.xcconfig"; path = "Target Support Files/Pods-BitsBytes/Pods-BitsBytes.release.xcconfig"; sourceTree = ""; }; + E73567A32BCD4FCD0001E89C /* LineWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LineWrapper.swift; path = ../../../../XC/GigyaSwift_XCFramework5/GigyaProviders/LineWrapper.swift; sourceTree = ""; }; + E73567A52BCFAEE90001E89C /* AboutMeScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutMeScreenView.swift; sourceTree = ""; }; + E73567A72BCFAF2D0001E89C /* AboutMeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutMeViewModel.swift; sourceTree = ""; }; + E73B9A4F2B5FC58F0018E9B4 /* BitsBytes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BitsBytes.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E73F8BC52B98649E00E11B48 /* SignInEmailScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInEmailScreenView.swift; sourceTree = ""; }; + E73F8BC72B98659F00E11B48 /* SignInEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInEmailViewModel.swift; sourceTree = ""; }; + E73F8BCD2B99C45900E11B48 /* SignInViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = ""; }; + E74A46932C748BB000C739EA /* AddPhoneScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddPhoneScreenView.swift; sourceTree = ""; }; + E74A46952C88499600C739EA /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = ""; }; + E76A94C82C032D1700862A4B /* PasswordlessScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordlessScreenView.swift; sourceTree = ""; }; + E76A94CA2C07073900862A4B /* PasswordlessViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordlessViewModel.swift; sourceTree = ""; }; + E77BF0E12B94D1BB002C77C1 /* CustomRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomRow.swift; sourceTree = ""; }; + E77BF0E32B94D376002C77C1 /* ProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewModel.swift; sourceTree = ""; }; + E788BCB32B8357A200C8F772 /* ConfigurationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationViewModel.swift; sourceTree = ""; }; + E788BCB42B8357A200C8F772 /* AppCoordinatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinatorView.swift; sourceTree = ""; }; + E788BCB72B8357A200C8F772 /* FavScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FavScreenView.swift; sourceTree = ""; }; + E788BCB82B8357A200C8F772 /* HomeScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeScreenView.swift; sourceTree = ""; }; + E788BCB92B8357A200C8F772 /* SearchScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchScreenView.swift; sourceTree = ""; }; + E788BCBA2B8357A200C8F772 /* CartScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CartScreenView.swift; sourceTree = ""; }; + E788BCBB2B8357A200C8F772 /* PorfileScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PorfileScreenView.swift; sourceTree = ""; }; + E788BCBC2B8357A200C8F772 /* SplashScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashScreenView.swift; sourceTree = ""; }; + E788BCBD2B8357A200C8F772 /* ConfigurationScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationScreenView.swift; sourceTree = ""; }; + E788BCBE2B8357A200C8F772 /* TestScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestScreenView.swift; sourceTree = ""; }; + E788BCBF2B8357A200C8F772 /* SignInScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignInScreenView.swift; sourceTree = ""; }; + E788BCC02B8357A200C8F772 /* NavigationWrapperView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationWrapperView.swift; sourceTree = ""; }; + E788BCC32B8357A200C8F772 /* CustomButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = ""; }; + E788BCC42B8357A200C8F772 /* CustomInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomInput.swift; sourceTree = ""; }; + E788BCC52B8357A200C8F772 /* NavBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavBar.swift; sourceTree = ""; }; + E788BCC62B8357A200C8F772 /* LoaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoaderView.swift; sourceTree = ""; }; + E788BCC72B8357A200C8F772 /* CustomTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; + E788BCCA2B8357A200C8F772 /* AppCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; + E788BCCB2B8357A200C8F772 /* RoutingManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoutingManager.swift; sourceTree = ""; }; + E788BCCC2B8357A200C8F772 /* HomeCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeCoordinator.swift; sourceTree = ""; }; + E788BCCD2B8357A200C8F772 /* BitsBytesApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitsBytesApp.swift; sourceTree = ""; }; + E788BCCE2B8357A200C8F772 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E788BCD02B8357A200C8F772 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + E788BCD22B8357A200C8F772 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + E788BCD32B8357A200C8F772 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + E788BCD42B8357A200C8F772 /* Coordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; + E788BCD72B8357A200C8F772 /* GigyaService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GigyaService.swift; sourceTree = ""; }; + E788BD132B8C832E00C8F772 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; }; + E788BD152B8C88AE00C8F772 /* BitsBytes.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BitsBytes.entitlements; sourceTree = ""; }; + E788BD162B8C8B3300C8F772 /* RegisterScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterScreenView.swift; sourceTree = ""; }; + E788BD182B8CA20000C8F772 /* RegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterViewModel.swift; sourceTree = ""; }; + E788BD1A2B8CCF8800C8F772 /* ProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCoordinator.swift; sourceTree = ""; }; + E78A32F12B83436A00C892D8 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; + E7B16EB02BA05CB3005DD81E /* AppleSignInWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppleSignInWrapper.swift; path = ../../../../TestApp/GigyaProviders/AppleSignInWrapper.swift; sourceTree = ""; }; + E7B16EB22BA1AEE2005DD81E /* FacebookWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FacebookWrapper.swift; path = ../../../../XC/GigyaSwift_XCFramework3/GigyaProviders/FacebookWrapper.swift; sourceTree = ""; }; + E7B16EB52BA304BB005DD81E /* GoogleWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GoogleWrapper.swift; path = ../../../../XC/GigyaSwift_XCFramework14/GigyaProviders/GoogleV7/GoogleWrapper.swift; sourceTree = ""; }; + E7D3180F2C16FF60005B03A3 /* OtpScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtpScreenView.swift; sourceTree = ""; }; + E7D318112C171B70005B03A3 /* OtpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtpViewModel.swift; sourceTree = ""; }; + E7FEA4D72C245343003A3973 /* ChangePasswordScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangePasswordScreenView.swift; sourceTree = ""; }; + E7FEA4D92C245497003A3973 /* ChangePasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangePasswordViewModel.swift; sourceTree = ""; }; + E7FEA4DB2C246FC7003A3973 /* ResetPasswordScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordScreenView.swift; sourceTree = ""; }; + E7FEA4DD2C247670003A3973 /* ResetPasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordViewModel.swift; sourceTree = ""; }; + E7FEA4DF2C2476DC003A3973 /* BaseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewModel.swift; sourceTree = ""; }; + E7FEA4E22C45138C003A3973 /* SignInInterruptionFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInInterruptionFlow.swift; sourceTree = ""; }; + E7FEA4E42C4CF78F003A3973 /* AccessibilityHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityHelper.swift; sourceTree = ""; }; + E7FEA4E62C4CFC7F003A3973 /* LinkAccountScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkAccountScreenView.swift; sourceTree = ""; }; + E7FEA4E82C4CFFBC003A3973 /* LinkAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkAccountViewModel.swift; sourceTree = ""; }; + E7FEA4EC2C4FA8BB003A3973 /* PenddingRegistrationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenddingRegistrationViewModel.swift; sourceTree = ""; }; + E7FEA4EE2C4FA9B1003A3973 /* PenddingRegistrationScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenddingRegistrationScreenView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E73B9A4C2B5FC58F0018E9B4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7FA82FB283C1A4E9F1A96655 /* Pods_BitsBytes.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 7329D39CD82828A16CB88EE7 /* Pods */ = { + isa = PBXGroup; + children = ( + 36500EF345FAE48629CE033A /* Pods-BitsBytes.debug.xcconfig */, + 36F42C38E94EBA3902EE14F4 /* Pods-BitsBytes.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + A5F18AAC529548A5790ABB50 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3489883CF507FA60E79F18AE /* Pods_BitsBytes.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E73B9A462B5FC58F0018E9B4 = { + isa = PBXGroup; + children = ( + E78A32F12B83436A00C892D8 /* Launch Screen.storyboard */, + E788BCB02B8357A200C8F772 /* BitsBytes */, + E73B9A502B5FC58F0018E9B4 /* Products */, + 7329D39CD82828A16CB88EE7 /* Pods */, + A5F18AAC529548A5790ABB50 /* Frameworks */, + ); + sourceTree = ""; + }; + E73B9A502B5FC58F0018E9B4 /* Products */ = { + isa = PBXGroup; + children = ( + E73B9A4F2B5FC58F0018E9B4 /* BitsBytes.app */, + ); + name = Products; + sourceTree = ""; + }; + E73F8BC92B98721500E11B48 /* Profile */ = { + isa = PBXGroup; + children = ( + E788BD162B8C8B3300C8F772 /* RegisterScreenView.swift */, + E74A46932C748BB000C739EA /* AddPhoneScreenView.swift */, + E76A94C82C032D1700862A4B /* PasswordlessScreenView.swift */, + E73F8BC52B98649E00E11B48 /* SignInEmailScreenView.swift */, + E73567A52BCFAEE90001E89C /* AboutMeScreenView.swift */, + E7FEA4D72C245343003A3973 /* ChangePasswordScreenView.swift */, + E788BCBF2B8357A200C8F772 /* SignInScreenView.swift */, + E7FEA4DB2C246FC7003A3973 /* ResetPasswordScreenView.swift */, + E7D3180F2C16FF60005B03A3 /* OtpScreenView.swift */, + ); + path = Profile; + sourceTree = ""; + }; + E73F8BCA2B99C40400E11B48 /* GigyaProviders */ = { + isa = PBXGroup; + children = ( + E7B16EB22BA1AEE2005DD81E /* FacebookWrapper.swift */, + E73567A32BCD4FCD0001E89C /* LineWrapper.swift */, + E7B16EB52BA304BB005DD81E /* GoogleWrapper.swift */, + E7B16EB02BA05CB3005DD81E /* AppleSignInWrapper.swift */, + ); + path = GigyaProviders; + sourceTree = ""; + }; + E788BCB02B8357A200C8F772 /* BitsBytes */ = { + isa = PBXGroup; + children = ( + E788BD152B8C88AE00C8F772 /* BitsBytes.entitlements */, + E788BCB12B8357A200C8F772 /* UI */, + E788BCC92B8357A200C8F772 /* Coordinators */, + E788BCCD2B8357A200C8F772 /* BitsBytesApp.swift */, + E788BD132B8C832E00C8F772 /* GoogleService-Info.plist */, + E788BCCE2B8357A200C8F772 /* Assets.xcassets */, + E788BCCF2B8357A200C8F772 /* Preview Content */, + E788BCD12B8357A200C8F772 /* System */, + E788BCD62B8357A200C8F772 /* Services */, + ); + path = BitsBytes; + sourceTree = ""; + }; + E788BCB12B8357A200C8F772 /* UI */ = { + isa = PBXGroup; + children = ( + E788BCB42B8357A200C8F772 /* AppCoordinatorView.swift */, + E7FEA4E12C451376003A3973 /* Flows */, + E788BCB22B8357A200C8F772 /* ViewModels */, + E788BCB52B8357A200C8F772 /* Screens */, + E788BCC02B8357A200C8F772 /* NavigationWrapperView.swift */, + E788BCC12B8357A200C8F772 /* Styles */, + E788BCC22B8357A200C8F772 /* Components */, + ); + path = UI; + sourceTree = ""; + }; + E788BCB22B8357A200C8F772 /* ViewModels */ = { + isa = PBXGroup; + children = ( + E7FEA4EA2C4FA6A9003A3973 /* Interruptions */, + E788BCB32B8357A200C8F772 /* ConfigurationViewModel.swift */, + E7FEA4DF2C2476DC003A3973 /* BaseViewModel.swift */, + E76A94CA2C07073900862A4B /* PasswordlessViewModel.swift */, + E73567A72BCFAF2D0001E89C /* AboutMeViewModel.swift */, + E788BD182B8CA20000C8F772 /* RegisterViewModel.swift */, + E73F8BC72B98659F00E11B48 /* SignInEmailViewModel.swift */, + E77BF0E32B94D376002C77C1 /* ProfileViewModel.swift */, + E73F8BCD2B99C45900E11B48 /* SignInViewModel.swift */, + E7FEA4D92C245497003A3973 /* ChangePasswordViewModel.swift */, + E7D318112C171B70005B03A3 /* OtpViewModel.swift */, + E7FEA4DD2C247670003A3973 /* ResetPasswordViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + E788BCB52B8357A200C8F772 /* Screens */ = { + isa = PBXGroup; + children = ( + E7FEA4EB2C4FA6BE003A3973 /* Interruptions */, + E788BCB62B8357A200C8F772 /* Tabs */, + E73F8BC92B98721500E11B48 /* Profile */, + E788BCBC2B8357A200C8F772 /* SplashScreenView.swift */, + E788BCBD2B8357A200C8F772 /* ConfigurationScreenView.swift */, + E788BCBE2B8357A200C8F772 /* TestScreenView.swift */, + ); + path = Screens; + sourceTree = ""; + }; + E788BCB62B8357A200C8F772 /* Tabs */ = { + isa = PBXGroup; + children = ( + E788BCB72B8357A200C8F772 /* FavScreenView.swift */, + E788BCB82B8357A200C8F772 /* HomeScreenView.swift */, + E788BCB92B8357A200C8F772 /* SearchScreenView.swift */, + E788BCBA2B8357A200C8F772 /* CartScreenView.swift */, + E788BCBB2B8357A200C8F772 /* PorfileScreenView.swift */, + ); + path = Tabs; + sourceTree = ""; + }; + E788BCC12B8357A200C8F772 /* Styles */ = { + isa = PBXGroup; + children = ( + ); + path = Styles; + sourceTree = ""; + }; + E788BCC22B8357A200C8F772 /* Components */ = { + isa = PBXGroup; + children = ( + E788BCC32B8357A200C8F772 /* CustomButton.swift */, + E788BCC42B8357A200C8F772 /* CustomInput.swift */, + E77BF0E12B94D1BB002C77C1 /* CustomRow.swift */, + E788BCC52B8357A200C8F772 /* NavBar.swift */, + E788BCC62B8357A200C8F772 /* LoaderView.swift */, + E788BCC72B8357A200C8F772 /* CustomTabBar.swift */, + ); + path = Components; + sourceTree = ""; + }; + E788BCC92B8357A200C8F772 /* Coordinators */ = { + isa = PBXGroup; + children = ( + E788BCCA2B8357A200C8F772 /* AppCoordinator.swift */, + E788BCCB2B8357A200C8F772 /* RoutingManager.swift */, + E788BCCC2B8357A200C8F772 /* HomeCoordinator.swift */, + E788BD1A2B8CCF8800C8F772 /* ProfileCoordinator.swift */, + ); + path = Coordinators; + sourceTree = ""; + }; + E788BCCF2B8357A200C8F772 /* Preview Content */ = { + isa = PBXGroup; + children = ( + E788BCD02B8357A200C8F772 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + E788BCD12B8357A200C8F772 /* System */ = { + isa = PBXGroup; + children = ( + E788BCD22B8357A200C8F772 /* AppDelegate.swift */, + E788BCD32B8357A200C8F772 /* SceneDelegate.swift */, + E74A46952C88499600C739EA /* AccountModel.swift */, + E788BCD42B8357A200C8F772 /* Coordinator.swift */, + E7FEA4E42C4CF78F003A3973 /* AccessibilityHelper.swift */, + ); + path = System; + sourceTree = ""; + }; + E788BCD62B8357A200C8F772 /* Services */ = { + isa = PBXGroup; + children = ( + E788BCD72B8357A200C8F772 /* GigyaService.swift */, + E73F8BCA2B99C40400E11B48 /* GigyaProviders */, + ); + path = Services; + sourceTree = ""; + }; + E7FEA4E12C451376003A3973 /* Flows */ = { + isa = PBXGroup; + children = ( + E7FEA4E22C45138C003A3973 /* SignInInterruptionFlow.swift */, + ); + path = Flows; + sourceTree = ""; + }; + E7FEA4EA2C4FA6A9003A3973 /* Interruptions */ = { + isa = PBXGroup; + children = ( + E7FEA4E82C4CFFBC003A3973 /* LinkAccountViewModel.swift */, + E7FEA4EC2C4FA8BB003A3973 /* PenddingRegistrationViewModel.swift */, + ); + path = Interruptions; + sourceTree = ""; + }; + E7FEA4EB2C4FA6BE003A3973 /* Interruptions */ = { + isa = PBXGroup; + children = ( + E7FEA4E62C4CFC7F003A3973 /* LinkAccountScreenView.swift */, + E7FEA4EE2C4FA9B1003A3973 /* PenddingRegistrationScreenView.swift */, + ); + path = Interruptions; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E73B9A4E2B5FC58F0018E9B4 /* BitsBytes */ = { + isa = PBXNativeTarget; + buildConfigurationList = E73B9A5D2B5FC5920018E9B4 /* Build configuration list for PBXNativeTarget "BitsBytes" */; + buildPhases = ( + 01DD5A349DADD0F76B36D2D4 /* [CP] Check Pods Manifest.lock */, + E73B9A4B2B5FC58F0018E9B4 /* Sources */, + E73B9A4C2B5FC58F0018E9B4 /* Frameworks */, + E73B9A4D2B5FC58F0018E9B4 /* Resources */, + 211926AC0B25A7D5CEDDE4CB /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BitsBytes; + productName = Shaggy; + productReference = E73B9A4F2B5FC58F0018E9B4 /* BitsBytes.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E73B9A472B5FC58F0018E9B4 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + TargetAttributes = { + E73B9A4E2B5FC58F0018E9B4 = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = E73B9A4A2B5FC58F0018E9B4 /* Build configuration list for PBXProject "BitsBytes" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E73B9A462B5FC58F0018E9B4; + productRefGroup = E73B9A502B5FC58F0018E9B4 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E73B9A4E2B5FC58F0018E9B4 /* BitsBytes */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E73B9A4D2B5FC58F0018E9B4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E788BCEE2B8357A300C8F772 /* Assets.xcassets in Resources */, + E788BD142B8C832E00C8F772 /* GoogleService-Info.plist in Resources */, + E788BCEF2B8357A300C8F772 /* Preview Assets.xcassets in Resources */, + E78A32F22B83436A00C892D8 /* Launch Screen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 01DD5A349DADD0F76B36D2D4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-BitsBytes-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 211926AC0B25A7D5CEDDE4CB /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-BitsBytes/Pods-BitsBytes-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-BitsBytes/Pods-BitsBytes-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BitsBytes/Pods-BitsBytes-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E73B9A4B2B5FC58F0018E9B4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E7B16EB12BA05CB3005DD81E /* AppleSignInWrapper.swift in Sources */, + E7FEA4D82C245343003A3973 /* ChangePasswordScreenView.swift in Sources */, + E788BCED2B8357A300C8F772 /* BitsBytesApp.swift in Sources */, + E788BCE42B8357A300C8F772 /* CustomButton.swift in Sources */, + E7FEA4E52C4CF78F003A3973 /* AccessibilityHelper.swift in Sources */, + E788BD172B8C8B3300C8F772 /* RegisterScreenView.swift in Sources */, + E788BCD82B8357A300C8F772 /* ConfigurationViewModel.swift in Sources */, + E788BCEB2B8357A300C8F772 /* RoutingManager.swift in Sources */, + E788BCE02B8357A300C8F772 /* ConfigurationScreenView.swift in Sources */, + E788BCE22B8357A300C8F772 /* SignInScreenView.swift in Sources */, + E7FEA4DC2C246FC7003A3973 /* ResetPasswordScreenView.swift in Sources */, + E73567A82BCFAF2D0001E89C /* AboutMeViewModel.swift in Sources */, + E788BCEC2B8357A300C8F772 /* HomeCoordinator.swift in Sources */, + E7D318122C171B70005B03A3 /* OtpViewModel.swift in Sources */, + E788BD1B2B8CCF8800C8F772 /* ProfileCoordinator.swift in Sources */, + E7FEA4DE2C247670003A3973 /* ResetPasswordViewModel.swift in Sources */, + E7FEA4E92C4CFFBC003A3973 /* LinkAccountViewModel.swift in Sources */, + E788BCD92B8357A300C8F772 /* AppCoordinatorView.swift in Sources */, + E7FEA4EF2C4FA9B1003A3973 /* PenddingRegistrationScreenView.swift in Sources */, + E788BCE62B8357A300C8F772 /* NavBar.swift in Sources */, + E788BCDA2B8357A300C8F772 /* FavScreenView.swift in Sources */, + E7FEA4E02C2476DC003A3973 /* BaseViewModel.swift in Sources */, + E788BCDB2B8357A300C8F772 /* HomeScreenView.swift in Sources */, + E788BCE82B8357A300C8F772 /* CustomTabBar.swift in Sources */, + E7FEA4ED2C4FA8BB003A3973 /* PenddingRegistrationViewModel.swift in Sources */, + E788BCE52B8357A300C8F772 /* CustomInput.swift in Sources */, + E788BCDD2B8357A300C8F772 /* CartScreenView.swift in Sources */, + E788BCDE2B8357A300C8F772 /* PorfileScreenView.swift in Sources */, + E73F8BC82B98659F00E11B48 /* SignInEmailViewModel.swift in Sources */, + E788BCDC2B8357A300C8F772 /* SearchScreenView.swift in Sources */, + E788BCE12B8357A300C8F772 /* TestScreenView.swift in Sources */, + E74A46942C748BB000C739EA /* AddPhoneScreenView.swift in Sources */, + E788BCEA2B8357A300C8F772 /* AppCoordinator.swift in Sources */, + E7B16EB42BA1E519005DD81E /* FacebookWrapper.swift in Sources */, + E7FEA4E32C45138C003A3973 /* SignInInterruptionFlow.swift in Sources */, + E77BF0E22B94D1BB002C77C1 /* CustomRow.swift in Sources */, + E788BCE72B8357A300C8F772 /* LoaderView.swift in Sources */, + E73567AB2BD132B40001E89C /* LineWrapper.swift in Sources */, + E788BCE32B8357A300C8F772 /* NavigationWrapperView.swift in Sources */, + E76A94C92C032D1700862A4B /* PasswordlessScreenView.swift in Sources */, + E788BCDF2B8357A300C8F772 /* SplashScreenView.swift in Sources */, + E7D318102C16FF60005B03A3 /* OtpScreenView.swift in Sources */, + E73F8BCE2B99C45900E11B48 /* SignInViewModel.swift in Sources */, + E77BF0E42B94D376002C77C1 /* ProfileViewModel.swift in Sources */, + E7FEA4E72C4CFC7F003A3973 /* LinkAccountScreenView.swift in Sources */, + E76A94CB2C07073900862A4B /* PasswordlessViewModel.swift in Sources */, + E788BD192B8CA20000C8F772 /* RegisterViewModel.swift in Sources */, + E788BCF22B8357A300C8F772 /* Coordinator.swift in Sources */, + E788BCF02B8357A300C8F772 /* AppDelegate.swift in Sources */, + E7B16EB62BA304BB005DD81E /* GoogleWrapper.swift in Sources */, + E7FEA4DA2C245497003A3973 /* ChangePasswordViewModel.swift in Sources */, + E74A46962C88499600C739EA /* AccountModel.swift in Sources */, + E788BCF12B8357A300C8F772 /* SceneDelegate.swift in Sources */, + E788BCF42B8357A300C8F772 /* GigyaService.swift in Sources */, + E73567A62BCFAEE90001E89C /* AboutMeScreenView.swift in Sources */, + E73F8BC62B98649E00E11B48 /* SignInEmailScreenView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + E73B9A5B2B5FC5920018E9B4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + 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; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + E73B9A5C2B5FC5920018E9B4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + 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; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + E73B9A5E2B5FC5920018E9B4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 36500EF345FAE48629CE033A /* Pods-BitsBytes.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = BitsBytes/BitsBytes.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"BitsBytes/Preview Content\""; + DEVELOPMENT_TEAM = SQR2SK9629; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = BitsBytes/Info.plist; + INFOPLIST_KEY_NSFaceIDUsageDescription = "BitsBytes Authentication with TouchId or FaceID"; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen.storyboard"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UIUserInterfaceStyle = light; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = sap.cdc.example.bitsbytes; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E73B9A5F2B5FC5920018E9B4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 36F42C38E94EBA3902EE14F4 /* Pods-BitsBytes.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = BitsBytes/BitsBytes.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"BitsBytes/Preview Content\""; + DEVELOPMENT_TEAM = SQR2SK9629; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = BitsBytes/Info.plist; + INFOPLIST_KEY_NSFaceIDUsageDescription = "BitsBytes Authentication with TouchId or FaceID"; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen.storyboard"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UIUserInterfaceStyle = light; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = sap.cdc.example.bitsbytes; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E73B9A4A2B5FC58F0018E9B4 /* Build configuration list for PBXProject "BitsBytes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E73B9A5B2B5FC5920018E9B4 /* Debug */, + E73B9A5C2B5FC5920018E9B4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E73B9A5D2B5FC5920018E9B4 /* Build configuration list for PBXNativeTarget "BitsBytes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E73B9A5E2B5FC5920018E9B4 /* Debug */, + E73B9A5F2B5FC5920018E9B4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E73B9A472B5FC58F0018E9B4 /* Project object */; +} diff --git a/example/BitsBytes.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/BitsBytes.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/example/BitsBytes.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/BitsBytes.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/BitsBytes.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/BitsBytes.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/BitsBytes.xcodeproj/project.xcworkspace/xcuserdata/i507698.xcuserdatad/UserInterfaceState.xcuserstate b/example/BitsBytes.xcodeproj/project.xcworkspace/xcuserdata/i507698.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..06645795 Binary files /dev/null and b/example/BitsBytes.xcodeproj/project.xcworkspace/xcuserdata/i507698.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/example/BitsBytes.xcodeproj/xcshareddata/xcschemes/BitsBytes.xcscheme b/example/BitsBytes.xcodeproj/xcshareddata/xcschemes/BitsBytes.xcscheme new file mode 100644 index 00000000..44e99635 --- /dev/null +++ b/example/BitsBytes.xcodeproj/xcshareddata/xcschemes/BitsBytes.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/BitsBytes.xcodeproj/xcuserdata/i507698.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/example/BitsBytes.xcodeproj/xcuserdata/i507698.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..8f9028bb --- /dev/null +++ b/example/BitsBytes.xcodeproj/xcuserdata/i507698.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/example/BitsBytes.xcodeproj/xcuserdata/i507698.xcuserdatad/xcschemes/xcschememanagement.plist b/example/BitsBytes.xcodeproj/xcuserdata/i507698.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..71beca1b --- /dev/null +++ b/example/BitsBytes.xcodeproj/xcuserdata/i507698.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + BitsBytes.xcscheme_^#shared#^_ + + orderHint + 15 + + Shaggy.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + E73B9A4E2B5FC58F0018E9B4 + + primary + + + + + diff --git a/example/BitsBytes.xcworkspace/contents.xcworkspacedata b/example/BitsBytes.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..e0ecbc4c --- /dev/null +++ b/example/BitsBytes.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/BitsBytes.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/BitsBytes.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/BitsBytes.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/BitsBytes.xcworkspace/xcuserdata/i507698.xcuserdatad/UserInterfaceState.xcuserstate b/example/BitsBytes.xcworkspace/xcuserdata/i507698.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..7d451dac Binary files /dev/null and b/example/BitsBytes.xcworkspace/xcuserdata/i507698.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/example/BitsBytes.xcworkspace/xcuserdata/i507698.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/example/BitsBytes.xcworkspace/xcuserdata/i507698.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..b173ed20 --- /dev/null +++ b/example/BitsBytes.xcworkspace/xcuserdata/i507698.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,632 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/BitsBytes/Assets.xcassets/AccentColor.colorset/Contents.json b/example/BitsBytes/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/BitsBytes/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..94494097 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "Version 8.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/AppIcon.appiconset/Version 8.png b/example/BitsBytes/Assets.xcassets/AppIcon.appiconset/Version 8.png new file mode 100644 index 00000000..c5a4d7f4 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/AppIcon.appiconset/Version 8.png differ diff --git a/example/BitsBytes/Assets.xcassets/Contents.json b/example/BitsBytes/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/aboutme.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/aboutme.imageset/Contents.json new file mode 100644 index 00000000..71586b78 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/aboutme.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon (3).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/aboutme.imageset/Icon (3).pdf b/example/BitsBytes/Assets.xcassets/aboutme.imageset/Icon (3).pdf new file mode 100644 index 00000000..5a3f39da Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/aboutme.imageset/Icon (3).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/apple.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/apple.imageset/Contents.json new file mode 100644 index 00000000..542ad0df --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/apple.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group 625243.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/apple.imageset/Group 625243.pdf b/example/BitsBytes/Assets.xcassets/apple.imageset/Group 625243.pdf new file mode 100644 index 00000000..623cd94d Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/apple.imageset/Group 625243.pdf differ diff --git a/example/BitsBytes/Assets.xcassets/cart.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/cart.imageset/Contents.json new file mode 100644 index 00000000..6960fa53 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/cart.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "cart-full 1.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/example/BitsBytes/Assets.xcassets/cart.imageset/cart-full 1.svg b/example/BitsBytes/Assets.xcassets/cart.imageset/cart-full 1.svg new file mode 100644 index 00000000..8cd3b4ce --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/cart.imageset/cart-full 1.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/example/BitsBytes/Assets.xcassets/changepassword.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/changepassword.imageset/Contents.json new file mode 100644 index 00000000..73b14824 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/changepassword.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon (4).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/changepassword.imageset/Icon (4).pdf b/example/BitsBytes/Assets.xcassets/changepassword.imageset/Icon (4).pdf new file mode 100644 index 00000000..d73e247b Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/changepassword.imageset/Icon (4).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/email.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/email.imageset/Contents.json new file mode 100644 index 00000000..81242212 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/email.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon (1).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/email.imageset/Icon (1).pdf b/example/BitsBytes/Assets.xcassets/email.imageset/Icon (1).pdf new file mode 100644 index 00000000..1f3e449b Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/email.imageset/Icon (1).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/facebook.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/facebook.imageset/Contents.json new file mode 100644 index 00000000..f032c946 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/facebook.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group 625243 (2).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/facebook.imageset/Group 625243 (2).pdf b/example/BitsBytes/Assets.xcassets/facebook.imageset/Group 625243 (2).pdf new file mode 100644 index 00000000..f0970bf3 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/facebook.imageset/Group 625243 (2).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/fav.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/fav.imageset/Contents.json new file mode 100644 index 00000000..9a04ce84 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/fav.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "heart-2.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/example/BitsBytes/Assets.xcassets/fav.imageset/heart-2.svg b/example/BitsBytes/Assets.xcassets/fav.imageset/heart-2.svg new file mode 100644 index 00000000..4d50167a --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/fav.imageset/heart-2.svg @@ -0,0 +1,3 @@ + + + diff --git a/example/BitsBytes/Assets.xcassets/google.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/google.imageset/Contents.json new file mode 100644 index 00000000..de9d1ad3 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/google.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group 625243 (1).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/google.imageset/Group 625243 (1).pdf b/example/BitsBytes/Assets.xcassets/google.imageset/Group 625243 (1).pdf new file mode 100644 index 00000000..f750f60b Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/google.imageset/Group 625243 (1).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/googleplus.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/googleplus.imageset/Contents.json new file mode 100644 index 00000000..de9d1ad3 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/googleplus.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group 625243 (1).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/googleplus.imageset/Group 625243 (1).pdf b/example/BitsBytes/Assets.xcassets/googleplus.imageset/Group 625243 (1).pdf new file mode 100644 index 00000000..f750f60b Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/googleplus.imageset/Group 625243 (1).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/headphone.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/headphone.imageset/Contents.json new file mode 100644 index 00000000..2340859b --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/headphone.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Rectangle 17460.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/headphone.imageset/Rectangle 17460.png b/example/BitsBytes/Assets.xcassets/headphone.imageset/Rectangle 17460.png new file mode 100644 index 00000000..5415b808 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/headphone.imageset/Rectangle 17460.png differ diff --git a/example/BitsBytes/Assets.xcassets/home.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/home.imageset/Contents.json new file mode 100644 index 00000000..e94db487 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/home.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Shaggy_Logo 2 3.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/home.imageset/Shaggy_Logo 2 3.svg b/example/BitsBytes/Assets.xcassets/home.imageset/Shaggy_Logo 2 3.svg new file mode 100644 index 00000000..df7826ae --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/home.imageset/Shaggy_Logo 2 3.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/BitsBytes/Assets.xcassets/homePhoto.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/homePhoto.imageset/Contents.json new file mode 100644 index 00000000..42065c1b --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/homePhoto.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Rectangle 17458.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/homePhoto.imageset/Rectangle 17458.png b/example/BitsBytes/Assets.xcassets/homePhoto.imageset/Rectangle 17458.png new file mode 100644 index 00000000..c926a3fe Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/homePhoto.imageset/Rectangle 17458.png differ diff --git a/example/BitsBytes/Assets.xcassets/line.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/line.imageset/Contents.json new file mode 100644 index 00000000..0fcfef3a --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/line.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon Button.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/line.imageset/Icon Button.svg b/example/BitsBytes/Assets.xcassets/line.imageset/Icon Button.svg new file mode 100644 index 00000000..1400b7e4 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/line.imageset/Icon Button.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/example/BitsBytes/Assets.xcassets/logo.imageset/Button 1.pdf b/example/BitsBytes/Assets.xcassets/logo.imageset/Button 1.pdf new file mode 100644 index 00000000..8c0e83d8 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/logo.imageset/Button 1.pdf differ diff --git a/example/BitsBytes/Assets.xcassets/logo.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/logo.imageset/Contents.json new file mode 100644 index 00000000..f92491c6 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/logo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Button 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/logout.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/logout.imageset/Contents.json new file mode 100644 index 00000000..1e08750d --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/logout.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon (6).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/logout.imageset/Icon (6).pdf b/example/BitsBytes/Assets.xcassets/logout.imageset/Icon (6).pdf new file mode 100644 index 00000000..caaeda45 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/logout.imageset/Icon (6).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/mac.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/mac.imageset/Contents.json new file mode 100644 index 00000000..489f14fb --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/mac.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Rectangle 17460.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/mac.imageset/Rectangle 17460.pdf b/example/BitsBytes/Assets.xcassets/mac.imageset/Rectangle 17460.pdf new file mode 100644 index 00000000..cbd33a55 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/mac.imageset/Rectangle 17460.pdf differ diff --git a/example/BitsBytes/Assets.xcassets/passwordless.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/passwordless.imageset/Contents.json new file mode 100644 index 00000000..bfbeb098 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/passwordless.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/passwordless.imageset/Icon.pdf b/example/BitsBytes/Assets.xcassets/passwordless.imageset/Icon.pdf new file mode 100644 index 00000000..5f6d168a Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/passwordless.imageset/Icon.pdf differ diff --git a/example/BitsBytes/Assets.xcassets/phone.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/phone.imageset/Contents.json new file mode 100644 index 00000000..7da7e53b --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/phone.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon (2).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/phone.imageset/Icon (2).pdf b/example/BitsBytes/Assets.xcassets/phone.imageset/Icon (2).pdf new file mode 100644 index 00000000..be70b0d7 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/phone.imageset/Icon (2).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/profile.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/profile.imageset/Contents.json new file mode 100644 index 00000000..5b9bcace --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/profile.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "person.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/example/BitsBytes/Assets.xcassets/profile.imageset/person.svg b/example/BitsBytes/Assets.xcassets/profile.imageset/person.svg new file mode 100644 index 00000000..ab9d1de2 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/profile.imageset/person.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/example/BitsBytes/Assets.xcassets/search.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/search.imageset/Contents.json new file mode 100644 index 00000000..548ab264 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/search.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "search.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/example/BitsBytes/Assets.xcassets/search.imageset/search.svg b/example/BitsBytes/Assets.xcassets/search.imageset/search.svg new file mode 100644 index 00000000..3065cced --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/search.imageset/search.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/example/BitsBytes/Assets.xcassets/settings.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/settings.imageset/Contents.json new file mode 100644 index 00000000..f82f602d --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/settings.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "action-settings.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/settings.imageset/action-settings.svg b/example/BitsBytes/Assets.xcassets/settings.imageset/action-settings.svg new file mode 100644 index 00000000..44e58651 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/settings.imageset/action-settings.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/example/BitsBytes/Assets.xcassets/splash.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/splash.imageset/Contents.json new file mode 100644 index 00000000..be4679ef --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/splash.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Splash Screen (1).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/splash.imageset/Splash Screen (1).pdf b/example/BitsBytes/Assets.xcassets/splash.imageset/Splash Screen (1).pdf new file mode 100644 index 00000000..dab21bb9 Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/splash.imageset/Splash Screen (1).pdf differ diff --git a/example/BitsBytes/Assets.xcassets/splashb.imageset/Contents.json b/example/BitsBytes/Assets.xcassets/splashb.imageset/Contents.json new file mode 100644 index 00000000..bf8d5085 --- /dev/null +++ b/example/BitsBytes/Assets.xcassets/splashb.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Splash Screen.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Assets.xcassets/splashb.imageset/Splash Screen.png b/example/BitsBytes/Assets.xcassets/splashb.imageset/Splash Screen.png new file mode 100644 index 00000000..27f490fc Binary files /dev/null and b/example/BitsBytes/Assets.xcassets/splashb.imageset/Splash Screen.png differ diff --git a/example/BitsBytes/BitsBytes.entitlements b/example/BitsBytes/BitsBytes.entitlements new file mode 100644 index 00000000..0751e66f --- /dev/null +++ b/example/BitsBytes/BitsBytes.entitlements @@ -0,0 +1,16 @@ + + + + + aps-environment + development + com.apple.developer.applesignin + + Default + + com.apple.developer.associated-domains + + webcredentials:sagi.gigya-cs.com + + + diff --git a/example/BitsBytes/BitsBytesApp.swift b/example/BitsBytes/BitsBytesApp.swift new file mode 100644 index 00000000..b1e0e634 --- /dev/null +++ b/example/BitsBytes/BitsBytesApp.swift @@ -0,0 +1,19 @@ +// +// BitsBytesApp.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +@main +struct BitsBytesApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate + + var body: some Scene { + WindowGroup { + AppCoordinatorView(coordinator: AppCoordinator()) + } + } +} diff --git a/example/BitsBytes/Coordinators/AppCoordinator.swift b/example/BitsBytes/Coordinators/AppCoordinator.swift new file mode 100644 index 00000000..b140802d --- /dev/null +++ b/example/BitsBytes/Coordinators/AppCoordinator.swift @@ -0,0 +1,65 @@ +// +// AppCoordinator.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation +import Combine +import SwiftUI +import Observation + +@Observable +class AppCoordinator { + let gigya = GigyaService() + + var selectedTab: Screens + var coordinatorStack: [Screens: Coordinator] + var isAppActive = false + + var isLoggedIn: Bool + + var webViewMode: Bool = false + + var selectionBinding: Binding { Binding( + get: { + self.selectedTab + }, + set: { + // check if it the current tab and pop to the root + if $0 == self.selectedTab { + self.coordinatorStack[self.selectedTab]?.routing.popToRoot() + } + self.selectedTab = $0 + } + )} + + + init() { + self.selectedTab = .home + self.isLoggedIn = gigya.shared.isLoggedIn() + + self.coordinatorStack = [:] + let homeRouting = RoutingManager() + self.coordinatorStack[.home] = HomeCoordinator(parent: self, routing: homeRouting, id: .home) + + let searchRouting = RoutingManager() + self.coordinatorStack[.search] = HomeCoordinator(parent: self, routing: searchRouting, id: .search) + + let favRouting = RoutingManager() + self.coordinatorStack[.fav] = HomeCoordinator(parent: self, routing: favRouting, id: .fav) + + let cartRouting = RoutingManager() + self.coordinatorStack[.cart] = HomeCoordinator(parent: self, routing: cartRouting, id: .cart) + + let profileRouting = RoutingManager() + self.coordinatorStack[.profile] = ProfileCoordinator(parent: self, routing: profileRouting, id: .profile) + + + } + + func pushToSettings() { + self.coordinatorStack[selectedTab]?.routing.push(.configuration) + } +} diff --git a/example/BitsBytes/Coordinators/HomeCoordinator.swift b/example/BitsBytes/Coordinators/HomeCoordinator.swift new file mode 100644 index 00000000..b465a547 --- /dev/null +++ b/example/BitsBytes/Coordinators/HomeCoordinator.swift @@ -0,0 +1,19 @@ +// +// HomeCoordinator.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation + +class HomeCoordinator: Coordinator, Identifiable { + override init(parent: AppCoordinator, routing: RoutingManager, id: Screens) { + super.init(parent: parent, routing: routing, id: id) + } + + override func start() { + + } + +} diff --git a/example/BitsBytes/Coordinators/ProfileCoordinator.swift b/example/BitsBytes/Coordinators/ProfileCoordinator.swift new file mode 100644 index 00000000..7038ba64 --- /dev/null +++ b/example/BitsBytes/Coordinators/ProfileCoordinator.swift @@ -0,0 +1,25 @@ +// +// ProfileCoordinator.swift +// BitsBytes +// +// Created by Sagi Shmuel on 26/02/2024. +// + +import Foundation + +class ProfileCoordinator: Coordinator, Identifiable { + override init(parent: AppCoordinator, routing: RoutingManager, id: Screens) { + super.init(parent: parent, routing: routing, id: id) + + routing.flowManager?.currentCordinator = self + } + + override func start() { + + } + + func popToRoot() { + routing.popToRoot() + } + +} diff --git a/example/BitsBytes/Coordinators/RoutingManager.swift b/example/BitsBytes/Coordinators/RoutingManager.swift new file mode 100644 index 00000000..40706381 --- /dev/null +++ b/example/BitsBytes/Coordinators/RoutingManager.swift @@ -0,0 +1,84 @@ +// +// RoutingCoordinator.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import Foundation +import SwiftUI +import Observation + +@Observable +class RoutingManager { + var screens = NavigationPath() + let gigya = GigyaService() + + var flowManager: SignInInterruptionFlow? = SignInInterruptionFlow() + + @ViewBuilder + func navigate(to screen: Screens) -> some View { + switch screen { + case .home: + HomeScreenView() + case .configuration: + let configurationViewModel = ConfigurationViewModel(gigya: gigya) + ConfigurationScreenView(viewModel: configurationViewModel) + case .profile: + let profileViewModel = ProfileViewModel(gigya: gigya) + PorfileScreenView(viewModel: profileViewModel) + case .signin: + let signinViewModel = SignInViewModel(gigya: gigya, flowManager: flowManager!) + SignInScreenView(viewModel: signinViewModel) + case .register: + let registerViewModel = RegisterViewModel(gigya: gigya, flowManager: flowManager!) + RegisterScreenView(viewModel: registerViewModel) + case .signinemail: + let signInEmailrViewModel = SignInEmailViewModel(gigya: gigya) + SignInEmailScreenView(viewModel: signInEmailrViewModel) + case .aboutme: + let aboutmeViewModel = AboutMeViewModel(gigya: gigya) + AboutMeScreenView(viewModel: aboutmeViewModel) + case .passwordless: + let passwordlessViewModel = PasswordlessViewModel(gigya: gigya) + PasswordlessScreenView(viewModel: passwordlessViewModel) + case .otpLogin: + let otpViewModel = OtpViewModel(gigya: gigya, flowManager: flowManager!) + OtpScreenView(viewModel: otpViewModel) + case .changePass: + let changePassViewModel = ChangePasswordViewModel(gigya: gigya) + ChangePasswordScreenView(viewModel: changePassViewModel) + case .resetPassword: + let resetPassViewModel = ResetPasswordViewModel(gigya: gigya) + ResetPasswordScreenView(viewModel: resetPassViewModel) + + case .linkAccount: + let linkViewModel = LinkAccountViewModel(gigya: gigya, flowManager: flowManager!) + LinkAccountScreenView(viewModel: linkViewModel) + case .penddingRegistration: + let penddingViewModel = PenddingRegistrationViewModel(gigya: gigya, flowManager: flowManager!) + PenddingRegistrationScreenView(viewModel: penddingViewModel) + case .addPhone : + let otpViewModel = OtpViewModel(gigya: gigya, flowManager: flowManager!) + AddPhoneScreenView(viewModel: otpViewModel) + default: + HomeScreenView() + } + } + + // add screen + func push(_ screen: Screens) { + screens.append(screen) + } + + // remove last screen + func pop() { + screens.removeLast() + } + + // go to root screen + func popToRoot() { + screens.removeLast(screens.count) + } +} + diff --git a/example/BitsBytes/Info.plist b/example/BitsBytes/Info.plist new file mode 100644 index 00000000..0408ed58 --- /dev/null +++ b/example/BitsBytes/Info.plist @@ -0,0 +1,94 @@ + + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER) + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + + + FacebookAppID + + FacebookClientToken + + FacebookDisplayName + BitsBytes + GigyaAccount + + extraProfileFields + + languages + phones + education + + include + + data + profile + emails + + + GigyaApiDomain + us1.gigya.com + GigyaApiKey + + GoogleClientID + + GoogleServerClientID + + LSApplicationQueriesSchemes + + fbapi + fbapi20130214 + fbapi20130410 + fbapi20130702 + fbapi20131010 + fbapi20131219 + fbapi20140410 + fbapi20140116 + fbapi20150313 + fbapi20150629 + fbapi20160328 + fbauth + fbauth2 + fb-messenger-api20140430 + lineauth + line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER) + wechat + weixin + weixinULAPI + fb-messenger-share-api + fbshareextension + lineauth2 + + LineSDKConfig + + ChannelID + 2004690310 + + + diff --git a/example/BitsBytes/Preview Content/Preview Assets.xcassets/Contents.json b/example/BitsBytes/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/example/BitsBytes/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/BitsBytes/Services/GigyaService.swift b/example/BitsBytes/Services/GigyaService.swift new file mode 100644 index 00000000..8e495d03 --- /dev/null +++ b/example/BitsBytes/Services/GigyaService.swift @@ -0,0 +1,13 @@ +// +// GigyaService.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import Foundation +import Gigya + +class GigyaService { + lazy var shared = Gigya.sharedInstance(AccountModel.self) +} diff --git a/example/BitsBytes/System/AccessibilityHelper.swift b/example/BitsBytes/System/AccessibilityHelper.swift new file mode 100644 index 00000000..d98c3606 --- /dev/null +++ b/example/BitsBytes/System/AccessibilityHelper.swift @@ -0,0 +1,27 @@ +// +// AccessibilityHelper.swift +// BitsBytes +// +// Created by Sagi Shmuel on 21/07/2024. +// + +import SwiftUI + +struct AccessibilityId: ViewModifier { + let label: String + let clazz: String + + func body(content: Content) -> some View { + + content + .accessibilityIdentifier("\(clazz)_\(label)") + } +} + +extension View { + func accessibilityId(_ tag: T, _ label: String) -> some View { + let clazz = String(describing: type(of: T.self)) + .replacingOccurrences(of: ".Type", with: "") + return modifier(AccessibilityId(label: label, clazz: clazz)) + } +} diff --git a/example/BitsBytes/System/AccountModel.swift b/example/BitsBytes/System/AccountModel.swift new file mode 100644 index 00000000..43349250 --- /dev/null +++ b/example/BitsBytes/System/AccountModel.swift @@ -0,0 +1,59 @@ +// +// AccountModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 04/09/2024. +// + +import Foundation +import Gigya + +struct AccountModel: GigyaAccountProtocol { + var UID: String? + + var profile: GigyaProfile? + + var UIDSignature: String? + + var apiVersion: Int? + + var created: String? + + var createdTimestamp: Double? + + var isActive: Bool? + + var isRegistered: Bool? + + var isVerified: Bool? + + var lastLogin: String? + + var lastLoginTimestamp: Double? + + var lastUpdated: String? + + var lastUpdatedTimestamp: Double? + + var loginProvider: String? + + var oldestDataUpdated: String? + + var oldestDataUpdatedTimestamp: Double? + + var registered: String? + + var registeredTimestamp: Double? + + var signatureTimestamp: String? + + var socialProviders: String? + + var verified: String? + + var verifiedTimestamp: Double? + + var phoneNumber: String? + + +} diff --git a/example/BitsBytes/System/AppDelegate.swift b/example/BitsBytes/System/AppDelegate.swift new file mode 100644 index 00000000..3565a016 --- /dev/null +++ b/example/BitsBytes/System/AppDelegate.swift @@ -0,0 +1,133 @@ +// +// AppDelegate.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation +import UIKit +import Firebase +import FirebaseMessaging +import Gigya +import GigyaTfa +import GigyaAuth +import FBSDKCoreKit +import AppTrackingTransparency +import AdSupport +import LineSDK + + +class AppDelegate: NSObject, UIApplicationDelegate { + var gigya: GigyaCore? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + LoginManager.shared.setup(channelID: "2004690310", universalLinkURL: nil) + + FirebaseApp.configure() + + // Gigya dependencies + gigya = Gigya.sharedInstance(AccountModel.self) + + GigyaLogger.setDebugMode(to: true) + + GigyaAuth.shared.registerForRemoteNotifications() + GigyaTfa.shared.registerForRemoteNotifications() + GigyaAuth.shared.register(scheme: AccountModel.self) + + ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions) + + // Request permissions for tracking ( for Facebook limited login ) + requestPermission() + + return true + } + + func requestPermission() { + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization { status in + switch status { + case .authorized: + // Tracking authorization dialog was shown + // and we are authorized + print("Authorized") + + // Now that we are authorized we can get the IDFA + print(ASIdentifierManager.shared().advertisingIdentifier) + case .denied: + // Tracking authorization dialog was + // shown and permission is denied + print("Denied") + case .notDetermined: + // Tracking authorization dialog has not been shown + print("Not Determined") + case .restricted: + print("Restricted") + @unknown default: + print("Unknown") + } + } + } + } + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + let sceneConfig: UISceneConfiguration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role) + sceneConfig.delegateClass = SceneDelegate.self + return sceneConfig + } + + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { + let _ = LoginManager.shared.application(app, open: url) + let handled = ApplicationDelegate.shared.application( + app, + open: url, + sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, + annotation: options[UIApplication.OpenURLOptionsKey.annotation]) + + return handled + } +} + +// MARK: Firebase Messaging +extension AppDelegate: MessagingDelegate { + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) } + let token = tokenParts.joined() + print("Device Token: \(token)") + + Messaging.messaging().apnsToken = deviceToken + } + + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + print("Firebase registration token: \(fcmToken!)") + let dataDict:[String: String] = ["token": fcmToken!] + + gigya?.updatePushToken(key: fcmToken!) + NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict) + } +} + +// MARK: Menagment notifications +@available(iOS 10.0, *) +extension AppDelegate: UNUserNotificationCenterDelegate { + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + gigya?.receivePush(userInfo: userInfo, completion: completionHandler) + } + + func application( + _ application: UIApplication, + didFailToRegisterForRemoteNotificationsWithError error: Error) { + print("Failed to register: \(error)") + } + + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { + // tap on notification + gigya?.verifyPush(with: response) + + completionHandler() + } + + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + completionHandler([.badge, .sound, .banner, .list]) + } +} diff --git a/example/BitsBytes/System/Coordinator.swift b/example/BitsBytes/System/Coordinator.swift new file mode 100644 index 00000000..6ca22722 --- /dev/null +++ b/example/BitsBytes/System/Coordinator.swift @@ -0,0 +1,62 @@ +// +// Coordinator.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation +import SwiftUI + +protocol CoordinatorProtocol: AnyObject, ObservableObject { + var parent: AppCoordinator { get set } + var routing: RoutingManager { get set } + var id: Screens { get set } + + func start() +} + +@Observable +open class Coordinator: CoordinatorProtocol { + var parent: AppCoordinator + var routing: RoutingManager + var id: Screens + + init(parent: AppCoordinator, routing: RoutingManager, id: Screens) { + self.parent = parent + self.routing = routing + self.id = id + } + + func start() { + + } + + +} + +enum Screens: String, CaseIterable { + case home + case search + case cart + case fav + case profile + case configuration + case signin + case register + case signinemail + case aboutme + case passwordless + case otpLogin + case changePass + case resetPassword + case linkAccount + case penddingRegistration + case addPhone + + static func onlyTabs() -> [Screens] { + return [.home, .search, .cart, .fav, .profile] + } + +} + diff --git a/example/BitsBytes/System/SceneDelegate.swift b/example/BitsBytes/System/SceneDelegate.swift new file mode 100644 index 00000000..7c410166 --- /dev/null +++ b/example/BitsBytes/System/SceneDelegate.swift @@ -0,0 +1,46 @@ +// +// SceneDelegate.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation +import UIKit +import LineSDK + +class SceneDelegate: NSObject, UIWindowSceneDelegate { + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let _ = (scene as? UIWindowScene) else { return } + print("SceneDelegate is connected!") + } + + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + if let url = URLContexts.first?.url { + // Handle URL + let _ = LoginManager.shared.application(UIApplication.shared, open: url) + } + } + + func sceneDidDisconnect(_ scene: UIScene) { + + } + + func sceneDidBecomeActive(_ scene: UIScene) { + + } + + func sceneWillResignActive(_ scene: UIScene) { + + } + + func sceneWillEnterForeground(_ scene: UIScene) { + + } + + func sceneDidEnterBackground(_ scene: UIScene) { + + } +} diff --git a/example/BitsBytes/UI/AppCoordinatorView.swift b/example/BitsBytes/UI/AppCoordinatorView.swift new file mode 100644 index 00000000..fda58e51 --- /dev/null +++ b/example/BitsBytes/UI/AppCoordinatorView.swift @@ -0,0 +1,53 @@ +// +// ContentView.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +struct AppCoordinatorView: View { + @State var coordinator: AppCoordinator + + init(coordinator: AppCoordinator) { + self.coordinator = coordinator + + UITabBar.appearance().isHidden = true + } + + var body: some View { + if self.coordinator.isAppActive { + ZStack{ + VStack { + TabView(selection: coordinator.selectionBinding){ + + NavigationWrapperView(coordinator: coordinator.coordinatorStack[.home]!).tag(Screens.home) + + SearchScreenView(coordinator: coordinator.coordinatorStack[.search]! as! HomeCoordinator).tag(Screens.search) + + FavScreenView(coordinator: coordinator.coordinatorStack[.fav]! as! HomeCoordinator).tag(Screens.fav) + + CartScreenView(coordinator: coordinator.coordinatorStack[.cart]! as! HomeCoordinator).tag(Screens.cart) + + NavigationWrapperView(coordinator: coordinator.coordinatorStack[.profile]! as! ProfileCoordinator).tag(Screens.profile) + + } + } + VStack { + Spacer() + CustomTabBar(selectedTab: coordinator.selectionBinding) + } + } + .environment(coordinator) + .ignoresSafeArea() + } else { + SplashScreenView(isActive: $coordinator.isAppActive) + } + + } +} + +#Preview { + AppCoordinatorView(coordinator: AppCoordinator()) +} diff --git a/example/BitsBytes/UI/Components/CustomButton.swift b/example/BitsBytes/UI/Components/CustomButton.swift new file mode 100644 index 00000000..3c5d422e --- /dev/null +++ b/example/BitsBytes/UI/Components/CustomButton.swift @@ -0,0 +1,86 @@ +// +// CustomButton.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import SwiftUI + +struct CustomButton: View { + let action: () -> Void + let label: String + let icon: String? + let padding: Int + + init(action: @escaping () -> Void, label: String, icon: String? = nil, padding: Int = 60) { + self.action = action + self.label = label + self.icon = icon + self.padding = padding + } + + var body: some View { + Button { + action() + } label: { + HStack { + if let icon { + Image(icon).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 0)) + Spacer() + } + Text(label) + .font(.system(size: 14)) + .bold() + .foregroundStyle(Color(red: 4/255, green: 7/255, blue: 43/255)) + if icon != nil { + Spacer() + } + } + .frame(maxWidth: .infinity, minHeight: 40, maxHeight: 40) + .overlay( + RoundedRectangle(cornerRadius: 5) + .stroke(Color(red: 4/255, green: 7/255, blue: 43/255), lineWidth: 1) + ) + .padding(EdgeInsets(top: 3, leading: CGFloat(padding), bottom: 3, trailing: CGFloat(padding))) + + } + .tint(.white) + } +} + +struct CustomDarkButton: View { + let action: () -> Void + let label: String + let padding: Int + + init(action: @escaping () -> Void, label: String, padding: Int = 60) { + self.action = action + self.label = label + self.padding = padding + } + + var body: some View { + Button{ + action() + } label: { + Text(label) + .font(.system(size: 14)) + .bold() + .foregroundStyle(.white) + .frame(maxWidth: .infinity, maxHeight: 40) + .background(Color(red: 4/255, green: 7/255, blue: 43/255)) + .buttonStyle(.bordered) + .cornerRadius(5) + .padding(EdgeInsets(top: 3, leading: CGFloat(padding), bottom: 3, trailing: CGFloat(padding))) + } + .tint(.white) + } +} + + +#Preview { + CustomDarkButton(action: {}, label: "Button") +} + + diff --git a/example/BitsBytes/UI/Components/CustomInput.swift b/example/BitsBytes/UI/Components/CustomInput.swift new file mode 100644 index 00000000..748552a5 --- /dev/null +++ b/example/BitsBytes/UI/Components/CustomInput.swift @@ -0,0 +1,171 @@ +// +// CustomInput.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import SwiftUI + +struct CustomInput: View { + + let label: String + let placeholder: String + var secured: Bool = false + + @Binding var value: String + @State var disable = false + @State var lineColor = Color(red: 217/255, green: 217/255, blue: 217/255) + + var body: some View { + VStack { + VStack { + Text(label) + .frame(maxWidth: .infinity, alignment: .leading) + .accessibilityHidden(true) + if secured { + SecureField("", text: $value) + .disabled(disable) + .bold() + .placeholder(when: value.isEmpty) { + Text(placeholder).foregroundColor(.gray).accessibilityHidden(true) + } + .accessibilityIdentifier("SecureField") + + } else { + TextField("", text: $value, onEditingChanged: { state in + if state { + lineColor = .black + } else { + lineColor = Color(red: 217/255, green: 217/255, blue: 217/255) + } + }) + .disabled(disable) + .bold() + .placeholder(when: value.isEmpty) { + Text(placeholder).foregroundColor(.gray).accessibilityHidden(true) + } + .accessibilityIdentifier("TextField") + + } + }.padding(EdgeInsets(top: 10, leading: 30, bottom: 10, trailing: 30)) + }.background(.white) + Spacer() + .frame(maxWidth: .infinity, maxHeight: 1) + .background(lineColor) + } +} + +struct CustomInputStyle2: View { + let label: String + let placeholder: String + let secured: Bool + var type: UIKeyboardType = .default + var contentType: UITextContentType? = .none + @State var disable = false + @Binding var value: String + + + var body: some View { + VStack { + Text(label) + .font(.system(size: 14)) + .frame(maxWidth: .infinity, alignment: .leading) + .foregroundColor(.gray) + + if secured { + SecureField(placeholder, text: $value) + .textFieldStyle(.roundedBorder) + .border(width: 0.6, edges: [.bottom], color: .gray) + } else { + TextField(placeholder, text: $value) + .keyboardType(type) + .textContentType(contentType) + .disabled(disable) + .textFieldStyle(.roundedBorder) + .border(width: 0.6, edges: [.bottom], color: .gray) + } + +// .shadow(color: .gray, radius: 1, x: 0, y: 1) + + + } + .padding(EdgeInsets(top: 10, leading: 60, bottom: 0, trailing: 60)) + } +} + +struct CustomDatePicker: View { + + let label: String + let placeholder: String + + @Binding var value: Date + @State var disable = false + @State var lineColor = Color(red: 217/255, green: 217/255, blue: 217/255) + + var body: some View { + VStack { + VStack { + Text(label) + .frame(maxWidth: .infinity, alignment: .leading) + .accessibilityHidden(true) + HStack { + DatePicker(selection: $value, in: ...Date.now, displayedComponents: .date) { + } + .labelsHidden() + .clipped() + .fixedSize() + .disabled(disable) + .bold() + .accessibilityIdentifier("DatePicker") + Spacer() + } + }.padding(EdgeInsets(top: 10, leading: 30, bottom: 10, trailing: 30)) + }.background(.white) + Spacer() + .frame(maxWidth: .infinity, maxHeight: 1) + .background(lineColor) + } +} + +#Preview { + CustomDatePicker(label: "Test", placeholder: "test", value: .constant(Date.now)) +} + + +extension View { + func placeholder( + when shouldShow: Bool, + alignment: Alignment = .leading, + @ViewBuilder placeholder: () -> Content) -> some View { + + ZStack(alignment: alignment) { + placeholder().opacity(shouldShow ? 1 : 0) + self + } + } +} + + +struct EdgeBorder: Shape { + var width: CGFloat + var edges: [Edge] + + func path(in rect: CGRect) -> Path { + edges.map { edge -> Path in + switch edge { + case .top: return Path(.init(x: rect.minX, y: rect.minY, width: rect.width, height: width)) + case .bottom: return Path(.init(x: rect.minX+3, y: rect.maxY - width, width: rect.width-5, height: width)) + case .leading: return Path(.init(x: rect.minX, y: rect.minY, width: width, height: rect.height)) + case .trailing: return Path(.init(x: rect.maxX - width, y: rect.minY, width: width, height: rect.height)) + } + }.reduce(into: Path()) { $0.addPath($1) } + } +} + +extension View { + func border(width: CGFloat, edges: [Edge], color: Color) -> some View { + overlay(EdgeBorder(width: width, edges: edges).foregroundColor(color)) + } +} + diff --git a/example/BitsBytes/UI/Components/CustomRow.swift b/example/BitsBytes/UI/Components/CustomRow.swift new file mode 100644 index 00000000..323be6b0 --- /dev/null +++ b/example/BitsBytes/UI/Components/CustomRow.swift @@ -0,0 +1,71 @@ +// +// CustomRow.swift +// BitsBytes +// +// Created by Sagi Shmuel on 03/03/2024. +// + +import SwiftUI + +struct CustomRow: View { + let label: String + let icon: String + let showRightIcon: Bool + let closure: ()-> Void + + var body: some View { + HStack { + Image(icon) + .frame(maxWidth: 30, alignment: .leading) + Text(label) + .frame(maxWidth: .infinity, minHeight: 30, alignment: .leading) + if showRightIcon { + Image(systemName: "chevron.compact.right") + .frame(minWidth: 30, alignment: .trailing) + } + } + .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)) + .frame(maxWidth: .infinity, minHeight: 50, alignment: .center) + .background(.white) + .border(width: 1, edges: [.bottom], color: Color(red: 217/255, green: 217/255, blue: 217/255)) + .onTapGesture { + closure() + } + } +} + +struct CustomRowWithButton: View { + let label: String + @Binding var active: Bool + let closure: ()-> Void + + var body: some View { + HStack { + Text(label) + + Spacer() + if active { + CustomDarkButton(action: { + closure() + }, label: "Deactivate", padding: 0) + .frame(width: 130, alignment: .trailing) + .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 15)) + + } else { + CustomButton(action: { + closure() + }, label: "Activate", padding: 0) + .frame(width: 130, alignment: .trailing) + .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 15)) + } + } + .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0)) + .frame(maxWidth: .infinity, minHeight: 60) + .background(.white) + .border(width: 1, edges: [.bottom], color: Color(red: 217/255, green: 217/255, blue: 217/255)) + } +} + +#Preview { + CustomRowWithButton(label: "Passwordless login", active: .constant(true) , closure: {}) +} diff --git a/example/BitsBytes/UI/Components/CustomTabBar.swift b/example/BitsBytes/UI/Components/CustomTabBar.swift new file mode 100644 index 00000000..90f618a5 --- /dev/null +++ b/example/BitsBytes/UI/Components/CustomTabBar.swift @@ -0,0 +1,49 @@ +// +// CustomTabBar.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation +import SwiftUI + +struct CustomTabBar: View { + @Binding var selectedTab: Screens + + var body: some View { + VStack { + HStack { + ForEach(Screens.onlyTabs(), id: \.rawValue) { tab in + Spacer() + Image(tab.rawValue) + .colorMultiply(tab == selectedTab ? .white : .gray) + .opacity(tab == selectedTab ? 1 : 0.4) + .scaleEffect(tab == selectedTab ? 1.25 : 1) + .accessibilityIdentifier("\(tab.rawValue)TabButton") + .onTapGesture { + withAnimation(.easeInOut(duration: 0.2)) { + selectedTab = tab + } + } + Spacer() + } + } + .frame(width: nil, height: 60) + .padding(.leading) + .padding(.trailing) + .background(.white) + .cornerRadius(10) + + Spacer() + .frame(maxWidth: .infinity, maxHeight: 10) + .background(.white) + } + } + +} + +#Preview { + CustomTabBar(selectedTab: .constant(.home)) +} + diff --git a/example/BitsBytes/UI/Components/LoaderView.swift b/example/BitsBytes/UI/Components/LoaderView.swift new file mode 100644 index 00000000..f9ebb83c --- /dev/null +++ b/example/BitsBytes/UI/Components/LoaderView.swift @@ -0,0 +1,69 @@ +// +// LoaderView.swift +// +// +// Created by Sagi Shmuel on 06/02/2024. +// + +import SwiftUI + +struct LoaderView: View { + @Binding var showSpinner: Bool + @State var start: Bool = false + @State private var degree: Int = 270 + @State private var spinnerLength = 0.6 + + var body: some View { + + if showSpinner { + VStack { + Circle() + .trim(from: 0.0,to: spinnerLength) + .stroke(LinearGradient(colors: [.red,.blue], startPoint: .topLeading, endPoint: .bottomTrailing),style: StrokeStyle(lineWidth: 8.0,lineCap: .round,lineJoin:.round)) + .animation(.easeIn(duration: 1.5).repeatForever(autoreverses: true), value: start) + .frame(width: 60,height: 60) + .rotationEffect(Angle(degrees: Double(degree))) + .animation(.linear(duration: 1).repeatForever(autoreverses: false), value: start) + .onAppear { + degree = 270 + 360 + spinnerLength = 0 + start = true + } + .onDisappear { + degree = 270 + spinnerLength = 0.6 + start = false + + } + } + } + + } + +} + +struct LoaderModifier: ViewModifier { + @Binding var showSpinner: Bool + + func body(content: Content) -> some View { + ZStack { + content + LoaderView(showSpinner: $showSpinner) + } + } +} + + +class LoaderExtendModel { + @Published var showLoder: Bool = false + + func toggelLoader() { + Task { @MainActor in + self.showLoder.toggle() + } + } +} + +//#Preview { +// LoaderView(showSpinner: .constant(true)) +//} diff --git a/example/BitsBytes/UI/Components/NavBar.swift b/example/BitsBytes/UI/Components/NavBar.swift new file mode 100644 index 00000000..427d9ced --- /dev/null +++ b/example/BitsBytes/UI/Components/NavBar.swift @@ -0,0 +1,41 @@ +// +// NavStyle.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import Foundation +import SwiftUI + +struct NavBar: ViewModifier { + + @State var showIcon: Bool = true + @Environment(AppCoordinator.self) var appCordinator: AppCoordinator + + @ViewBuilder var title: C + + init(_ title: C, showIcon: Bool = true) { + self.title = title + self.showIcon = showIcon + } + + func body(content: Content) -> some View { + content + .navigationBarTitle("", displayMode: .inline) + .toolbar { + ToolbarItem(placement: .principal) { + title + } + } + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + if showIcon { + Image("settings").onTapGesture { + appCordinator.pushToSettings() + }.accessibilityIdentifier("settingsButton") + } + } + } +} + diff --git a/example/BitsBytes/UI/Flows/SignInInterruptionFlow.swift b/example/BitsBytes/UI/Flows/SignInInterruptionFlow.swift new file mode 100644 index 00000000..ec7664e5 --- /dev/null +++ b/example/BitsBytes/UI/Flows/SignInInterruptionFlow.swift @@ -0,0 +1,89 @@ +// +// SignInInterruptionFlow.swift +// BitsBytes +// +// Created by Sagi Shmuel on 15/07/2024. +// + +import Foundation +import Gigya +import GigyaAuth + +@Observable +class SignInInterruptionFlow: Identifiable { + enum Interruptions { + case none + case penddingRegistration + case conflitingAccount + } + + var currentFlow: Interruptions = .none { + didSet { + linkAccountResolver = nil + penddingRegistrationResolver = nil + } + } + + weak var currentCordinator: Coordinator? + + var linkAccountResolver: LinkAccountsResolver? + var penddingRegistrationResolver: PendingRegistrationResolver? + var otpResolver: OtpServiceVerifyProtocol? + + var resultClosure: (GigyaLoginResult) -> Void = { _ in } + var resultOtpClosure: (GigyaOtpResult) -> Void = { _ in } + + var successClousre: () -> Void = { } + var errorClousre: (String) -> Void = { _ in } + + init() { + resultOtpClosure = { [weak self] result in + switch result { + + case .success(data: _): + self?.successClousre() + case .pendingOtpVerification(resolver: let resolver): + self?.otpResolver = resolver + case .failure(error: let error): + self?.interuuptionHandle(error: error) + } + } + + resultClosure = { [weak self] result in + switch result { + case .success(data: _): + self?.successClousre() + case .failure(let error): + self?.interuuptionHandle(error: error) + + } + } + } + + func interuuptionHandle(error: LoginApiError) { + self.errorClousre(error.error.localizedDescription) + guard let interruption = error.interruption else { return } + + switch interruption { + case .pendingRegistration(resolver: let resolver): + self.currentCordinator?.routing.push(.penddingRegistration) + + self.currentFlow = .penddingRegistration + self.penddingRegistrationResolver = resolver + case .pendingVerification(regToken: let regToken): + break + case .pendingPasswordChange(regToken: let regToken): + break + case .conflitingAccount(resolver: let resolver): + self.currentCordinator?.routing.push(.linkAccount) + + self.currentFlow = .conflitingAccount + self.linkAccountResolver = resolver + case .pendingTwoFactorRegistration(response: let response, inactiveProviders: let inactiveProviders, factory: let factory): + break + case .pendingTwoFactorVerification(response: let response, activeProviders: let activeProviders, factory: let factory): + break + } + } + +} diff --git a/example/BitsBytes/UI/NavigationWrapperView.swift b/example/BitsBytes/UI/NavigationWrapperView.swift new file mode 100644 index 00000000..4889feb0 --- /dev/null +++ b/example/BitsBytes/UI/NavigationWrapperView.swift @@ -0,0 +1,24 @@ +// +// NavigationWrapperView.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +struct NavigationWrapperView: View { + @State var coordinator: T + + var body: some View { + NavigationStack(path: $coordinator.routing.screens) { + coordinator.routing.navigate(to: coordinator.id) + .navigationDestination(for: Screens.self) { screen in + coordinator.routing.navigate(to: screen) + } + + } + .environment(coordinator) + } +} + diff --git a/example/BitsBytes/UI/Screens/ConfigurationScreenView.swift b/example/BitsBytes/UI/Screens/ConfigurationScreenView.swift new file mode 100644 index 00000000..009aee76 --- /dev/null +++ b/example/BitsBytes/UI/Screens/ConfigurationScreenView.swift @@ -0,0 +1,54 @@ +// +// ConfigurationScreenView.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import SwiftUI + +struct ConfigurationScreenView: View { + @Environment(AppCoordinator.self) var appCordinator: AppCoordinator + + @ObservedObject var viewModel: ConfigurationViewModel + + var body: some View { + @Bindable var appCordinator = appCordinator + + Spacer() + .frame(maxWidth: .infinity, maxHeight: 10) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + + VStack { + Toggle("Use ScreenSets \n(default: native view)", isOn: $appCordinator.webViewMode) + .toggleStyle(SwitchToggleStyle(tint: .blue)) + .padding(EdgeInsets(top: 10, leading: 30, bottom: 10, trailing: 30)) + .background(.white) + .accessibilityId(self, "screenSetToggle") + + CustomInput(label: "API Key", placeholder: "API Key", value: $viewModel.apiKey) + .accessibilityId(self, "apiInput") + CustomInput(label: "Domain", placeholder: "Domain", value: $viewModel.domain) + .accessibilityId(self, "domainInput") + CustomInput(label: "CNAME", placeholder: "CNAME", value: $viewModel.cname) + .accessibilityId(self, "cnameInput") + + CustomDarkButton(action: { + viewModel.reInitGigya() + }, label: "SAVE") + .accessibilityId(self, "saveButton") + + LoaderView(showSpinner: $viewModel.showLoder) + + Spacer(minLength: 5) + + } + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + .modifier(NavBar(Text("APP CONFIGURATION"), showIcon: false)) + + } +} + +#Preview { + ConfigurationScreenView(viewModel: ConfigurationViewModel(gigya: GigyaService())) +} diff --git a/example/BitsBytes/UI/Screens/Interruptions/LinkAccountScreenView.swift b/example/BitsBytes/UI/Screens/Interruptions/LinkAccountScreenView.swift new file mode 100644 index 00000000..c0f93e2a --- /dev/null +++ b/example/BitsBytes/UI/Screens/Interruptions/LinkAccountScreenView.swift @@ -0,0 +1,91 @@ +// +// LinkAccountScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 21/07/2024. +// + +import SwiftUI +import Gigya + +struct LinkAccountScreenView: View { + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + @ObservedObject var viewModel: LinkAccountViewModel + + var body: some View { + VStack { + Text("Link Account") + .bold() + .font(.system(size: 24)) + .padding(7) + Text("Use your preferred method") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + if let loginProviders = + viewModel.flowManager.linkAccountResolver?.conflictingAccount?.loginProviders { + + ForEach (loginProviders, id: \.hashValue) { provider in + Image(provider) + .padding(EdgeInsets(top: 30, leading: 5, bottom: 30, trailing: 5)) + .onTapGesture { + viewModel.linkToSocial(provider: provider) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } + .accessibilityId(self, "\(provider)Button") + } + + + Rectangle() + .frame(maxWidth: .infinity, maxHeight: 1) + .foregroundColor(Color(red: 227/255, green: 227/255, blue: 227/255)) + .padding(EdgeInsets(top: 5, leading: 75, bottom: 5, trailing: 75)) + + + if loginProviders.contains("site") { + CustomInputStyle2(label: "Email:", placeholder: "Email", secured: false, disable: true, value: $viewModel.email) + .accessibilityId(self, "emailInput") + if viewModel.formIsSubmitState && viewModel.email.isEmpty { + Text("Email is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + } + + CustomInputStyle2(label: "Password:", placeholder: "Password", secured: true, value: $viewModel.pass) + .accessibilityId(self, "passInput") + if viewModel.formIsSubmitState && viewModel.pass.isEmpty { + Text("Password is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + } + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + + CustomDarkButton(action: { + viewModel.linkToSite() { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "Login") + .accessibilityId(self, "loginButton") + } + + } + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .modifier(NavBar(Text("Link Account"), showIcon: false)) + + } + +} + +#Preview { + LinkAccountScreenView( viewModel: LinkAccountViewModel(gigya: GigyaService(), flowManager: SignInInterruptionFlow())) +} diff --git a/example/BitsBytes/UI/Screens/Interruptions/PenddingRegistrationScreenView.swift b/example/BitsBytes/UI/Screens/Interruptions/PenddingRegistrationScreenView.swift new file mode 100644 index 00000000..e93f7c9f --- /dev/null +++ b/example/BitsBytes/UI/Screens/Interruptions/PenddingRegistrationScreenView.swift @@ -0,0 +1,57 @@ +// +// PenddingRegistrationScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 23/07/2024. +// + +import SwiftUI + +struct PenddingRegistrationScreenView: View { + @ObservedObject var viewModel: PenddingRegistrationViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + ZStack { + Spacer() + .frame(maxWidth: .infinity, maxHeight: 10) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + + VStack { + + Text("Additional information") + .font(.system(size: 14)) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10)) + + CustomDatePicker(label: "Birthday", placeholder: "Birthday", value: $viewModel.birthDay) + .accessibilityId(self, "birthDayInput") + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + .padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0)) + + CustomDarkButton(action: { + viewModel.setAccount { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "SEND") + .accessibilityId(self, "saveButton") + + Spacer(minLength: 5) + + } + + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + .modifier(NavBar(Text("Pending Information"), showIcon: false)) + } +} + +#Preview { + PenddingRegistrationScreenView(viewModel: PenddingRegistrationViewModel(gigya: GigyaService(), flowManager: SignInInterruptionFlow())) +} diff --git a/example/BitsBytes/UI/Screens/Profile/AboutMeScreenView.swift b/example/BitsBytes/UI/Screens/Profile/AboutMeScreenView.swift new file mode 100644 index 00000000..4af8395a --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/AboutMeScreenView.swift @@ -0,0 +1,70 @@ +// +// AboutMeScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 17/04/2024. +// + +import SwiftUI + +struct AboutMeScreenView: View { + @ObservedObject var viewModel: AboutMeViewModel + + var body: some View { + ZStack { + Spacer() + .frame(maxWidth: .infinity, maxHeight: 10) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + + VStack { + Text("About me") + .font(.system(size: 14)) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10)) + + CustomInput(label: "First Name", placeholder: "First Name", value: $viewModel.firstName) + .accessibilityId(self, "fnameInput") + CustomInput(label: "Last Name", placeholder: "Last Name", value: $viewModel.lastName) + .accessibilityId(self, "lnameInput") + + CustomInput(label: "Email", placeholder: "Email", value: $viewModel.email, disable: true) + .accessibilityId(self, "emailInput") + if !viewModel.phone.isEmpty { + CustomInput(label: "Phone", placeholder: "Phone", value: $viewModel.phone, disable: true) + .accessibilityId(self, "phoneInput") + } + Text("Additional information") + .font(.system(size: 14)) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10)) + + CustomDatePicker(label: "Birthday", placeholder: "Birthday", value: $viewModel.birthDay) + .accessibilityId(self, "birthDayInput") + CustomInput(label: "Country", placeholder: "Country", value: $viewModel.country) + .accessibilityId(self, "CountryInput") + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + .padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0)) + + CustomDarkButton(action: { + viewModel.setAccount() + }, label: "SAVE") + .accessibilityId(self, "saveButton") + + Spacer(minLength: 5) + + } + + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + .modifier(NavBar(Text("ABOUT ME"), showIcon: false)) + } +} + +#Preview { + AboutMeScreenView(viewModel: AboutMeViewModel(gigya: GigyaService())) +} diff --git a/example/BitsBytes/UI/Screens/Profile/AddPhoneScreenView.swift b/example/BitsBytes/UI/Screens/Profile/AddPhoneScreenView.swift new file mode 100644 index 00000000..d20df401 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/AddPhoneScreenView.swift @@ -0,0 +1,67 @@ +// +// AddPhoneScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 20/08/2024. +// + +import SwiftUI + +struct AddPhoneScreenView: View { + @ObservedObject var viewModel: OtpViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + + ZStack { + VStack { + Text("Add Phone Number") + .bold() + .font(.system(size: 24)) + .padding(7) + + if viewModel.codeSent == false { + Text("Please enter your phone number") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + CustomInputStyle2(label: "Phone Number:", placeholder: "Phone", secured: false, value: $viewModel.phone) + .accessibilityId(self, "PhoneInput") + + CustomDarkButton(action: { + viewModel.sendCode(mode: .update) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "Send Code") + + } else { + CustomInputStyle2(label: "Enter Verification Code:", placeholder: "", secured: false, value: $viewModel.code) + .accessibilityId(self, "PhoneInput") + + CustomDarkButton(action: { + viewModel.verifyCode() + }, label: "Verify") + + Text("Didn't get code?") + .font(.system(size: 14)) + } + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + } + + + + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + + .modifier(NavBar(Text("Sign In").bold())) + } +} + +//#Preview { +// AddPhoneScreenView() +//} diff --git a/example/BitsBytes/UI/Screens/Profile/ChangePasswordScreenView.swift b/example/BitsBytes/UI/Screens/Profile/ChangePasswordScreenView.swift new file mode 100644 index 00000000..69f851f4 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/ChangePasswordScreenView.swift @@ -0,0 +1,58 @@ +// +// ChangePasswordScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 20/06/2024. +// + +import SwiftUI + +struct ChangePasswordScreenView: View { + + @ObservedObject var viewModel: ChangePasswordViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + ZStack { + Spacer() + .frame(maxWidth: .infinity, maxHeight: 10) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + + VStack { + + CustomInput(label: "Current Password", placeholder: "Enter your current password", secured: true, value: $viewModel.currentPass) + .accessibilityId(self, "currentPassInput") + + CustomInput(label: "New Password", placeholder: "Enter new password", secured: true, value: $viewModel.newPass) + .accessibilityId(self, "newPassInput") + + CustomInput(label: "Confirm New Password", placeholder: "Enter new password", secured: true, value: $viewModel.confirmPass) + .accessibilityId(self, "confirmPassInput") + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + .padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0)) + + CustomDarkButton(action: { + viewModel.savePassword { + currentCordinator.routing.pop() + } + }, label: "Save Password") + .accessibilityId(self, "saveButton") + + Spacer(minLength: 5) + + } + + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + .modifier(NavBar(Text("Change Password"), showIcon: false)) + } +} + +#Preview { + ChangePasswordScreenView(viewModel: ChangePasswordViewModel(gigya: GigyaService())) +} diff --git a/example/BitsBytes/UI/Screens/Profile/OtpScreenView.swift b/example/BitsBytes/UI/Screens/Profile/OtpScreenView.swift new file mode 100644 index 00000000..a9e937fe --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/OtpScreenView.swift @@ -0,0 +1,67 @@ +// +// OtpScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 10/06/2024. +// + +import SwiftUI + +struct OtpScreenView: View { + @ObservedObject var viewModel: OtpViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + + ZStack { + VStack { + Text("Sign In With Phone") + .bold() + .font(.system(size: 24)) + .padding(7) + + if viewModel.codeSent == false { + Text("Please enter your phone number") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + CustomInputStyle2(label: "Phone Number:", placeholder: "Phone", secured: false, value: $viewModel.phone) + .accessibilityId(self, "PhoneInput") + + CustomDarkButton(action: { + viewModel.sendCode { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "Send Code") + + } else { + CustomInputStyle2(label: "Enter Verification Code:", placeholder: "", secured: false, value: $viewModel.code) + .accessibilityId(self, "PhoneInput") + + CustomDarkButton(action: { + viewModel.verifyCode() + }, label: "Verify") + + Text("Didn't get code?") + .font(.system(size: 14)) + } + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + } + + + + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + + .modifier(NavBar(Text("Sign In").bold())) + } +} + +//#Preview { +// OtpScreenView(viewModel: OtpViewModel(gigya: GigyaService())) +//} diff --git a/example/BitsBytes/UI/Screens/Profile/PasswordlessScreenView.swift b/example/BitsBytes/UI/Screens/Profile/PasswordlessScreenView.swift new file mode 100644 index 00000000..94004926 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/PasswordlessScreenView.swift @@ -0,0 +1,57 @@ +// +// PasswordlessScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 26/05/2024. +// + +import SwiftUI + +struct PasswordlessScreenView: View { + @ObservedObject var viewModel: PasswordlessViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + Spacer() + .frame(maxWidth: .infinity, maxHeight: 10) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + + VStack(spacing: 0) { + CustomRowWithButton(label: "Passkey Login", active: $viewModel.fidoIsAvailable) { + viewModel.useFido() + } + .accessibilityId(self, "passwordless") + + CustomRowWithButton(label: "Biometrics", active: $viewModel.biometricAvailable) { + viewModel.biometricAction() + } + .accessibilityId(self, "biometrics") + + if viewModel.biometricAvailable { + CustomDarkButton(action: { + viewModel.lockSession { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = false + } + }, label: "Locked Session") + } + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .padding(10) + .accessibilityId(self, "errorLabel") + + Spacer(minLength: 5) + + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + .modifier(NavBar(Text("LOGIN OPTIONS"), showIcon: false)) + + } +} + +#Preview { + PasswordlessScreenView(viewModel: PasswordlessViewModel(gigya: GigyaService())) +} diff --git a/example/BitsBytes/UI/Screens/Profile/RegisterScreenView.swift b/example/BitsBytes/UI/Screens/Profile/RegisterScreenView.swift new file mode 100644 index 00000000..73a9c1ee --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/RegisterScreenView.swift @@ -0,0 +1,107 @@ +// +// RegisterScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 26/02/2024. +// + +import SwiftUI + +struct RegisterScreenView: View { + + @ObservedObject var viewModel: RegisterViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + VStack { + VStack { + Text("Create your account") + .bold() + .font(.system(size: 24)) + .padding(7) + Text("Please fill out the listed inputs") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + + CustomInputStyle2(label: "First Name:", placeholder: "First Name", secured: false, value: $viewModel.firstName) + .accessibilityId(self, "firstNameInput") + if viewModel.formIsSubmitState && viewModel.firstName.isEmpty { + Text("First Name is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "firstNameEmptyError") + } + + CustomInputStyle2(label: "Last Name:", placeholder: "Last Name", secured: false, value: $viewModel.lastName) + .accessibilityId(self, "lastNameInput") + if viewModel.formIsSubmitState && viewModel.lastName.isEmpty { + Text("Last Name is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "lastNameEmptyError") + } + + CustomInputStyle2(label: "Email:", placeholder: "Email", secured: false, value: $viewModel.email) + .accessibilityId(self, "emailInput") + if viewModel.formIsSubmitState && viewModel.firstName.isEmpty { + Text("Email is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "emailEmptyError") + } + + + CustomInputStyle2(label: "Password:", placeholder: "Password", secured: true, value: $viewModel.pass) + .accessibilityId(self, "passInput") + if viewModel.formIsSubmitState && viewModel.firstName.isEmpty { + Text("Password is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "passEmptyError") + } + + + CustomInputStyle2(label: "Confirm Password:", placeholder: "Confirm Password", secured: true, value: $viewModel.confirmPass) + .accessibilityId(self, "confirmpassInput") + if viewModel.formIsSubmitState && viewModel.firstName.isEmpty { + Text("Confirm Password is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "confirmpassEmptyError") + } + + + Text("By clicking on \"register\", you conform that you have read and agree to the privacy policy and terms of use.") + .font(.system(size: 14)) + .padding(EdgeInsets(top: 10, leading: 60, bottom: 0, trailing: 60)) + + CustomDarkButton(action: { + viewModel.submit() { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "Register") + .accessibilityId(self, "registerButton") + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + + + } + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .modifier(NavBar(Text("Register").bold())) + } +} + +#Preview { + NavigationWrapperView(coordinator: Coordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .register)) +} diff --git a/example/BitsBytes/UI/Screens/Profile/ResetPasswordScreenView.swift b/example/BitsBytes/UI/Screens/Profile/ResetPasswordScreenView.swift new file mode 100644 index 00000000..26a30424 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/ResetPasswordScreenView.swift @@ -0,0 +1,68 @@ +// +// ResetPasswordScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 20/06/2024. +// + +import SwiftUI +import Gigya + +struct ResetPasswordScreenView: View { + @ObservedObject var viewModel: ResetPasswordViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + VStack { + VStack { + Text("Reset Password") + .bold() + .font(.system(size: 24)) + .padding(7) + + Text("Please enter your Email and we will send you an Email with instructions to create a new password") + .font(.system(size: 14)) + .foregroundStyle(.gray) + .multilineTextAlignment(.center) + .padding(EdgeInsets(top: 0, leading: 60, bottom: 0, trailing: 60)) + + + CustomInputStyle2(label: "Email:", placeholder: "Email", secured: false, value: $viewModel.email) + .accessibilityId(self, "emailInput") +// if viewModel.formIsSubmitState && viewModel.email.isEmpty { +// Text("Email is empty.") +// .font(.system(size: 12)) +// .foregroundStyle(.red) +// .bold() +// } + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + + CustomDarkButton(action: { + viewModel.send() +// viewModel.submit() { +// currentCordinator.routing.popToRoot() +// currentCordinator.parent.isLoggedIn = true +// } + }, label: "Reset Password") + .opacity(viewModel.resetSent ? 0.5 : 1) + .disabled(viewModel.resetSent) + .accessibilityId(self, "resetButton") + + if viewModel.resetSent == true { + Text("The password was sent to you!") + .foregroundStyle(Color(red: 0/255, green: 100/255, blue: 216/255)) + .accessibilityId(self, "passSentLabel") + } + } + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .modifier(NavBar(Text("Reset Password").bold())) + }} + +#Preview { + ResetPasswordScreenView(viewModel: ResetPasswordViewModel(gigya: GigyaService())) +} diff --git a/example/BitsBytes/UI/Screens/Profile/SignInEmailScreenView.swift b/example/BitsBytes/UI/Screens/Profile/SignInEmailScreenView.swift new file mode 100644 index 00000000..9457c62d --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/SignInEmailScreenView.swift @@ -0,0 +1,80 @@ +// +// SignInEmailScreenView.swift +// BitsBytes +// +// Created by Sagi Shmuel on 06/03/2024. +// + +import SwiftUI + +struct SignInEmailScreenView: View { + @ObservedObject var viewModel: SignInEmailViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + VStack { + VStack { + Text("Sign in with Email") + .bold() + .font(.system(size: 24)) + .padding(7) + Text("Please enter your Email and Password") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + + CustomInputStyle2(label: "Email:", placeholder: "Email", secured: false, type: .emailAddress, contentType: .emailAddress, value: $viewModel.email) + .accessibilityId(self, "emailInput") + if viewModel.formIsSubmitState && viewModel.email.isEmpty { + Text("Email is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + } + + CustomInputStyle2(label: "Password:", placeholder: "Password", secured: true, contentType: .password, value: $viewModel.pass) + .accessibilityId(self, "passInput") + if viewModel.formIsSubmitState && viewModel.pass.isEmpty { + Text("Password is empty.") + .font(.system(size: 12)) + .foregroundStyle(.red) + .bold() + } + + Text(viewModel.error) + .foregroundStyle(.red) + .bold() + .accessibilityId(self, "errorLabel") + + Text("Forgot Password?") + .bold() + .font(.system(size: 14)) + .padding(EdgeInsets(top: 12, leading: 140, bottom: 0, trailing: 0)) + .onTapGesture { +// currentCordinator.routing.push(.resetPassword) + viewModel.showPass() + } + + CustomDarkButton(action: { + viewModel.submit() { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "Login") + .accessibilityId(self, "loginButton") + + + } + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .modifier(NavBar(Text("Sign in").bold())) + .onAppear { + viewModel.currentCordinator = currentCordinator + } + } +} + +#Preview { + NavigationWrapperView(coordinator: ProfileCoordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .signinemail)) +} + diff --git a/example/BitsBytes/UI/Screens/Profile/SignInScreenView.swift b/example/BitsBytes/UI/Screens/Profile/SignInScreenView.swift new file mode 100644 index 00000000..b686a26a --- /dev/null +++ b/example/BitsBytes/UI/Screens/Profile/SignInScreenView.swift @@ -0,0 +1,109 @@ +// +// SignInScreenView.swift +// +// +// Created by Sagi Shmuel on 12/02/2024. +// + +import SwiftUI + +struct SignInScreenView: View { + @ObservedObject var viewModel: SignInViewModel + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + + var body: some View { + + ZStack { + VStack(spacing: 0) { + Text("Sign In") + .bold() + .font(.system(size: 24)) + .padding(7) + Text("Use your preferred method") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + HStack { + Image("line") + .padding(EdgeInsets(top: 30, leading: 5, bottom: 30, trailing: 5)) + .onTapGesture { + viewModel.loginWithProvider(.line) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } + .accessibilityId(self, "lineButton") + Image("facebook") + .padding(EdgeInsets(top: 30, leading: 5, bottom: 30, trailing: 5)) + .onTapGesture { + viewModel.loginWithProvider(.facebook) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } + .accessibilityId(self, "facebookButton") + Image("google") + .padding(EdgeInsets(top: 30, leading: 5, bottom: 30, trailing: 5)) + .onTapGesture { + viewModel.loginWithProvider(.google) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } + .accessibilityId(self, "googleButton") + Image("apple") + .padding(EdgeInsets(top: 30, leading: 5, bottom: 30, trailing: 5)) + .onTapGesture { + viewModel.loginWithProvider(.apple) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } + .accessibilityId(self, "appleButton") + + } + Rectangle() + .frame(maxWidth: .infinity, maxHeight: 1) + .foregroundColor(Color(red: 227/255, green: 227/255, blue: 227/255)) + .padding(EdgeInsets(top: 5, leading: 75, bottom: 5, trailing: 75)) + CustomButton(action: { + Task { + let success = await viewModel.fidoLogin() + if success { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } + }, label: "Sign in with Passkey", icon: "passwordless") + .accessibilityId(self, "passwordlessButton") + + CustomButton(action: { + currentCordinator.routing.push(.signinemail) + }, label: "Sign in with Email", icon: "email") + .accessibilityId(self, "emailButton") + + CustomButton(action: { + currentCordinator.routing.push(.otpLogin) + }, label: "Sign in with Phone", icon: "phone") + .accessibilityId(self, "phoneButton") + + if viewModel.biometricAvailable { + CustomDarkButton(action: { + viewModel.unlockSession { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + }, label: "Biometric Unlock") + .accessibilityIdentifier("Profile_biometricButton") + } + + } + } + .modifier(LoaderModifier(showSpinner: $viewModel.showLoder)) + .modifier(NavBar(Text("Sign In").bold())) + } +} + +#Preview { + NavigationWrapperView(coordinator: ProfileCoordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .signin)) +} diff --git a/example/BitsBytes/UI/Screens/SplashScreenView.swift b/example/BitsBytes/UI/Screens/SplashScreenView.swift new file mode 100644 index 00000000..65ab8331 --- /dev/null +++ b/example/BitsBytes/UI/Screens/SplashScreenView.swift @@ -0,0 +1,30 @@ +// +// SplashScreenView.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import SwiftUI + +struct SplashScreenView: View { + @Binding var isActive: Bool + + var body: some View { + Image("splash") + .resizable() + .aspectRatio(contentMode: .fill) + .ignoresSafeArea() + .onAppear { + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + withAnimation { + self.isActive = true + } + } + } + } +} + +#Preview { + SplashScreenView(isActive: .constant(true)) +} diff --git a/example/BitsBytes/UI/Screens/Tabs/CartScreenView.swift b/example/BitsBytes/UI/Screens/Tabs/CartScreenView.swift new file mode 100644 index 00000000..27e0df9c --- /dev/null +++ b/example/BitsBytes/UI/Screens/Tabs/CartScreenView.swift @@ -0,0 +1,24 @@ +// +// CartScreenView.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +struct CartScreenView: View { + @State var coordinator: Coordinator + + var body: some View { + VStack { + + } + .modifier(NavBar(Text("Cart"))) + .environment(coordinator) + } +} + +#Preview { + CartScreenView(coordinator: HomeCoordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .cart)) +} diff --git a/example/BitsBytes/UI/Screens/Tabs/FavScreenView.swift b/example/BitsBytes/UI/Screens/Tabs/FavScreenView.swift new file mode 100644 index 00000000..24c521c9 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Tabs/FavScreenView.swift @@ -0,0 +1,24 @@ +// +// FavScreenView.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +struct FavScreenView: View { + @State var coordinator: HomeCoordinator + + var body: some View { + VStack { + + } + .modifier(NavBar(Text("Favorites"))) + .environment(coordinator) + } +} + +#Preview { + FavScreenView(coordinator: HomeCoordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .fav)) +} diff --git a/example/BitsBytes/UI/Screens/Tabs/HomeScreenView.swift b/example/BitsBytes/UI/Screens/Tabs/HomeScreenView.swift new file mode 100644 index 00000000..bc5cdbf8 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Tabs/HomeScreenView.swift @@ -0,0 +1,103 @@ +// +// HomeScreenView.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import SwiftUI + +struct HomeScreenView: View { +// @Environment(HomeCoordinator.self) var currentCordinator: HomeCoordinator + + var body: some View { + ScrollView { + VStack { + Spacer() + .padding(.all) + Text("The All-new") + .foregroundStyle(.gray) + .font(.system(size: 24)) + Text("MacBook Pro") + .bold() + .font(.system(size: 32)) + Text("with Retina display") + .font(.system(size: 14)) + .foregroundStyle(Color(red: 29/255, green: 45/255, blue: 62/255)) + + CustomButton(action: { + + }, label: "Buy Now") + + Image("homePhoto") + .padding(.top) + } + VStack { + Text("All New") + .font(.system(size: 32)) + .foregroundStyle(.white) + Text("2024") + .font(.system(size: 14)) + .foregroundStyle(.white) + ScrollView(.horizontal, showsIndicators: false) { + HStack { + ZStack { + VStack { + Image("headphone").padding(.all) + Text("Headphones") + .padding([.bottom]) + } + } + .padding(.all) + .frame(width: 140, height: 230) + .background(.white) + .cornerRadius(8) + + ZStack { + VStack { + Image("mac").padding(.all) + Text("MacBook") + .padding([.bottom]) + } + } + .padding(.all) + .frame(width: 140, height: 230) + .background(.white) + .cornerRadius(8) + + ZStack { + VStack { + Image("headphone").padding(.all) + Text("iPhone") + .padding([.bottom]) + } + } + .padding(.all) + .frame(width: 140, height: 230) + .background(.white) + .cornerRadius(8) + + + } + }.padding([.top, .leading, .bottom]) + CustomButton(action: { + + }, label: "More") + .padding(.bottom) + + } + + .frame(maxWidth: .infinity, minHeight:450, maxHeight: 450) + .background( + LinearGradient(gradient: Gradient(colors: [Color(red: 124/255, green: 90/255, blue: 208/255, opacity: 0.85), Color(red: 136/255, green: 246/255, blue: 250/255, opacity: 0.63)]), startPoint: .top, endPoint: .bottom)) + .padding(.top) + } + .modifier(NavBar(Image("logo"))) + + } + +} + +#Preview { + NavigationWrapperView(coordinator: Coordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .home)) +} diff --git a/example/BitsBytes/UI/Screens/Tabs/PorfileScreenView.swift b/example/BitsBytes/UI/Screens/Tabs/PorfileScreenView.swift new file mode 100644 index 00000000..1c94ed50 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Tabs/PorfileScreenView.swift @@ -0,0 +1,197 @@ +// +// PorfileScreenView.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +struct PorfileScreenView: View { + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + @ObservedObject var viewModel: ProfileViewModel + + var body: some View { + if currentCordinator.parent.isLoggedIn { + LoggedIn() + .modifier(NavBar(Text("MY PROFILE").bold())) + .environment(viewModel) + } else { + NotLoggedView() + .modifier(NavBar(Text("SIGN IN").bold())) + .environment(viewModel) + } + } +} + +struct LoggedIn: View { + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + @Environment(AppCoordinator.self) var appCordinator: AppCoordinator + + @Environment(ProfileViewModel.self) var viewModel: ProfileViewModel + + var body: some View { + ScrollView { + ZStack { + Spacer() + .frame(maxWidth: .infinity, maxHeight: 85) + .background( + LinearGradient(gradient: Gradient(colors: [Color(red: 245/255, green: 126/255, blue: 164/255), Color(red: 124/255, green: 90/255, blue: 208/255), Color(red: 103/255, green: 100/255, blue: 225/255)]), startPoint: .top, endPoint: .bottom) + ) + AsyncImage(url: URL(string: viewModel.image)) { phase in + if let image = phase.image { + image + .resizable() + .scaledToFill() + .background(.white) + .border(.white, width: 2) + .frame(width: 100, height: 100) + .clipShape(Circle()) + .offset(y: 40) + } else if phase.error != nil { + ZStack { + Rectangle() + .fill(Color(red: 223/255, green: 227/255, blue: 231/255)) + .clipShape(Circle()) + Text(viewModel.name.prefix(1)) + .foregroundColor(.white) + .font(.system(size: 50)) + .bold() + } + .frame(width: 100, height: 100) + .offset(y: 40) + } else { + // Acts as a placeholder. + ZStack { + Rectangle() + .fill(Color(red: 223/255, green: 227/255, blue: 231/255)) + .clipShape(Circle()) + Text(viewModel.name.prefix(0)) + .foregroundColor(.white) + .font(.system(size: 50)) + .bold() + } + .frame(width: 100, height: 100) + .offset(y: 40) + + + + } + } + + } + .frame(maxWidth: .infinity, minHeight: 170, alignment: .top) + .background(.white) + + VStack { + Text("Welcome") + .font(.system(size: 14)) + .foregroundStyle(.gray) + Text(viewModel.name) + .foregroundStyle(.black) + .font(.system(size: 36)) + } + .frame(maxWidth: .infinity, minHeight: 100) + .background(.white) + .padding(EdgeInsets(top: -10, leading: 0, bottom: 0, trailing: 0)) + + VStack(spacing: 0) { + CustomRow(label: "About Me", icon: "aboutme", showRightIcon: true) { + if appCordinator.webViewMode { + viewModel.loginWebView(screen: .profile) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } else { + currentCordinator.routing.push(.aboutme) + } + } + .padding(.zero) + CustomRow(label: "Change Password", icon: "changepassword", showRightIcon: true) { + + if appCordinator.webViewMode { + viewModel.loginWebView(screen: .profile, startScreen: .changePassword) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } else { + currentCordinator.routing.push(.changePass) + } + } + Spacer() + CustomRow(label: "Login Options", icon: "passwordless", showRightIcon: false) { + currentCordinator.routing.push(.passwordless) + } + Spacer() + CustomRow(label: "Add Phone", icon: "phone", showRightIcon: false) { + currentCordinator.routing.push(.addPhone) + } + Spacer() + CustomRow(label: "Logout", icon: "logout", showRightIcon: false) { + viewModel.logout { + currentCordinator.parent.isLoggedIn = false + } + } + .accessibilityId(self, "logoutButton") + + } + + } + .background(Color(red: 245/255, green: 246/255, blue: 247/255)) + } +} + +struct NotLoggedView: View { + @Environment(ProfileCoordinator.self) var currentCordinator: ProfileCoordinator + @Environment(AppCoordinator.self) var appCordinator: AppCoordinator + + @Environment(ProfileViewModel.self) var viewModel: ProfileViewModel + + var body: some View { + VStack { + Text("Welcome!") + .bold() + .font(.system(size: 32)) + Text("Manage your profile") + .font(.system(size: 14)) + .foregroundStyle(.gray) + + CustomButton(action: { + if appCordinator.webViewMode { + viewModel.loginWebView(screen: .login) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } else { + currentCordinator.routing.push(.signin) + } + }, label: "Sign in") + .accessibilityIdentifier("Profile_signinButton") + + CustomDarkButton(action: { + if appCordinator.webViewMode { + viewModel.loginWebView(screen: .login, startScreen: .register) { + currentCordinator.routing.popToRoot() + currentCordinator.parent.isLoggedIn = true + } + } else { + currentCordinator.routing.push(.register) + } + }, label: "Register") + .accessibilityIdentifier("Profile_registerButton") + + } + } +} + +#Preview { + Group { + let currentCordinator: ProfileCoordinator = ProfileCoordinator(parent: AppCoordinator(), routing: RoutingManager(), id: .profile) + + let viewModel: ProfileViewModel = ProfileViewModel(gigya: GigyaService()) + + LoggedIn() + .environment(currentCordinator) + .environment(viewModel) + } +} diff --git a/example/BitsBytes/UI/Screens/Tabs/SearchScreenView.swift b/example/BitsBytes/UI/Screens/Tabs/SearchScreenView.swift new file mode 100644 index 00000000..2ba92d84 --- /dev/null +++ b/example/BitsBytes/UI/Screens/Tabs/SearchScreenView.swift @@ -0,0 +1,24 @@ +// +// SearchScreenView.swift +// +// +// Created by Sagi Shmuel on 23/01/2024. +// + +import SwiftUI + +struct SearchScreenView: View { + @State var coordinator: Coordinator + + var body: some View { + VStack { + + } + .modifier(NavBar(Text("Search"))) + .environment(coordinator) + } +} + +#Preview { + SearchScreenView(coordinator: Coordinator(parent: AppCoordinator(), routing: RoutingManager(), id: Screens.search)) +} diff --git a/example/BitsBytes/UI/Screens/TestScreenView.swift b/example/BitsBytes/UI/Screens/TestScreenView.swift new file mode 100644 index 00000000..be64201c --- /dev/null +++ b/example/BitsBytes/UI/Screens/TestScreenView.swift @@ -0,0 +1,18 @@ +// +// TestScreenView.swift +// +// +// Created by Sagi Shmuel on 06/02/2024. +// + +import SwiftUI + +struct TestScreenView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + TestScreenView() +} diff --git a/example/BitsBytes/UI/ViewModels/AboutMeViewModel.swift b/example/BitsBytes/UI/ViewModels/AboutMeViewModel.swift new file mode 100644 index 00000000..5f6077cf --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/AboutMeViewModel.swift @@ -0,0 +1,102 @@ +// +// AboutMeViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 17/04/2024. +// + +import Foundation +import Gigya + +final class AboutMeViewModel: BaseViewModel { + @Published var lastName: String = "" + @Published var firstName: String = "" + @Published var email: String = "" + @Published var phone: String = "" + @Published var birthDay: Date = Date.init(timeIntervalSince1970: 0) { + didSet { + self.birthDatyIsUpdated = true + } + } + @Published var country: String = "" + + @Published var error: String = "" + + var birthDatyIsUpdated: Bool = false + + + var account: AccountModel? + + override init(gigya: GigyaService) { + super.init(gigya: gigya) + + getAccount() + } + + func getAccount() { + gigya?.shared.getAccount(){ result in + switch result { + case .success(data: let data): + self.lastName = data.profile?.lastName ?? "" + self.firstName = data.profile?.firstName ?? "" + self.email = data.profile?.email ?? "" + self.phone = data.phoneNumber ?? "" + self.country = data.profile?.country ?? "" + self.account = data + + if let birthDay = data.profile?.birthDay, + let birthMonth = data.profile?.birthMonth, + let birthYear = data.profile?.birthYear { + var dateComponents = DateComponents() + dateComponents.year = birthYear + dateComponents.month = birthMonth + dateComponents.day = birthDay + + self.birthDay = Calendar.current.date(from: dateComponents)! + } + case .failure(_): + break + } + } + } + + func setAccount() { + guard var account = account else { return } + + if birthDatyIsUpdated { + let calendar = Calendar.current + let year = calendar.component(.year, from: birthDay) + let month = calendar.component(.month, from: birthDay) + let day = calendar.component(.day, from: birthDay) + + account.profile?.birthDay = day + account.profile?.birthMonth = month + account.profile?.birthYear = year + } + + account.profile?.firstName = firstName + account.profile?.lastName = lastName + account.profile?.country = country + + toggelLoader() + + gigya?.shared.setAccount(with: account) { [weak self] result in + guard let self = self else { return } + + switch result { + case .success(data: let data): + self.toggelLoader() + self.account = data + case .failure(let error): + switch error { + case .gigyaError(data: let data): + self.error = data.errorMessage ?? error.localizedDescription + default: + self.error = error.localizedDescription + } + self.toggelLoader() + } + } + } + +} diff --git a/example/BitsBytes/UI/ViewModels/BaseViewModel.swift b/example/BitsBytes/UI/ViewModels/BaseViewModel.swift new file mode 100644 index 00000000..2ec8cf3c --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/BaseViewModel.swift @@ -0,0 +1,16 @@ +// +// BaseVideModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 20/06/2024. +// + +import Foundation + +class BaseViewModel: LoaderExtendModel , ObservableObject { + let gigya: GigyaService? + + init(gigya: GigyaService) { + self.gigya = gigya + } +} diff --git a/example/BitsBytes/UI/ViewModels/ChangePasswordViewModel.swift b/example/BitsBytes/UI/ViewModels/ChangePasswordViewModel.swift new file mode 100644 index 00000000..f5606552 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/ChangePasswordViewModel.swift @@ -0,0 +1,46 @@ +// +// ChangePasswordViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 20/06/2024. +// + +import Foundation + +class ChangePasswordViewModel: BaseViewModel { + @Published var error: String = "" + + @Published var currentPass: String = "" + @Published var newPass: String = "" + @Published var confirmPass: String = "" + + func savePassword(sucess: @escaping ()-> Void) { + if currentPass.isEmpty { + error = "Current Password is empty" + return + } else if !newPass.isEmpty && !confirmPass.isEmpty && newPass != confirmPass { + error = "Password not match" + return + } + + toggelLoader() + + gigya?.shared.setAccount(with: ["password": currentPass, "newPassword": newPass]) { [weak self] res in + switch res { + case .success(_): + sucess() + case .failure(let error): + switch error { + + case .gigyaError(data: let data): + self?.error = data.errorMessage ?? error.localizedDescription + default: + self?.error = error.localizedDescription + } + } + + self?.toggelLoader() + } + } + +} diff --git a/example/BitsBytes/UI/ViewModels/ConfigurationViewModel.swift b/example/BitsBytes/UI/ViewModels/ConfigurationViewModel.swift new file mode 100644 index 00000000..d47c857d --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/ConfigurationViewModel.swift @@ -0,0 +1,31 @@ +// +// ConfigurationViewModel.swift +// +// +// Created by Sagi Shmuel on 05/02/2024. +// + +import Foundation + +final class ConfigurationViewModel: BaseViewModel { + @Published var domain: String = "" + @Published var apiKey: String = "" + @Published var cname: String = "" + + override init(gigya: GigyaService) { + super.init(gigya: gigya) + + self.domain = gigya.shared.config.apiDomain + self.apiKey = gigya.shared.config.apiKey ?? "" + self.cname = gigya.shared.config.cname ?? "" + } + + func reInitGigya() { + showLoder.toggle() + gigya?.shared.initFor(apiKey: self.apiKey, apiDomain: self.domain, cname: self.cname) + showLoder.toggle() + } + + +} + diff --git a/example/BitsBytes/UI/ViewModels/Interruptions/LinkAccountViewModel.swift b/example/BitsBytes/UI/ViewModels/Interruptions/LinkAccountViewModel.swift new file mode 100644 index 00000000..32313809 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/Interruptions/LinkAccountViewModel.swift @@ -0,0 +1,55 @@ +// +// LinkAccountViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 21/07/2024. +// + +import Foundation +import Gigya + +final class LinkAccountViewModel: BaseViewModel { + @Published var email: String = "" + @Published var pass: String = "" + @Published var error: String = "" + @Published var formIsSubmitState: Bool = false + + var tempClosure: ()-> Void = { } + + let flowManager: SignInInterruptionFlow + + init(gigya: GigyaService, flowManager: SignInInterruptionFlow) { + self.flowManager = flowManager + super.init(gigya: gigya) + + self.email = flowManager.linkAccountResolver?.conflictingAccount?.loginID ?? "" + } + + func linkToSocial(provider: String, clousre: @escaping () -> Void) { + guard let presentingViewController = (UIApplication.shared.connectedScenes.first + as? UIWindowScene)?.windows.first?.rootViewController + else { return } + + guard let provider = GigyaSocialProviders(rawValue: provider) else { return } + + flowManager.successClousre = { [weak self] in + self?.toggelLoader() + clousre() + } + + toggelLoader() + + flowManager.linkAccountResolver?.linkToSocial(provider: provider, viewController: presentingViewController) + } + + func linkToSite(clousre: @escaping () -> Void) { + flowManager.successClousre = { [weak self] in + self?.toggelLoader() + clousre() + } + + toggelLoader() + + flowManager.linkAccountResolver?.linkToSite(loginId: email, password: pass) + } +} diff --git a/example/BitsBytes/UI/ViewModels/Interruptions/PenddingRegistrationViewModel.swift b/example/BitsBytes/UI/ViewModels/Interruptions/PenddingRegistrationViewModel.swift new file mode 100644 index 00000000..5dff8508 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/Interruptions/PenddingRegistrationViewModel.swift @@ -0,0 +1,52 @@ +// +// PenddingRegistrationViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 23/07/2024. +// + +import Foundation +import Gigya + +final class PenddingRegistrationViewModel: BaseViewModel { + @Published var birthDay: Date = Date.init(timeIntervalSince1970: 0) { + didSet { + self.birthDatyIsUpdated = true + } + } + @Published var formIsSubmitState: Bool = false + @Published var error: String = "" + + var birthDatyIsUpdated: Bool = false + + var tempClosure: ()-> Void = { } + + let flowManager: SignInInterruptionFlow + + init(gigya: GigyaService, flowManager: SignInInterruptionFlow) { + self.flowManager = flowManager + super.init(gigya: gigya) + } + + func setAccount(clousre: @escaping () -> Void) { + flowManager.successClousre = { [weak self] in + self?.toggelLoader() + clousre() + } + + toggelLoader() + + if birthDatyIsUpdated { + let calendar = Calendar.current + let year = calendar.component(.year, from: birthDay) + let month = calendar.component(.month, from: birthDay) + let day = calendar.component(.day, from: birthDay) + + flowManager.penddingRegistrationResolver?.setAccount(params: ["profile":["birthMonth": month, "birthYear": year, "birthDay": day]]) + } else { + error = "Please choose Birthday" + toggelLoader() + } + + } +} diff --git a/example/BitsBytes/UI/ViewModels/OtpViewModel.swift b/example/BitsBytes/UI/ViewModels/OtpViewModel.swift new file mode 100644 index 00000000..6de3883b --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/OtpViewModel.swift @@ -0,0 +1,80 @@ +// +// OtpViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 10/06/2024. +// +import Gigya +import GigyaAuth + +class OtpViewModel: BaseViewModel, InterruptionFlow { + + @Published var error: String = "" + @Published var phone: String = "" + @Published var code: String = "" + @Published var codeSent: Bool = false + + var flowManager: SignInInterruptionFlow + + enum Mode { + case login + case update + } + + init(gigya: GigyaService, flowManager: SignInInterruptionFlow) { + self.flowManager = flowManager + super.init(gigya: gigya) + } + + func sendCode(mode: Mode = .login, sucess: @escaping ()-> Void) { + if phone.isEmpty { + error = "Phone is empty" + return + } + + flowManager.successClousre = { [weak self] in + self?.toggelLoader() + sucess() + } + + flowManager.errorClousre = { [weak self] error in + self?.error = error + } + + switch mode { + case .login: + GigyaAuth.shared.otp.login(phone: phone, completion: flowManager.resultOtpClosure) + case .update: + GigyaAuth.shared.otp.update(phone: phone, completion: flowManager.resultOtpClosure) + } + + codeSent = true + +// { [weak self] (result: GigyaOtpResult) in +// switch result { +// case .success(data: _): +// sucess() +// case .pendingOtpVerification(resolver: let resolver): +// self?.codeSent = true +// self?.otpResolver = resolver +// case .failure(error: let error): +// print(error.error) +// self?.error = error.error.localizedDescription +// } +// +// self?.toggelLoader() +// } + } + + func verifyCode() { + guard let otpResolver = self.flowManager.otpResolver else { + self.error = "Resolver not found" + self.codeSent = false + return + } + + toggelLoader() + + otpResolver.verify(code: code) + } +} diff --git a/example/BitsBytes/UI/ViewModels/PasswordlessViewModel.swift b/example/BitsBytes/UI/ViewModels/PasswordlessViewModel.swift new file mode 100644 index 00000000..48ee3157 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/PasswordlessViewModel.swift @@ -0,0 +1,103 @@ +// +// PasswordlessViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 29/05/2024. +// + +import Foundation +import UIKit + +final class PasswordlessViewModel: BaseViewModel { + @Published var fidoIsAvailable: Bool = false + @Published var biometricAvailable: Bool = false + @Published var error: String = "" + + override init(gigya: GigyaService) { + super.init(gigya: gigya) + + checkFidoState() + + biometricAvailable = gigya.shared.biometric.isOptIn + } + + // MARK: - Fido + + func checkFidoState() { + Task { [weak self ] in + do { + let account = try await self?.gigya?.shared.getAccount() + let isAvailable = self?.gigya?.shared.webAuthn.passkeyForUser(uid: account?.UID) + self?.fidoIsAvailable = isAvailable ?? false + } catch (let error) { + self?.error = error.localizedDescription + } + } + } + + func useFido() { + guard let presentingViewController = (UIApplication.shared.connectedScenes.first + as? UIWindowScene)?.windows.first?.rootViewController + else { return } + + toggelLoader() + + if fidoIsAvailable { + Task { + await gigya?.shared.webAuthn.revoke() + self.checkFidoState() + print("webAuthn.revoke") + toggelLoader() + } + } else { + Task { + guard let result = await gigya?.shared.webAuthn.register(viewController: presentingViewController) else { return } + print("webAuthn.register") + + switch result { + case .success(data: _): + self.error = "" + self.checkFidoState() + case .failure(let e): + switch e { + case .gigyaError(data: let data): + self.error = data.errorMessage ?? "" + default: + break + } + } + + toggelLoader() + } + } + } + + // MARK: - Biometrics + + func biometricAction() { + toggelLoader() + + if !biometricAvailable { + gigya?.shared.biometric.optIn() { [weak self] res in + self?.biometricAvailable = self?.gigya?.shared.biometric.isOptIn ?? false + self?.toggelLoader() + } + } else { + gigya?.shared.biometric.optOut() { [weak self] res in + self?.biometricAvailable = self?.gigya?.shared.biometric.isOptIn ?? false + self?.toggelLoader() + } + } + } + + func lockSession(closure: @escaping ()-> Void) { + gigya?.shared.biometric.lockSession() { [weak self] res in + switch res { + case .success: + closure() + case .failure: + self?.error = "lock failed" + } + } + } +} diff --git a/example/BitsBytes/UI/ViewModels/ProfileViewModel.swift b/example/BitsBytes/UI/ViewModels/ProfileViewModel.swift new file mode 100644 index 00000000..5f4bf2d2 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/ProfileViewModel.swift @@ -0,0 +1,71 @@ +// +// ProfileViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 03/03/2024. +// +import UIKit +import Foundation + +@Observable +final class ProfileViewModel: BaseViewModel { + var name: String = "" + var image: String = "" + + enum Screen: String { + case login = "Default-RegistrationLogin" + case profile = "Default-ProfileUpdate" + } + + enum StartScreen: String { + case register = "gigya-register-screen" + case changePassword = "gigya-change-password-screen" + } + + override init(gigya: GigyaService) { + super.init(gigya: gigya) + + getAccount() + } + + func getAccount() { + gigya?.shared.getAccount(){ result in + switch result { + case .success(data: let data): + self.name = "\(data.profile?.firstName ?? "") \(data.profile?.lastName ?? "")" + self.image = data.profile?.photoURL ?? "logo" + case .failure(_): + break + } + } + } + + func logout(closure: @escaping ()-> Void) { + gigya?.shared.logout() { res in + closure() + } + } + + func loginWebView(screen: Screen, startScreen: StartScreen? = nil, closure: @escaping ()-> Void) { + guard let presentingViewController = (UIApplication.shared.connectedScenes.first + as? UIWindowScene)?.windows.first?.rootViewController + else { return } + + var params: [String: String] = [:] + + if let startScreen = startScreen { + params["startScreen"] = startScreen.rawValue + } + + gigya?.shared.showScreenSet(with: screen.rawValue, viewController: presentingViewController, params: params) { event in + switch event { + + case .onLogin(_): + closure() + default: + break + } + } + } + +} diff --git a/example/BitsBytes/UI/ViewModels/RegisterViewModel.swift b/example/BitsBytes/UI/ViewModels/RegisterViewModel.swift new file mode 100644 index 00000000..b620a3be --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/RegisterViewModel.swift @@ -0,0 +1,72 @@ +// +// RegisterViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 26/02/2024. +// + +import Foundation +import Gigya + +protocol InterruptionFlow { + var flowManager: SignInInterruptionFlow { get set } +} + +final class RegisterViewModel: BaseViewModel, InterruptionFlow { + @Published var formIsSubmitState: Bool = false + @Published var firstName: String = "" + @Published var lastName: String = "" + @Published var email: String = "" + @Published var pass: String = "" + @Published var confirmPass: String = "" + @Published var error: String = "" + + var flowManager: SignInInterruptionFlow + + init(gigya: GigyaService, flowManager: SignInInterruptionFlow) { + self.flowManager = flowManager + super.init(gigya: gigya) + } + + func submit(closure: @escaping ()-> Void) { + formIsSubmitState = true + showLoder = true + if !pass.isEmpty && !confirmPass.isEmpty && pass != confirmPass { + self.error = "Password not match." + self.toggelLoader() + return + } else if (!firstName.isEmpty && !email.isEmpty && !pass.isEmpty && !confirmPass.isEmpty) { + guard let gigya = gigya else { + self.error = "Genral error" + self.toggelLoader() + return + } + + flowManager.successClousre = { [weak self] in + self?.toggelLoader() + closure() + } + + gigya.shared.register(email: email, password: pass, params: ["profile": ["firstName": firstName, "lastName": lastName]], completion: flowManager.resultClosure) + +// { [ weak self] result in +// guard let self = self else { return } +// +// toggelLoader() +// +// switch result { +// case .success(data: _): +// closure() +// case .failure(let error): +// switch error.error { +// case .gigyaError(let data): +// self.error = data.errorMessage ?? "Genral Error" +// default: +// self.error = "Genral Error" +// } +// +// } +// } + } + } +} diff --git a/example/BitsBytes/UI/ViewModels/ResetPasswordViewModel.swift b/example/BitsBytes/UI/ViewModels/ResetPasswordViewModel.swift new file mode 100644 index 00000000..6ca022f7 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/ResetPasswordViewModel.swift @@ -0,0 +1,29 @@ +// +// ResetPasswordViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 20/06/2024. +// + +import Foundation + +class ResetPasswordViewModel: BaseViewModel { + @Published var error: String = "" + @Published var email: String = "" + @Published var resetSent: Bool = false + + func send() { + toggelLoader() + + gigya?.shared.forgotPassword(loginId: email) { [weak self] res in + switch res { + case .success(data: _): + self?.resetSent = true + case .failure(let error): + self?.error = error.localizedDescription + } + + self?.toggelLoader() + } + } +} diff --git a/example/BitsBytes/UI/ViewModels/SignInEmailViewModel.swift b/example/BitsBytes/UI/ViewModels/SignInEmailViewModel.swift new file mode 100644 index 00000000..a1574805 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/SignInEmailViewModel.swift @@ -0,0 +1,52 @@ +// +// SignInEmailViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 06/03/2024. +// + +import Foundation +import Gigya + +final class SignInEmailViewModel: BaseViewModel { + var currentCordinator: ProfileCoordinator? + + @Published var formIsSubmitState: Bool = false + @Published var email: String = "" + @Published var pass: String = "" + @Published var error: String = "" + + func submit(closure: @escaping ()-> Void) { + formIsSubmitState = true + toggelLoader() + + if (!email.isEmpty && !pass.isEmpty) { + guard let gigya = gigya else { + self.error = "Genral error" + return + } + + gigya.shared.login(loginId: email, password: pass) { [ weak self] result in + guard let self = self else { return } + + toggelLoader() + + switch result { + case .success(data: _): + closure() + case .failure(let error): + switch error.error { + case .gigyaError(let data): + self.error = data.errorMessage ?? "Genral Error" + default: + self.error = "Genral Error" + } + } + } + } + } + + func showPass() { + currentCordinator?.routing.push(.resetPassword) + } +} diff --git a/example/BitsBytes/UI/ViewModels/SignInViewModel.swift b/example/BitsBytes/UI/ViewModels/SignInViewModel.swift new file mode 100644 index 00000000..16d93787 --- /dev/null +++ b/example/BitsBytes/UI/ViewModels/SignInViewModel.swift @@ -0,0 +1,73 @@ +// +// SignInViewModel.swift +// BitsBytes +// +// Created by Sagi Shmuel on 07/03/2024. +// + +import Foundation +import Gigya + +final class SignInViewModel: BaseViewModel { + @Published var error: String = "" + @Published var biometricAvailable: Bool = false + + let flowManager: SignInInterruptionFlow + + init(gigya: GigyaService, flowManager: SignInInterruptionFlow) { + self.flowManager = flowManager + super.init(gigya: gigya) + + biometricAvailable = gigya.shared.biometric.isOptIn + + } + + func loginWithProvider(_ provider: GigyaSocialProviders, closure: @escaping ()-> Void) { + guard let presentingViewController = (UIApplication.shared.connectedScenes.first + as? UIWindowScene)?.windows.first?.rootViewController + else { return } + + flowManager.successClousre = { [weak self] in + self?.toggelLoader() + closure() + } + + toggelLoader() + + gigya?.shared.login(with: provider, viewController: presentingViewController, completion: flowManager.resultClosure) + } + + func fidoLogin() async -> Bool { + guard let presentingViewController = await (UIApplication.shared.connectedScenes.first + as? UIWindowScene)?.windows.first?.rootViewController + else { return false} + + guard let result = await gigya?.shared.webAuthn.login(viewController: presentingViewController) else { return false} + + switch result { + case .success(_): + return true + case .failure(let error): + switch error.error { + case .gigyaError(data: let data): + self.error = data.errorMessage ?? "" + + default: + break + } + return false + } + + } + + func unlockSession(closure: @escaping ()-> Void) { + gigya?.shared.biometric.unlockSession() { [weak self] res in + switch res { + case .success: + closure() + case .failure: + self?.error = "unlock failed" + } + } + } +} diff --git a/example/Launch Screen.storyboard b/example/Launch Screen.storyboard new file mode 100644 index 00000000..4781b9ae --- /dev/null +++ b/example/Launch Screen.storyboard @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/Podfile b/example/Podfile new file mode 100644 index 00000000..cffe4d31 --- /dev/null +++ b/example/Podfile @@ -0,0 +1,18 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'BitsBytes' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for BitsBytes + pod 'Gigya', + pod 'GigyaTfa' + pod 'GigyaAuth' + pod 'Firebase' + pod 'Firebase/Messaging' + pod 'FBSDKCoreKit' + pod 'FBSDKLoginKit' + pod 'GoogleSignIn' + pod 'LineSDKSwift' +end