diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..959cd66 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 9bdca8e..5708445 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ node_modules .env dist migrations -.DS_Store +Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/mortezafaraji.xcuserdatad/UserInterfaceState.xcuserstate .vscode -coverage \ No newline at end of file +**/GoogleService-Info.plist +.DS_Store +coverage diff --git a/Rethread/.DS_Store b/Rethread/.DS_Store index 6d556de..ec8e23f 100644 Binary files a/Rethread/.DS_Store and b/Rethread/.DS_Store differ diff --git a/Rethread/.gitignore b/Rethread/.gitignore new file mode 100644 index 0000000..1d62266 --- /dev/null +++ b/Rethread/.gitignore @@ -0,0 +1,91 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +Packages/ +Package.pins +Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ +GoogleService-Info.plist \ No newline at end of file diff --git a/Rethread/GoogleService-Info.plist b/Rethread/GoogleService-Info.plist new file mode 100644 index 0000000..34f2b70 --- /dev/null +++ b/Rethread/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 69711373157-smt51cs82nik0nceo6slguta9vmaip00.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.69711373157-smt51cs82nik0nceo6slguta9vmaip00 + API_KEY + AIzaSyCt95kuSORiMMuxgV7BXBI0LqhQ78E3CS0 + GCM_SENDER_ID + 69711373157 + PLIST_VERSION + 1 + BUNDLE_ID + techstart.Rethread + PROJECT_ID + rethread-6c539 + STORAGE_BUCKET + rethread-6c539.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:69711373157:ios:31a3f912661197e84ef78c + + \ No newline at end of file diff --git a/Rethread/Rethread.xcodeproj/project.pbxproj b/Rethread/Rethread.xcodeproj/project.pbxproj index f23537c..bcda19b 100644 --- a/Rethread/Rethread.xcodeproj/project.pbxproj +++ b/Rethread/Rethread.xcodeproj/project.pbxproj @@ -7,27 +7,45 @@ objects = { /* Begin PBXBuildFile section */ - 7C3A04B82B0AD9DF00E36883 /* OnboardingApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C3A04B42B0AD9DF00E36883 /* OnboardingApp.swift */; }; + 7C8446E52B58CE8F00911C00 /* MapViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C8446E42B58CE8F00911C00 /* MapViewModel.swift */; }; 983014C22B451A3E004A6A07 /* NavigationTransitions in Frameworks */ = {isa = PBXBuildFile; productRef = 983014C12B451A3E004A6A07 /* NavigationTransitions */; }; 983286B92B05698F00851B19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 983286B82B05698F00851B19 /* Assets.xcassets */; }; 983286BC2B05698F00851B19 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 983286BB2B05698F00851B19 /* Preview Assets.xcassets */; }; 983286C62B05698F00851B19 /* RethreadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983286C52B05698F00851B19 /* RethreadTests.swift */; }; 983286D02B05698F00851B19 /* RethreadUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983286CF2B05698F00851B19 /* RethreadUITests.swift */; }; 983286D22B05698F00851B19 /* RethreadUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983286D12B05698F00851B19 /* RethreadUITestsLaunchTests.swift */; }; - 9868A7D82B1FAD280063D9BA /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9868A7D72B1FAD280063D9BA /* WelcomeView.swift */; }; - 9868A7DA2B1FADA70063D9BA /* QuestionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9868A7D92B1FADA70063D9BA /* QuestionView.swift */; }; + 98434A5D2B63342700F81127 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98434A5C2B63342700F81127 /* ContentView.swift */; }; + 984674952B747FD200AFB77A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 984674942B747FD200AFB77A /* GoogleService-Info.plist */; }; + 985674F12B663E0D003FA5A0 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 985674F02B663E0D003FA5A0 /* FirebaseAuth */; }; + 985674F32B663E0D003FA5A0 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 985674F22B663E0D003FA5A0 /* FirebaseFirestore */; }; + 985674F52B663E0D003FA5A0 /* FirebaseFirestoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 985674F42B663E0D003FA5A0 /* FirebaseFirestoreSwift */; }; + 985674F72B663E0D003FA5A0 /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 985674F62B663E0D003FA5A0 /* FirebaseStorage */; }; 9868A7DE2B1FAE780063D9BA /* ButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9868A7DD2B1FAE780063D9BA /* ButtonStyles.swift */; }; - 988A0F952B3BFB4C00ACDC90 /* SignUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A0F942B3BFB4C00ACDC90 /* SignUpView.swift */; }; 988A0F992B3C112300ACDC90 /* DatePickerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A0F982B3C112300ACDC90 /* DatePickerModel.swift */; }; 9897C7732B3E6C4000EDE9D9 /* CustomDropdownMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9897C7722B3E6C4000EDE9D9 /* CustomDropdownMenu.swift */; }; - 98A183862B38273B001E324A /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A183852B38273B001E324A /* MainView.swift */; }; - 98A183882B383C0B001E324A /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A183872B383C0B001E324A /* SignInView.swift */; }; - 98A1838A2B383C47001E324A /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A183892B383C47001E324A /* VerificationView.swift */; }; 98A1838C2B38D32A001E324A /* ColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A1838B2B38D32A001E324A /* ColorPalette.swift */; }; - 98AE7AB92B1FAADB0029C2F7 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98AE7AB82B1FAADB0029C2F7 /* OnboardingView.swift */; }; + 98BBA11D2B68A6A100003AC2 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA10F2B68A6A100003AC2 /* ProfileView.swift */; }; + 98BBA11E2B68A6A100003AC2 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1102B68A6A100003AC2 /* VerificationView.swift */; }; + 98BBA11F2B68A6A100003AC2 /* ProductView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1112B68A6A100003AC2 /* ProductView.swift */; }; + 98BBA1202B68A6A100003AC2 /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1122B68A6A100003AC2 /* MapView.swift */; }; + 98BBA1212B68A6A100003AC2 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1132B68A6A100003AC2 /* HomeView.swift */; }; + 98BBA1222B68A6A100003AC2 /* testest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1142B68A6A100003AC2 /* testest.swift */; }; + 98BBA1232B68A6A100003AC2 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1152B68A6A100003AC2 /* WelcomeView.swift */; }; + 98BBA1242B68A6A100003AC2 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1162B68A6A100003AC2 /* SignInView.swift */; }; + 98BBA1252B68A6A100003AC2 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1172B68A6A100003AC2 /* SwiftUIView.swift */; }; + 98BBA1262B68A6A100003AC2 /* ClothingItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1182B68A6A100003AC2 /* ClothingItemView.swift */; }; + 98BBA1272B68A6A100003AC2 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA1192B68A6A100003AC2 /* MainView.swift */; }; + 98BBA1282B68A6A100003AC2 /* SignUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA11A2B68A6A100003AC2 /* SignUpView.swift */; }; + 98BBA1292B68A6A100003AC2 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA11B2B68A6A100003AC2 /* OnboardingView.swift */; }; + 98BBA12B2B68A75200003AC2 /* OnboardingApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA12A2B68A75200003AC2 /* OnboardingApp.swift */; }; + 98BBA12D2B68ACBF00003AC2 /* Verification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BBA12C2B68ACBF00003AC2 /* Verification.swift */; }; + 98D04FFD2B7871F200889156 /* CustomTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 98D04FFC2B7871F200889156 /* CustomTextField */; }; + 98D04FFF2B78763C00889156 /* CustomField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D04FFE2B78763C00889156 /* CustomField.swift */; }; + 98EA47352B6065C600AA2E8F /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98EA47342B6065C600AA2E8F /* User.swift */; }; 98F525C92B469BBD00CCAD78 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F525C82B469BBD00CCAD78 /* PlayerView.swift */; }; 98F525CB2B469BEB00CCAD78 /* UIPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F525CA2B469BEB00CCAD78 /* UIPlayerView.swift */; }; 98F525CE2B46A96F00CCAD78 /* TermsAndConditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F525CD2B46A96F00CCAD78 /* TermsAndConditions.swift */; }; + 98F541222B60A2CC00B6AA04 /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F541212B60A2CC00B6AA04 /* AuthViewModel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -48,7 +66,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 7C3A04B42B0AD9DF00E36883 /* OnboardingApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingApp.swift; sourceTree = ""; }; + 7C8446E42B58CE8F00911C00 /* MapViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewModel.swift; sourceTree = ""; }; 983286B12B05698E00851B19 /* Rethread.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Rethread.app; sourceTree = BUILT_PRODUCTS_DIR; }; 983286B82B05698F00851B19 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 983286BB2B05698F00851B19 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; @@ -57,20 +75,34 @@ 983286CB2B05698F00851B19 /* RethreadUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RethreadUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 983286CF2B05698F00851B19 /* RethreadUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RethreadUITests.swift; sourceTree = ""; }; 983286D12B05698F00851B19 /* RethreadUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RethreadUITestsLaunchTests.swift; sourceTree = ""; }; - 9868A7D72B1FAD280063D9BA /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; - 9868A7D92B1FADA70063D9BA /* QuestionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionView.swift; sourceTree = ""; }; + 983D40FA2B68D13E00905D4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 98434A5C2B63342700F81127 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 984674942B747FD200AFB77A /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 9868A7DD2B1FAE780063D9BA /* ButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonStyles.swift; sourceTree = ""; }; - 988A0F942B3BFB4C00ACDC90 /* SignUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpView.swift; sourceTree = ""; }; 988A0F982B3C112300ACDC90 /* DatePickerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatePickerModel.swift; sourceTree = ""; }; 9897C7722B3E6C4000EDE9D9 /* CustomDropdownMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDropdownMenu.swift; sourceTree = ""; }; - 98A183852B38273B001E324A /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; - 98A183872B383C0B001E324A /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = ""; }; - 98A183892B383C47001E324A /* VerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = ""; }; 98A1838B2B38D32A001E324A /* ColorPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPalette.swift; sourceTree = ""; }; - 98AE7AB82B1FAADB0029C2F7 /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = ""; }; + 98BBA10F2B68A6A100003AC2 /* ProfileView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; + 98BBA1102B68A6A100003AC2 /* VerificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = ""; }; + 98BBA1112B68A6A100003AC2 /* ProductView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductView.swift; sourceTree = ""; }; + 98BBA1122B68A6A100003AC2 /* MapView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; + 98BBA1132B68A6A100003AC2 /* HomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; + 98BBA1142B68A6A100003AC2 /* testest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = testest.swift; sourceTree = ""; }; + 98BBA1152B68A6A100003AC2 /* WelcomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; + 98BBA1162B68A6A100003AC2 /* SignInView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = ""; }; + 98BBA1172B68A6A100003AC2 /* SwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = ""; }; + 98BBA1182B68A6A100003AC2 /* ClothingItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClothingItemView.swift; sourceTree = ""; }; + 98BBA1192B68A6A100003AC2 /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; + 98BBA11A2B68A6A100003AC2 /* SignUpView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignUpView.swift; sourceTree = ""; }; + 98BBA11B2B68A6A100003AC2 /* OnboardingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = ""; }; + 98BBA12A2B68A75200003AC2 /* OnboardingApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingApp.swift; sourceTree = ""; }; + 98BBA12C2B68ACBF00003AC2 /* Verification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Verification.swift; sourceTree = ""; }; + 98D04FFE2B78763C00889156 /* CustomField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomField.swift; sourceTree = ""; }; + 98EA47342B6065C600AA2E8F /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 98F525C82B469BBD00CCAD78 /* PlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerView.swift; sourceTree = ""; }; 98F525CA2B469BEB00CCAD78 /* UIPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIPlayerView.swift; sourceTree = ""; }; 98F525CD2B46A96F00CCAD78 /* TermsAndConditions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsAndConditions.swift; sourceTree = ""; }; + 98F541212B60A2CC00B6AA04 /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -79,6 +111,11 @@ buildActionMask = 2147483647; files = ( 983014C22B451A3E004A6A07 /* NavigationTransitions in Frameworks */, + 98D04FFD2B7871F200889156 /* CustomTextField in Frameworks */, + 985674F12B663E0D003FA5A0 /* FirebaseAuth in Frameworks */, + 985674F32B663E0D003FA5A0 /* FirebaseFirestore in Frameworks */, + 985674F72B663E0D003FA5A0 /* FirebaseStorage in Frameworks */, + 985674F52B663E0D003FA5A0 /* FirebaseFirestoreSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -104,33 +141,36 @@ children = ( 988A0F982B3C112300ACDC90 /* DatePickerModel.swift */, 98F525CD2B46A96F00CCAD78 /* TermsAndConditions.swift */, + 7C8446E42B58CE8F00911C00 /* MapViewModel.swift */, ); path = Models; sourceTree = ""; }; - 7C9AA2D12B0EC3BC00EF6F36 /* Extensions */ = { + 7C9AA2D42B0ECADF00EF6F36 /* Styles */ = { isa = PBXGroup; children = ( + 9868A7DD2B1FAE780063D9BA /* ButtonStyles.swift */, + 98A1838B2B38D32A001E324A /* ColorPalette.swift */, ); - path = Extensions; + path = Styles; sourceTree = ""; }; - 7C9AA2D42B0ECADF00EF6F36 /* Styles */ = { + 980DACBB2B71E7110008B88A /* Extensions */ = { isa = PBXGroup; children = ( - 9868A7DD2B1FAE780063D9BA /* ButtonStyles.swift */, - 98A1838B2B38D32A001E324A /* ColorPalette.swift */, ); - path = Styles; + path = Extensions; sourceTree = ""; }; 983286A82B05698E00851B19 = { isa = PBXGroup; children = ( 983286B32B05698E00851B19 /* Rethread */, + 984674942B747FD200AFB77A /* GoogleService-Info.plist */, 983286C42B05698F00851B19 /* RethreadTests */, 983286CE2B05698F00851B19 /* RethreadUITests */, 983286B22B05698E00851B19 /* Products */, + 98BBA10C2B68A51A00003AC2 /* Recovered References */, ); sourceTree = ""; }; @@ -147,19 +187,15 @@ 983286B32B05698E00851B19 /* Rethread */ = { isa = PBXGroup; children = ( - 7C9AA2D12B0EC3BC00EF6F36 /* Extensions */, + 983D40FA2B68D13E00905D4E /* Info.plist */, 7C9AA2D42B0ECADF00EF6F36 /* Styles */, + 980DACBB2B71E7110008B88A /* Extensions */, 9897C7712B3E6BF600EDE9D9 /* Components */, 98F525CC2B46A8E900CCAD78 /* VideoPlayer */, 7C9AA2CC2B0EC02600EF6F36 /* Models */, + 98EA47332B6065A500AA2E8F /* UserAuthentication */, + 98BBA10D2B68A6A100003AC2 /* Views */, 98EA47322B605E5200AA2E8F /* Core */, - 98AE7AB82B1FAADB0029C2F7 /* OnboardingView.swift */, - 98A183852B38273B001E324A /* MainView.swift */, - 98A183872B383C0B001E324A /* SignInView.swift */, - 988A0F942B3BFB4C00ACDC90 /* SignUpView.swift */, - 98A183892B383C47001E324A /* VerificationView.swift */, - 9868A7D92B1FADA70063D9BA /* QuestionView.swift */, - 9868A7D72B1FAD280063D9BA /* WelcomeView.swift */, 983286B82B05698F00851B19 /* Assets.xcassets */, 983286BA2B05698F00851B19 /* Preview Content */, ); @@ -194,19 +230,58 @@ 9897C7712B3E6BF600EDE9D9 /* Components */ = { isa = PBXGroup; children = ( + 98BBA12C2B68ACBF00003AC2 /* Verification.swift */, 9897C7722B3E6C4000EDE9D9 /* CustomDropdownMenu.swift */, + 98D04FFE2B78763C00889156 /* CustomField.swift */, ); path = Components; sourceTree = ""; }; + 98BBA10C2B68A51A00003AC2 /* Recovered References */ = { + isa = PBXGroup; + children = ( + ); + name = "Recovered References"; + sourceTree = ""; + }; + 98BBA10D2B68A6A100003AC2 /* Views */ = { + isa = PBXGroup; + children = ( + 98BBA10F2B68A6A100003AC2 /* ProfileView.swift */, + 98BBA1102B68A6A100003AC2 /* VerificationView.swift */, + 98BBA1112B68A6A100003AC2 /* ProductView.swift */, + 98BBA1122B68A6A100003AC2 /* MapView.swift */, + 98BBA1132B68A6A100003AC2 /* HomeView.swift */, + 98BBA1142B68A6A100003AC2 /* testest.swift */, + 98BBA1152B68A6A100003AC2 /* WelcomeView.swift */, + 98BBA1162B68A6A100003AC2 /* SignInView.swift */, + 98BBA1172B68A6A100003AC2 /* SwiftUIView.swift */, + 98BBA1182B68A6A100003AC2 /* ClothingItemView.swift */, + 98BBA1192B68A6A100003AC2 /* MainView.swift */, + 98BBA11A2B68A6A100003AC2 /* SignUpView.swift */, + 98BBA11B2B68A6A100003AC2 /* OnboardingView.swift */, + ); + path = Views; + sourceTree = ""; + }; 98EA47322B605E5200AA2E8F /* Core */ = { isa = PBXGroup; children = ( - 7C3A04B42B0AD9DF00E36883 /* OnboardingApp.swift */, + 98BBA12A2B68A75200003AC2 /* OnboardingApp.swift */, + 98434A5C2B63342700F81127 /* ContentView.swift */, ); path = Core; sourceTree = ""; }; + 98EA47332B6065A500AA2E8F /* UserAuthentication */ = { + isa = PBXGroup; + children = ( + 98F541212B60A2CC00B6AA04 /* AuthViewModel.swift */, + 98EA47342B6065C600AA2E8F /* User.swift */, + ); + path = UserAuthentication; + sourceTree = ""; + }; 98F525CC2B46A8E900CCAD78 /* VideoPlayer */ = { isa = PBXGroup; children = ( @@ -234,6 +309,11 @@ name = Rethread; packageProductDependencies = ( 983014C12B451A3E004A6A07 /* NavigationTransitions */, + 985674F02B663E0D003FA5A0 /* FirebaseAuth */, + 985674F22B663E0D003FA5A0 /* FirebaseFirestore */, + 985674F42B663E0D003FA5A0 /* FirebaseFirestoreSwift */, + 985674F62B663E0D003FA5A0 /* FirebaseStorage */, + 98D04FFC2B7871F200889156 /* CustomTextField */, ); productName = Rethread; productReference = 983286B12B05698E00851B19 /* Rethread.app */; @@ -310,6 +390,8 @@ mainGroup = 983286A82B05698E00851B19; packageReferences = ( 983014C02B451A3E004A6A07 /* XCRemoteSwiftPackageReference "swiftui-navigation-transitions" */, + 985674EF2B663E0D003FA5A0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + 98D04FFB2B7871F200889156 /* XCRemoteSwiftPackageReference "SwiftUI-Custom-TextField" */, ); productRefGroup = 983286B22B05698E00851B19 /* Products */; projectDirPath = ""; @@ -328,6 +410,7 @@ buildActionMask = 2147483647; files = ( 983286BC2B05698F00851B19 /* Preview Assets.xcassets in Resources */, + 984674952B747FD200AFB77A /* GoogleService-Info.plist in Resources */, 983286B92B05698F00851B19 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -353,21 +436,33 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9868A7DA2B1FADA70063D9BA /* QuestionView.swift in Sources */, - 7C3A04B82B0AD9DF00E36883 /* OnboardingApp.swift in Sources */, + 98BBA1292B68A6A100003AC2 /* OnboardingView.swift in Sources */, + 98BBA1222B68A6A100003AC2 /* testest.swift in Sources */, + 98BBA1262B68A6A100003AC2 /* ClothingItemView.swift in Sources */, 9868A7DE2B1FAE780063D9BA /* ButtonStyles.swift in Sources */, - 98AE7AB92B1FAADB0029C2F7 /* OnboardingView.swift in Sources */, - 988A0F952B3BFB4C00ACDC90 /* SignUpView.swift in Sources */, + 98EA47352B6065C600AA2E8F /* User.swift in Sources */, + 98BBA12D2B68ACBF00003AC2 /* Verification.swift in Sources */, 98A1838C2B38D32A001E324A /* ColorPalette.swift in Sources */, + 98BBA12B2B68A75200003AC2 /* OnboardingApp.swift in Sources */, + 98BBA1242B68A6A100003AC2 /* SignInView.swift in Sources */, + 98F541222B60A2CC00B6AA04 /* AuthViewModel.swift in Sources */, 98F525CE2B46A96F00CCAD78 /* TermsAndConditions.swift in Sources */, - 98A183862B38273B001E324A /* MainView.swift in Sources */, 98F525C92B469BBD00CCAD78 /* PlayerView.swift in Sources */, - 98A1838A2B383C47001E324A /* VerificationView.swift in Sources */, 98F525CB2B469BEB00CCAD78 /* UIPlayerView.swift in Sources */, - 98A183882B383C0B001E324A /* SignInView.swift in Sources */, + 98BBA1232B68A6A100003AC2 /* WelcomeView.swift in Sources */, + 98BBA11D2B68A6A100003AC2 /* ProfileView.swift in Sources */, + 98434A5D2B63342700F81127 /* ContentView.swift in Sources */, 988A0F992B3C112300ACDC90 /* DatePickerModel.swift in Sources */, 9897C7732B3E6C4000EDE9D9 /* CustomDropdownMenu.swift in Sources */, - 9868A7D82B1FAD280063D9BA /* WelcomeView.swift in Sources */, + 98BBA1272B68A6A100003AC2 /* MainView.swift in Sources */, + 98BBA1212B68A6A100003AC2 /* HomeView.swift in Sources */, + 98BBA1252B68A6A100003AC2 /* SwiftUIView.swift in Sources */, + 98BBA11E2B68A6A100003AC2 /* VerificationView.swift in Sources */, + 98D04FFF2B78763C00889156 /* CustomField.swift in Sources */, + 98BBA11F2B68A6A100003AC2 /* ProductView.swift in Sources */, + 98BBA1282B68A6A100003AC2 /* SignUpView.swift in Sources */, + 98BBA1202B68A6A100003AC2 /* MapView.swift in Sources */, + 7C8446E52B58CE8F00911C00 /* MapViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -535,18 +630,20 @@ DEVELOPMENT_TEAM = 4GW9NWA7H9; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Rethread/Info.plist; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Rethread needs your location"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = techstart.Rethread; + PRODUCT_BUNDLE_IDENTIFIER = techstart.Rethread2; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -567,18 +664,20 @@ DEVELOPMENT_TEAM = 4GW9NWA7H9; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Rethread/Info.plist; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Rethread needs your location"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = techstart.Rethread; + PRODUCT_BUNDLE_IDENTIFIER = techstart.Rethread2; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -708,6 +807,22 @@ minimumVersion = 0.13.3; }; }; + 985674EF2B663E0D003FA5A0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 10.20.0; + }; + }; + 98D04FFB2B7871F200889156 /* XCRemoteSwiftPackageReference "SwiftUI-Custom-TextField" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/esatgozcu/SwiftUI-Custom-TextField"; + requirement = { + branch = main; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -716,6 +831,31 @@ package = 983014C02B451A3E004A6A07 /* XCRemoteSwiftPackageReference "swiftui-navigation-transitions" */; productName = NavigationTransitions; }; + 985674F02B663E0D003FA5A0 /* FirebaseAuth */ = { + isa = XCSwiftPackageProductDependency; + package = 985674EF2B663E0D003FA5A0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; + }; + 985674F22B663E0D003FA5A0 /* FirebaseFirestore */ = { + isa = XCSwiftPackageProductDependency; + package = 985674EF2B663E0D003FA5A0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestore; + }; + 985674F42B663E0D003FA5A0 /* FirebaseFirestoreSwift */ = { + isa = XCSwiftPackageProductDependency; + package = 985674EF2B663E0D003FA5A0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestoreSwift; + }; + 985674F62B663E0D003FA5A0 /* FirebaseStorage */ = { + isa = XCSwiftPackageProductDependency; + package = 985674EF2B663E0D003FA5A0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseStorage; + }; + 98D04FFC2B7871F200889156 /* CustomTextField */ = { + isa = XCSwiftPackageProductDependency; + package = 98D04FFB2B7871F200889156 /* XCRemoteSwiftPackageReference "SwiftUI-Custom-TextField" */; + productName = CustomTextField; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 983286A92B05698E00851B19 /* Project object */; diff --git a/Rethread/Rethread.xcodeproj/xcuserdata/parsakargari.xcuserdatad/xcschemes/xcschememanagement.plist b/Rethread/Rethread.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 50% rename from Rethread/Rethread.xcodeproj/xcuserdata/parsakargari.xcuserdatad/xcschemes/xcschememanagement.plist rename to Rethread/Rethread.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index c636354..0c67376 100644 --- a/Rethread/Rethread.xcodeproj/xcuserdata/parsakargari.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Rethread/Rethread.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -1,14 +1,5 @@ - - SchemeUserState - - Rethread.xcscheme_^#shared#^_ - - orderHint - 0 - - - + diff --git a/Rethread/Rethread.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Rethread/Rethread.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 81d08fe..0000000 --- a/Rethread/Rethread.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,23 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swiftui-introspect", - "kind" : "remoteSourceControl", - "location" : "https://github.com/siteline/swiftui-introspect", - "state" : { - "revision" : "9e1cc02a65b22e09a8251261cccbccce02731fc5", - "version" : "1.1.1" - } - }, - { - "identity" : "swiftui-navigation-transitions", - "kind" : "remoteSourceControl", - "location" : "https://github.com/davdroman/swiftui-navigation-transitions.git", - "state" : { - "revision" : "a6a3c70ad5d771bd1e927fb55897231cd9592024", - "version" : "0.13.3" - } - } - ], - "version" : 2 -} diff --git a/Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/mortezafaraji.xcuserdatad/UserInterfaceState.xcuserstate b/Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/mortezafaraji.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index b5e369f..0000000 Binary files a/Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/mortezafaraji.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/parsakargari.xcuserdatad/UserInterfaceState.xcuserstate b/Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/parsakargari.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index d7ee170..0000000 Binary files a/Rethread/Rethread.xcodeproj/project.xcworkspace/xcuserdata/parsakargari.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Rethread/Rethread.xcodeproj/xcuserdata/mortezafaraji.xcuserdatad/xcschemes/xcschememanagement.plist b/Rethread/Rethread.xcodeproj/xcuserdata/mortezafaraji.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index c636354..0000000 --- a/Rethread/Rethread.xcodeproj/xcuserdata/mortezafaraji.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - Rethread.xcscheme_^#shared#^_ - - orderHint - 0 - - - - diff --git a/Rethread/Rethread.xcodeproj/xcuserdata/parsakargari.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Rethread/Rethread.xcodeproj/xcuserdata/parsakargari.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index a9d4ab5..0000000 --- a/Rethread/Rethread.xcodeproj/xcuserdata/parsakargari.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/Rethread/Rethread/.DS_Store b/Rethread/Rethread/.DS_Store index 71e5808..eb14a59 100644 Binary files a/Rethread/Rethread/.DS_Store and b/Rethread/Rethread/.DS_Store differ diff --git a/Rethread/Rethread/Assets.xcassets/.DS_Store b/Rethread/Rethread/Assets.xcassets/.DS_Store new file mode 100644 index 0000000..6ddd850 Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/.DS_Store differ diff --git a/Rethread/Rethread/Assets.xcassets/appleLogo.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/appleLogo.imageset/Contents.json new file mode 100644 index 0000000..a33044f --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/appleLogo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "appleLogo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/appleLogo.imageset/appleLogo.png b/Rethread/Rethread/Assets.xcassets/appleLogo.imageset/appleLogo.png new file mode 100644 index 0000000..263562e Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/appleLogo.imageset/appleLogo.png differ diff --git a/Rethread/Rethread/Assets.xcassets/brandCard_1.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/brandCard_1.imageset/Contents.json new file mode 100644 index 0000000..07bc69b --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/brandCard_1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "patagonia.jpeg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/brandCard_1.imageset/patagonia.jpeg b/Rethread/Rethread/Assets.xcassets/brandCard_1.imageset/patagonia.jpeg new file mode 100644 index 0000000..a202c7a Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/brandCard_1.imageset/patagonia.jpeg differ diff --git a/Rethread/Rethread/Assets.xcassets/brandCard_2.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/brandCard_2.imageset/Contents.json new file mode 100644 index 0000000..848f235 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/brandCard_2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "tentree_Logo.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/brandCard_2.imageset/tentree_Logo.jpg b/Rethread/Rethread/Assets.xcassets/brandCard_2.imageset/tentree_Logo.jpg new file mode 100644 index 0000000..019c071 Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/brandCard_2.imageset/tentree_Logo.jpg differ diff --git a/Rethread/Rethread/Assets.xcassets/brandCard_3.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/brandCard_3.imageset/Contents.json new file mode 100644 index 0000000..979e884 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/brandCard_3.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Pact_Logo_Grey_ID_Logo.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/brandCard_3.imageset/Pact_Logo_Grey_ID_Logo.jpg b/Rethread/Rethread/Assets.xcassets/brandCard_3.imageset/Pact_Logo_Grey_ID_Logo.jpg new file mode 100644 index 0000000..d9a08cf Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/brandCard_3.imageset/Pact_Logo_Grey_ID_Logo.jpg differ diff --git a/Rethread/Rethread/Assets.xcassets/clothingCard_1.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/clothingCard_1.imageset/Contents.json new file mode 100644 index 0000000..3444f35 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/clothingCard_1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "download.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/clothingCard_1.imageset/download.jpg b/Rethread/Rethread/Assets.xcassets/clothingCard_1.imageset/download.jpg new file mode 100644 index 0000000..d9bf8c3 Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/clothingCard_1.imageset/download.jpg differ diff --git a/Rethread/Rethread/Assets.xcassets/flowerMainPage.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/flowerMainPage.imageset/Contents.json new file mode 100644 index 0000000..031c178 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/flowerMainPage.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Screenshot 2024-02-10 at 7.44.59 PM.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Rethread/Rethread/Assets.xcassets/flowerMainPage.imageset/Screenshot 2024-02-10 at 7.44.59\342\200\257PM.png" "b/Rethread/Rethread/Assets.xcassets/flowerMainPage.imageset/Screenshot 2024-02-10 at 7.44.59\342\200\257PM.png" new file mode 100644 index 0000000..907f632 Binary files /dev/null and "b/Rethread/Rethread/Assets.xcassets/flowerMainPage.imageset/Screenshot 2024-02-10 at 7.44.59\342\200\257PM.png" differ diff --git a/Rethread/Rethread/Assets.xcassets/googleLogo.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/googleLogo.imageset/Contents.json new file mode 100644 index 0000000..4fe01b3 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/googleLogo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "googleLogo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/googleLogo.imageset/googleLogo.png b/Rethread/Rethread/Assets.xcassets/googleLogo.imageset/googleLogo.png new file mode 100644 index 0000000..bf4722a Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/googleLogo.imageset/googleLogo.png differ diff --git a/Rethread/Rethread/Assets.xcassets/starSky.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/king.imageset/Contents.json similarity index 88% rename from Rethread/Rethread/Assets.xcassets/starSky.imageset/Contents.json rename to Rethread/Rethread/Assets.xcassets/king.imageset/Contents.json index 4aa7228..09b8b72 100644 --- a/Rethread/Rethread/Assets.xcassets/starSky.imageset/Contents.json +++ b/Rethread/Rethread/Assets.xcassets/king.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "starSky.jpg", + "filename" : "king.jpeg", "idiom" : "universal", "scale" : "1x" }, diff --git a/Rethread/Rethread/Assets.xcassets/king.imageset/king.jpeg b/Rethread/Rethread/Assets.xcassets/king.imageset/king.jpeg new file mode 100644 index 0000000..4f6bef7 Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/king.imageset/king.jpeg differ diff --git a/Rethread/Rethread/Assets.xcassets/metaLogo.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/metaLogo.imageset/Contents.json new file mode 100644 index 0000000..c749717 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/metaLogo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "metaLogo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/metaLogo.imageset/metaLogo.png b/Rethread/Rethread/Assets.xcassets/metaLogo.imageset/metaLogo.png new file mode 100644 index 0000000..84a24cc Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/metaLogo.imageset/metaLogo.png differ diff --git a/Rethread/Rethread/Assets.xcassets/starSky.imageset/starSky.jpg b/Rethread/Rethread/Assets.xcassets/starSky.imageset/starSky.jpg deleted file mode 100644 index 9a64bd5..0000000 Binary files a/Rethread/Rethread/Assets.xcassets/starSky.imageset/starSky.jpg and /dev/null differ diff --git a/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/.DS_Store b/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/.DS_Store differ diff --git a/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/Contents.json b/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/Contents.json new file mode 100644 index 0000000..594d773 --- /dev/null +++ b/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sweatshirt.jpeg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/sweatshirt.jpeg b/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/sweatshirt.jpeg new file mode 100644 index 0000000..befdd4f Binary files /dev/null and b/Rethread/Rethread/Assets.xcassets/sweatshirt.imageset/sweatshirt.jpeg differ diff --git a/Rethread/Rethread/Components/CustomDropdownMenu.swift b/Rethread/Rethread/Components/CustomDropdownMenu.swift index 6020c5f..d90a3ec 100644 --- a/Rethread/Rethread/Components/CustomDropdownMenu.swift +++ b/Rethread/Rethread/Components/CustomDropdownMenu.swift @@ -23,7 +23,7 @@ struct CustomDropdownMenu: View { } .padding(.horizontal) .padding(.vertical, 1.5) - .foregroundColor(Color.primaryTextColor) + .foregroundColor(Color.primaryDark) if isSelecting { Divider() @@ -40,7 +40,7 @@ struct CustomDropdownMenu: View { .padding(.vertical) .background( RoundedRectangle(cornerRadius: 10) - .strokeBorder(Color.gray, lineWidth: 1) + .strokeBorder(Color.primaryDark, lineWidth: 1) .background(Color.white) .cornerRadius(10) ) @@ -54,6 +54,7 @@ struct CustomDropdownMenu: View { } .animation(.easeInOut(duration: 0.3)) } + } private func dropDownItemsList() -> some View { diff --git a/Rethread/Rethread/Components/CustomField.swift b/Rethread/Rethread/Components/CustomField.swift new file mode 100644 index 0000000..7da1400 --- /dev/null +++ b/Rethread/Rethread/Components/CustomField.swift @@ -0,0 +1,25 @@ +import SwiftUI +import CustomTextField + +struct CustomField: View { + @Binding var text: String + var titleText: String + var placeHolderText: String + var secureText: Bool = false + + var body: some View { + EGTextField(text: $text) + .setTitleText(titleText) + .setTitleColor(Color.primaryDark) + .setPlaceHolderText(placeHolderText) + .setPlaceHolderTextColor(Color.PrimaryLight) + .setTruncateMode(.tail) + .setBorderColor(.primaryDark) + .setTextColor(Color.primaryDark) + .setDisableAutoCorrection(true) + .setTextFieldHeight(48) + .setFocusedBorderColorEnable(true) + .setSecureText(secureText) + .setTrailingImageForegroundColor(Color.primaryDark) + } +} diff --git a/Rethread/Rethread/Components/Verification.swift b/Rethread/Rethread/Components/Verification.swift new file mode 100644 index 0000000..634ed37 --- /dev/null +++ b/Rethread/Rethread/Components/Verification.swift @@ -0,0 +1,99 @@ +import SwiftUI + + +struct Verification: View { + @Binding var otpFields: [String] + @State var otpText: String + + // Text Field Focus State + @FocusState var activeField: OTPField? + + var body: some View { + VStack { + OTPField() + } + .padding() + .frame(maxHeight: .infinity, alignment: .top) + .onChange(of: otpFields) { newValue in + OTPCondition(value: newValue) + } + } + + func checkStates()->Bool { + for index in 0..<6 { + if otpFields[index].isEmpty { return true } + } + + return false + } + + // MARK: Only one character per input & Moving + func OTPCondition(value: [String]) { + + // Move Front + for index in 0..<5 { + if value[index].count == 1 && activeStateForIndex(index: index) == activeField { + activeField = activeStateForIndex(index: index + 1) + } + } + + //Move back if current is empty and back is not + for index in 1...5 { + if value[index].isEmpty && !value[index - 1].isEmpty { + activeField = activeStateForIndex(index: index - 1) + } + } + + for index in 0..<6 { + if value[index].count > 1 { + otpFields[index] = String(value[index].last!) + } + } + } + + @ViewBuilder + func OTPField()->some View { + HStack(spacing: 14) { + ForEach(0..<6, id: \.self) { index in + VStack (spacing: 8) { + TextField("", text: $otpFields[index]) + .keyboardType(.numberPad) + .textContentType(.oneTimeCode) + .multilineTextAlignment(.center) + .frame(width: 45, height: 45) + .overlay(RoundedRectangle(cornerRadius: 8).stroke( + activeField == activeStateForIndex(index: index) ? Color.primaryDark.opacity(0.4) : Color.primaryDark, + lineWidth: 1)) + .focused($activeField, equals: activeStateForIndex(index: index)) + + + } + .frame(width: 40) + } + } + } + + func activeStateForIndex (index: Int) -> OTPField { + switch index { + case 0: return .field1 + case 1: return .field2 + case 2: return .field3 + case 3: return .field4 + case 4: return .field5 + default: return .field6 + } + } +} + +enum OTPField { + case field1 + case field2 + case field3 + case field4 + case field5 + case field6 +} + +#Preview { + Verification(otpFields: .constant(["","","","","",""]), otpText: "") +} diff --git a/Rethread/Rethread/Core/ContentView.swift b/Rethread/Rethread/Core/ContentView.swift new file mode 100644 index 0000000..f15249f --- /dev/null +++ b/Rethread/Rethread/Core/ContentView.swift @@ -0,0 +1,22 @@ +import SwiftUI + +struct ContentView: View { + @EnvironmentObject var viewModel: AuthViewModel + + + var body: some View { + Group { + if viewModel.isLoading { + ProgressView("Loading...") + } else { + if viewModel.currentUser?.onboardingComplete == false { + WelcomeView() + } else if viewModel.userSession != nil { + HomeView() + } else { + MainView() + } + } + } + } +} diff --git a/Rethread/Rethread/Core/OnboardingApp.swift b/Rethread/Rethread/Core/OnboardingApp.swift index 05a2d43..366e95a 100644 --- a/Rethread/Rethread/Core/OnboardingApp.swift +++ b/Rethread/Rethread/Core/OnboardingApp.swift @@ -1,12 +1,20 @@ // OnboardingApp.swift import SwiftUI +import Firebase @main struct OnboardingApp: App { + @StateObject var viewModel = AuthViewModel() + + init() { + FirebaseApp.configure() + } + var body: some Scene { WindowGroup { - MainView() + ContentView() + .environmentObject(viewModel) } } } diff --git a/Rethread/Rethread/Info.plist b/Rethread/Rethread/Info.plist new file mode 100644 index 0000000..83fb1ab --- /dev/null +++ b/Rethread/Rethread/Info.plist @@ -0,0 +1,17 @@ + + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.69711373157-smt51cs82nik0nceo6slguta9vmaip00 + + + + + diff --git a/Rethread/Rethread/MainView.swift b/Rethread/Rethread/MainView.swift deleted file mode 100644 index 9e58835..0000000 --- a/Rethread/Rethread/MainView.swift +++ /dev/null @@ -1,128 +0,0 @@ -import SwiftUI -import NavigationTransitions - -#if canImport(UIKit) -extension View { - func hideKeyboard() { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } -} -#endif - -struct MainView: View { - @AppStorage("isLoggedIn") var isLoggedIn = false - @State private var path: [String] = [] - - var body: some View { - NavigationStack (path: $path) { - ZStack (alignment: .bottom) { - // Add Image - Image("starSky") - .resizable() - .overlay(Color.black.opacity(0.01)) - .clipped() - .edgesIgnoringSafeArea(.all) - .padding(.bottom, 210) - - // Description text - VStack { - Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit purus sit amet luctus venenatis, lectus magna fringilla urna.") - .font(.body) - .foregroundColor(.gray) - .multilineTextAlignment(.center) - .padding(.horizontal, 25) - .padding(.bottom, 55) - .padding(.top, 35) - - - - HStack(spacing: 30) { - // Log In Button - Button(action: { - path.append("SignInView") - }) { - HStack { - Text("Log In") - Image(systemName: "arrow.right.circle") - } - .frame(maxWidth: .infinity) - } - .buttonStyle(PrimaryButtonStyle()) - - // Sign Up Button - Button(action: { - path.append("SignUpView") - }) { - HStack { - Text("Join Us") - Image(systemName: "person.crop.circle.badge.plus") - } - .frame(maxWidth: .infinity) - } - .buttonStyle(SecondaryButtonStyle()) - } - .padding(.horizontal) - .padding(.bottom, 15) - .navigationDestination(for: String.self) { view in - if view == "SignInView" { - SignInView(path: $path) - } else if view == "SignUpView" { - SignUpView(path: $path) - } else if view == "WelcomeView" { - WelcomeView(path: $path) - } - } - } - .frame(maxWidth: .infinity) - .background(Color.white) // Background for text readability - .cornerRadius(20) - .edgesIgnoringSafeArea(.bottom) - } - .frame(maxHeight: .infinity) - .onAppear() { - if isLoggedIn { - - // Get user data from database and store in userDefaults - // We want to check if the user has onboarding completed or not - // If not, we want to show the onboarding view - - // If logged in, and onboarding is not completed, show onboarding - } - } - } - .navigationTransition(.slide(axis: .vertical)) - // Safe area for iPhone X and above - .edgesIgnoringSafeArea(.all) // This will extend the content to the edges - .background(Color(UIColor.systemGray6)) - .overlay( - GeometryReader { geometry in - Color.white.opacity(0.65) // Adjust the opacity here for semi-transparency - .frame(width: geometry.size.width, height: geometry.safeAreaInsets.top) - .edgesIgnoringSafeArea(.top) - }, alignment: .top - ) - } -} - -struct CustomTextField: View { - var placeholder: String - @Binding var text: String - - var body: some View { - TextField(placeholder, text: $text) - .foregroundColor(Color.primaryTextColor) - .padding() - .overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.gray, lineWidth: 1)) - .zIndex(-1) - } - -} - -#if DEBUG -struct MainView_Previews: PreviewProvider { - static var previews: some View { - MainView() - } -} -#endif - diff --git a/Rethread/Rethread/Models/MapViewModel.swift b/Rethread/Rethread/Models/MapViewModel.swift new file mode 100644 index 0000000..7526762 --- /dev/null +++ b/Rethread/Rethread/Models/MapViewModel.swift @@ -0,0 +1,47 @@ +// MapViewModel.swift + +import MapKit + + +final class MapViewModel: NSObject, ObservableObject, CLLocationManagerDelegate { + + @Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.331516, longitude: -121.891054), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)) + + + var locationManager: CLLocationManager? + + func isUserLocationOn() { + if CLLocationManager.locationServicesEnabled() { + locationManager = CLLocationManager() + locationManager!.delegate = self + } + else { + print("Show an alert showing user that they need to turn on location") + } + } + + private func checkLocationAuthorization () { + guard let locationManager = locationManager else { return } + + + switch locationManager.authorizationStatus { + + case .notDetermined: + locationManager.requestWhenInUseAuthorization() + case .restricted: + print("Sorry! Your location is restricted.") + case .denied: + print("You have denied ReThread the use of your location. Go into settings to allow premissions.") + case .authorizedAlways, .authorizedWhenInUse: + region = MKCoordinateRegion(center: locationManager.location!.coordinate, + span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)) + @unknown default: + break + } + } + + func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { + checkLocationAuthorization() + } + +} diff --git a/Rethread/Rethread/QuestionView.swift b/Rethread/Rethread/QuestionView.swift deleted file mode 100644 index 0c60716..0000000 --- a/Rethread/Rethread/QuestionView.swift +++ /dev/null @@ -1,84 +0,0 @@ -import SwiftUI - -struct QuestionView: View { - var question: String - var options: [String] - var isLastPage: Bool - var action: () -> Void - var previousAction: () -> Void - - @Binding var selectedAnswers: [String] // Directly using the binding to manage state - - private func currentButtonStyle() -> AnyButtonStyle { - if isLastPage { - return AnyButtonStyle(LetStartButtonStyle(isEnabled: !selectedAnswers.isEmpty)) - } else { - return AnyButtonStyle(NextButtonStyle(isEnabled: !selectedAnswers.isEmpty)) - } - } - - var body: some View { - VStack { - Text(question) - .font(.body) - .foregroundColor(.gray) - .padding(.top, 100) - .padding(.bottom, 40) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 20.0) - - ForEach(options, id: \.self) { option in - OptionRow(option: option, isSelected: selectedAnswers.contains(option)) { - if let index = selectedAnswers.firstIndex(of: option) { - selectedAnswers.remove(at: index) // Deselect the option - } else { - selectedAnswers.append(option) // Select the option - } - } - } - .padding([.leading, .trailing], 35) - - Spacer() - - // Navigation buttons - HStack { - Button(action: previousAction) { - Image(systemName: "chevron.left") - .font(.title) - } - .buttonStyle(PreviousButtonStyle()) - - Spacer() - - Button(action: action) { - if isLastPage { - Text("Let's Start!") - .font(.body) - .foregroundColor(.white) - } else { - Image(systemName: "chevron.right") - .font(.title) - } - } - .buttonStyle(currentButtonStyle()) - .disabled(selectedAnswers.isEmpty) - } - .padding(.bottom, 70) - - } - .background(Color(UIColor.systemGray6)) // Use the system background color - .edgesIgnoringSafeArea(.all) - } -} - -struct AnyButtonStyle: ButtonStyle { - private let _makeBody: (Configuration) -> AnyView - - init(_ style: Style) { - self._makeBody = { configuration in AnyView(style.makeBody(configuration: configuration)) } - } - - func makeBody(configuration: Configuration) -> some View { - self._makeBody(configuration) - } -} diff --git a/Rethread/Rethread/SignInView.swift b/Rethread/Rethread/SignInView.swift deleted file mode 100644 index 90d88ec..0000000 --- a/Rethread/Rethread/SignInView.swift +++ /dev/null @@ -1,144 +0,0 @@ -import SwiftUI - - - -struct SignInView: View { - @Binding var path: [String] - @State private var email: String = "" - @State private var password: String = "" - @State private var isShowingVerification: Bool = false - @State private var isPasswordVisible: Bool = false - @FocusState var isFieldFocus: FieldToFocus? - @Environment(\.dismiss) private var dismiss - - enum FieldToFocus { - case secureField, textField - } - - var body: some View { - VStack { - // Top content, including the back button and text fields - VStack(alignment: .leading) { - HStack { - Button(action: { - dismiss() - }) { - Image(systemName: "chevron.left") - } - .buttonStyle(SecondaryButtonStyle(width: 15, height: 15)) - .clipShape(Circle()) - Spacer() - } - .padding(.horizontal) - .padding(.top, 40) - .padding(.bottom, 20) - - Text("Welcome back!") - .font(.largeTitle) - .fontWeight(.bold) - .padding(.horizontal, 25) - .padding(.bottom, 1) - .foregroundColor(Color.primaryColor) - - HStack (spacing: 0) { - Text("Login below or ") - .fontWeight(.medium) - .foregroundColor(Color.primaryColor) - Button(action: { - path.removeLast() - path.append("SignUpView") - }) { - Text("create an account") - .foregroundColor(Color.primaryColor) - .fontWeight(.bold) - .underline() // Underlined text - } - Spacer() - } - .padding(.horizontal, 25) - - - VStack(alignment: .leading, spacing: 0) { - Text("Email") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 25) - - CustomTextField(placeholder: "Email", text: $email) - .padding(.horizontal, 25) - .padding(.top, 9) - - Text("Password") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 20) - .padding(.bottom, 9) - - HStack { - if isPasswordVisible { - TextField("Password", text: $password) - .disableAutocorrection(true) - .autocapitalization(/*@START_MENU_TOKEN@*/.none/*@END_MENU_TOKEN@*/) - .focused($isFieldFocus, equals: .textField) - } else { - SecureField("Password", text: $password) - .disableAutocorrection(true) - .autocapitalization(/*@START_MENU_TOKEN@*/.none/*@END_MENU_TOKEN@*/) - .focused($isFieldFocus, equals: .secureField) - } - - Button(action: { - self.isPasswordVisible.toggle() - }) { - Image(systemName: self.isPasswordVisible ? "eye.slash.fill" : "eye.fill") - .foregroundColor(Color.gray) - } - } - .padding() - .overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.gray, lineWidth: 1)) - .padding(.horizontal, 25) - .onChange(of: isPasswordVisible) { newValue in - isFieldFocus = isPasswordVisible ? .textField : .secureField - } - } - - Spacer() - } - - // Bottom content, including the sign-in button - VStack (spacing: 16) { - Button("Sign In") { - // Handle sign in action - self.isShowingVerification = true - } - .buttonStyle(PrimaryButtonStyle(width: 300)) - - - - Button(action: { - // Handle forgot password action - }) { - Text("Forgot Password") - .foregroundColor(Color.primaryColor) - .fontWeight(.semibold) - .underline() // Underlined text - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) // Aligns buttons to the bottom - } - .fullScreenCover(isPresented: $isShowingVerification) { - VerificationView(isSignIn: true, path: $path) - } - .gesture(TapGesture().onEnded{ - self.hideKeyboard() - }) - .ignoresSafeArea(.keyboard) - .navigationBarBackButtonHidden(true) - } -} - -struct MainView2_Previews: PreviewProvider { - static var previews: some View { - MainView() - } -} diff --git a/Rethread/Rethread/SignUpView.swift b/Rethread/Rethread/SignUpView.swift deleted file mode 100644 index 8a18f0d..0000000 --- a/Rethread/Rethread/SignUpView.swift +++ /dev/null @@ -1,264 +0,0 @@ -import SwiftUI - -struct SignUpView: View { - @Binding var path: [String] - @State private var isShowingVerification: Bool = false - struct SignUpFormData { - var firstName: String = "" // First name text field - var lastName: String = "" // Last name text field - var email: String = "" // Email text field - var password: String = "" // Password text field - var confirmPassword: String = "" // Confirm password text field - var phoneNumber: String = "" // Phone number text field - var postalCode: String = "" // Zip code text field - var dateOfBirth: String = "" // Date of birth text field - var gender: String = "Male" // Gender text field - } - @State private var formData = SignUpFormData() - @State private var isPasswordVisible = false - @State private var showingDatePicker = false - @State private var showingTermsAndConditions = false - @State private var showingGenderPicker = false - @State private var genderOptions = ["Male", "Female", "Other"] - @State private var areTermsAccepted = false - @Environment(\.dismiss) private var dismiss - - func toggleDatePicker() { - showingDatePicker.toggle() - } - - - var body: some View { - ZStack { - VStack { - // Top content, including the back button and text fields - ScrollView { - VStack(alignment: .leading) { - HStack { - Button(action: { - dismiss() - }) { - Image(systemName: "chevron.left") - } - .buttonStyle(SecondaryButtonStyle(width: 15, height: 15)) - .clipShape(Circle()) - Spacer() - } - .padding(.horizontal) - .padding(.top, 40) - .padding(.bottom, 20) - - Text("Create an account") - .font(.largeTitle) - .fontWeight(.bold) - .padding(.horizontal, 25) - .padding(.bottom, 1) - .foregroundColor(Color.primaryColor) - - HStack (spacing: 0) { - Text("Enter your account details below or ") - .fontWeight(.medium) - .foregroundColor(Color.primaryColor) - Button(action: { - path.removeLast() - path.append("SignInView") - }) { - Text("log in") - .foregroundColor(Color.primaryColor) - .fontWeight(.bold) - .underline() // Underlined text - } - Spacer() - } - .padding(.horizontal, 25) - .padding(.bottom, 10) - } - - VStack(alignment: .leading) { - VStack(alignment: .leading, spacing: 0) { - HStack { - VStack(alignment: .leading, spacing: 0) { - Text("First Name") - .foregroundColor(Color.primaryColor) - .padding(.leading, 25) - .padding(.top, 20) - - CustomTextField(placeholder: "First Name", text: $formData.firstName) - .padding(.leading, 25) - .padding(.top, 9) - } - - VStack(alignment: .leading, spacing: 0) { - Text("Last Name") - .foregroundColor(Color.primaryColor) - .padding(.trailing, 25) - .padding(.top, 20) - - CustomTextField(placeholder: "Last Name", text: $formData.lastName) - .padding(.trailing, 25) - .padding(.top, 9) - } - } - - Text("Email") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 20) - - CustomTextField(placeholder: "Email", text: $formData.email) - .padding(.horizontal, 25) - .padding(.top, 9) - HStack { - VStack (alignment: .leading, spacing: 0){ - Text("Date of Birth") - .foregroundColor(Color.primaryColor) - .padding(.top, 20) - - HStack { - TextField("MM / DD / YYYY", text: $formData.dateOfBirth ) - .foregroundColor(Color.primaryTextColor) - .keyboardType(.numberPad) - .onChange(of: formData.dateOfBirth) { newValue in - formData.dateOfBirth = formatDate(newValue) - } - - - Button(action: { - // Actions to present a date picker - toggleDatePicker() - }) { - Image(systemName: "calendar") - .foregroundColor(.gray) - } - } - .padding() - .overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.gray, lineWidth: 1)) - .padding(.top, 9) - } - - - VStack (alignment: .leading, spacing: 0) { - Text("Gender") - .foregroundColor(Color.primaryColor) - .padding(.trailing, 25) - .padding(.top, 20) - - CustomDropdownMenu(items: [ - DropdownItem(id: 1, title: "Male", onSelect: {formData.gender = "Male"}), - DropdownItem(id: 2, title: "Female", onSelect: {formData.gender = "Female"}), - DropdownItem(id: 3, title: "Other", onSelect: {formData.gender = "Other"}) - ]) - .frame(width:130) - .padding(.top, 9) - - } - } - .padding(.horizontal, 25) - - Text("Phone Number") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 20) - - CustomTextField(placeholder: "Phone Number", text: $formData.phoneNumber) - .padding(.horizontal, 25) - .padding(.top, 9) - - Text("Password") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 20) - .padding(.bottom, 9) - - SecureField("Password", text: $formData.password) - .disableAutocorrection(true) - .autocapitalization(.none) - .padding() - .overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.gray, lineWidth: 1)) - .padding(.horizontal, 25) - - Text("Confirm Password") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 20) - .padding(.bottom, 9) - - SecureField("Confirm Password", text: $formData.confirmPassword) - .disableAutocorrection(true) - .autocapitalization(.none) - .padding() - .overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.gray, lineWidth: 1)) - .padding(.horizontal, 25) - - Text("Postal Code") - .foregroundColor(Color.primaryColor) - .padding(.horizontal, 25) - .padding(.top, 20) - - CustomTextField(placeholder: "Postal Code", text: $formData.postalCode) - .padding(.horizontal, 25) - .padding(.top, 9) - - } - } - - Spacer() - - - // Bottom content, including the sign-in button - VStack (spacing: 16) { - Button("Join Us") { - // Handle sign up - print(formData) - self.isShowingVerification = true - } - .buttonStyle(PrimaryButtonStyle(width: 300, isDisabled: !areTermsAccepted)) - .disabled(!areTermsAccepted) - - HStack { - Image(systemName: areTermsAccepted ? "checkmark.square.fill" : "square") - .foregroundColor(Color.primaryColor) - .onTapGesture { - areTermsAccepted.toggle() - } - .offset(y: 2) - .font(.system(size: 20)) - - - Button(action: { - showingTermsAndConditions.toggle() - }) { - Text("Terms and Conditions") - .foregroundColor(Color.primaryColor) - .fontWeight(.semibold) - .underline() // Underlined text - } - } - } - .frame(maxWidth: .infinity) // Aligns buttons to the bottom - .padding(.vertical, 10) - } - } - .fullScreenCover(isPresented: $isShowingVerification) { - VerificationView(isSignIn: false, path: $path) - } - .gesture(TapGesture().onEnded{ - self.hideKeyboard() - }) - } - // Date picker modal - .sheet(isPresented: $showingDatePicker) { - DatePickerModalView(showModal: $showingDatePicker, chosenDate: $formData.dateOfBirth) - .presentationDetents([.fraction(0.7)]) - .presentationDragIndicator(.visible) - - } - .sheet(isPresented: $showingTermsAndConditions){ - TermsAndConditions() - .presentationDetents([.medium, .large]) - .padding(.horizontal, 15) - .padding(.top, 15) - } - .navigationBarBackButtonHidden(true) - } -} diff --git a/Rethread/Rethread/Styles/ButtonStyles.swift b/Rethread/Rethread/Styles/ButtonStyles.swift index a2050bb..7d0acac 100644 --- a/Rethread/Rethread/Styles/ButtonStyles.swift +++ b/Rethread/Rethread/Styles/ButtonStyles.swift @@ -34,8 +34,7 @@ struct PrimaryButtonStyle: ButtonStyle { configuration.label .frame(width: width, height: height) // Use optional binding in case width and height are not provided .padding() - .background(configuration.isPressed || isDisabled ? Color(red: 170/255, green: 177/255, blue: 187/255) - : Color.primaryColor) + .background(configuration.isPressed || isDisabled ? Color.GrayDisabled : Color.primaryDark) .cornerRadius(9) .foregroundColor(.white) .scaleEffect(configuration.isPressed ? 0.95 : 1) @@ -53,10 +52,9 @@ struct SecondaryButtonStyle: ButtonStyle { configuration.label .frame(width: width, height: height) // Use optional binding in case width and height are not provided .padding() - .background(configuration.isPressed ? Color(red: 214/255, green: 216/255, blue: 219/255) - : Color(red: 238/255, green: 241/255, blue: 244/255)) + .background(configuration.isPressed ? Color.GrayDisabled : Color.Secondary) .cornerRadius(9) - .foregroundColor(Color(red: 84/255, green: 95/255, blue: 113/255)) + .foregroundColor(.white) .scaleEffect(configuration.isPressed ? 0.95 : 1) } } @@ -66,14 +64,15 @@ struct PreviousButtonStyle: ButtonStyle { configuration.label .foregroundColor(.white) .frame(width: 70, height: 60) - .background(UnevenRoundedRectangle(cornerRadii: .init( - topLeading: 0.0, - bottomLeading: 0.0, - bottomTrailing: 25.0, - topTrailing: 6.0), - style: .continuous) - .fill(configuration.isPressed ? Color(red: 170/255, green: 177/255, blue: 187/255) - : Color.primaryColor)) + .background( + RoundedCorners( + color: !configuration.isPressed ? Color.primaryDark : Color.primaryDark.opacity(0.5), + tl: 0, + tr: 7, + bl: 0, + br: 7 + ) + ) } } @@ -84,14 +83,15 @@ struct NextButtonStyle: ButtonStyle { configuration.label .foregroundColor(.white) .frame(width: 70, height: 60) - .background(UnevenRoundedRectangle(cornerRadii: .init( - topLeading: 6.0, - bottomLeading: 25.0, - bottomTrailing: 0.0, - topTrailing: 0.0), - style: .continuous) - .fill(isEnabled && !configuration.isPressed ? Color.primaryColor - : Color(red: 170/255, green: 177/255, blue: 187/255))) // Disabled color + .background( + RoundedCorners( + color: isEnabled && !configuration.isPressed ? Color.Secondary : Color.Secondary.opacity(0.5), + tl: 7, + tr: 0, + bl: 7, + br: 0 + ) + ) } } @@ -102,14 +102,15 @@ struct LetStartButtonStyle: ButtonStyle { configuration.label .foregroundColor(.white) .frame(width: 140, height: 60) - .background(UnevenRoundedRectangle(cornerRadii: .init( - topLeading: 6.0, - bottomLeading: 25.0, - bottomTrailing: 0.0, - topTrailing: 0.0), - style: .continuous) - .fill(isEnabled && !configuration.isPressed ? Color.primaryColor - : Color(red: 170/255, green: 177/255, blue: 187/255))) // Disabled color + .background( + RoundedCorners( + color: isEnabled && !configuration.isPressed ? Color.Secondary : Color.Secondary.opacity(0.5), + tl: 7, + tr: 0, + bl: 7, + br: 0 + ) + ) } } diff --git a/Rethread/Rethread/Styles/ColorPalette.swift b/Rethread/Rethread/Styles/ColorPalette.swift index 4cc4bca..dcb7646 100644 --- a/Rethread/Rethread/Styles/ColorPalette.swift +++ b/Rethread/Rethread/Styles/ColorPalette.swift @@ -3,4 +3,11 @@ import SwiftUI extension Color { static let primaryColor = Color(red: 102/255, green: 112/255, blue: 128/255) static let primaryTextColor = Color(red: 84/255, green: 95/255, blue: 113/255) + + // New Colors + static let primaryDark = Color(red: 25/255, green: 75/255, blue: 82/255, opacity: 1) + static let Secondary = Color(red: 249/255, green: 95/255, blue: 95/255, opacity: 1) + static let GrayDisabled = Color(red: 217/255, green: 217/255, blue: 218/255, opacity: 1) + static let PrimaryLight = Color(red: 93/255, green: 148/255, blue: 167/255, opacity: 1) + } diff --git a/Rethread/Rethread/UserAuthentication/AuthViewModel.swift b/Rethread/Rethread/UserAuthentication/AuthViewModel.swift new file mode 100644 index 0000000..ebe927c --- /dev/null +++ b/Rethread/Rethread/UserAuthentication/AuthViewModel.swift @@ -0,0 +1,110 @@ +import Foundation +import FirebaseCore +import FirebaseAuth +import FirebaseFirestore +import FirebaseFirestoreSwift + +@MainActor +class AuthViewModel: ObservableObject { + @Published var userSession: FirebaseAuth.User? + @Published var currentUser: User? + @Published var CLIENT_CODE: String = "" + private var verificationId: String? + @Published var isLoading: Bool = true + + init(){ + self.userSession = Auth.auth().currentUser + self.isLoading = true + Task { + await fetchUser() + self.isLoading = false + } + } + + // Sign In function + func signIn(withEmail email: String, password: String) async throws { + do { + let result = try await Auth.auth().signIn(withEmail: email, password: password) + self.userSession = result.user + await fetchUser() + } catch { + print("DEBUG: Failed to log in with error .\(error.localizedDescription)") + } + } + + // Sign Up a user + func createUser(formData: SignUpFormData) async throws { + do { + let result = try await Auth.auth().createUser(withEmail: formData.email, password: formData.password) + self.userSession = result.user + + let user = User(id: result.user.uid, firstname: formData.firstName, lastname: formData.lastName, + email: formData.email, dateOfBirth: formData.dateOfBirth, gender: formData.gender, + phoneNumber: formData.phoneNumber,postalCode: formData.postalCode, onboardingComplete: false) + + let encodedUser = try Firestore.Encoder().encode(user) + try await Firestore.firestore().collection("users").document(user.id).setData(encodedUser) + await fetchUser() + } catch { + print("DEBUG: Error creating user: \(error.localizedDescription)") + } + } + + func updateOnboardingComplete() async throws { + do { + let userRef = Firestore.firestore().collection("users").document(userSession!.uid) + try await userRef.updateData(["onboardingComplete": true]) + await fetchUser() + } catch { + print("DEBUG: Error updating user onboard status: \(error.localizedDescription)") + } + } + + // Signout + func signOut() { + do { + try Auth.auth().signOut() + self.userSession = nil + self.currentUser = nil + } catch { + print("DEBUG: Failed to sign out with error \(error.localizedDescription)") + } + } + + // Delete Account + func deleteAccount() { + //TODO: Implement user deleting account. + } + + // Fetch User + func fetchUser() async { + guard let uid = Auth.auth().currentUser?.uid else {return} + guard let snapshot = try? await Firestore.firestore().collection("users").document(uid).getDocument() else {return} + self.currentUser = try? snapshot.data(as: User.self) + } + + + +// func sendPhoneAuth() async { +// PhoneAuthProvider.provider().verifyPhoneNumber("+16505551111", uiDelegate: nil) { [weak self] verificationID, error in +// guard let verificationID = verificationID, error == nil else { +// print("DEBUG: Error sending phone auth: \(error!.localizedDescription)") +// return +// } +// self?.verificationId = verificationID +// } +// } +// func verifyPhoneAuth(otp: String) async { +// guard let verificationId = self.verificationId else {return} +// let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationId, verificationCode: otp) +// +// Auth.auth().signIn(with: credential) { (result, error) in +// if let error = error { +// print("DEBUG: Error verifying phone auth: \(error.localizedDescription)") +// return +// } +// self.userSession = result?.user +// } +// } + +} diff --git a/Rethread/Rethread/UserAuthentication/User.swift b/Rethread/Rethread/UserAuthentication/User.swift new file mode 100644 index 0000000..58f328b --- /dev/null +++ b/Rethread/Rethread/UserAuthentication/User.swift @@ -0,0 +1,14 @@ +import Foundation + + +struct User: Identifiable, Codable { + let id: String + let firstname: String + let lastname: String + let email: String + let dateOfBirth: String + let gender: String + let phoneNumber: String + let postalCode: String + let onboardingComplete: Bool +} diff --git a/Rethread/Rethread/VerificationView.swift b/Rethread/Rethread/VerificationView.swift deleted file mode 100644 index 015b28a..0000000 --- a/Rethread/Rethread/VerificationView.swift +++ /dev/null @@ -1,125 +0,0 @@ -import SwiftUI - -struct VerificationView: View { - // Sign in or Sign up verification? - @State var isSignIn: Bool - @Binding var path: [String] - @Environment(\.dismiss) private var dismiss - @State private var code: [String] = ["", "", "", ""] - @FocusState private var focusedField: Field? - - enum Field: Int, Hashable { - case field1 = 0, field2, field3, field4 - - var next: Field? { - return Field(rawValue: self.rawValue + 1) - } - } - - - var body: some View { - VStack { - VStack(alignment: .leading) { - HStack { - Button(action: { - dismiss() - }) { - Image(systemName: "chevron.left") - } - .buttonStyle(SecondaryButtonStyle(width: 15, height: 15)) - .clipShape(Circle()) - Spacer() - } - .padding(.horizontal) - .padding(.top, 40) - .padding(.bottom, 20) - - Text("Verify your account") - .font(.largeTitle) - .fontWeight(.bold) - .padding(.horizontal, 25) - .padding(.bottom, 1) - .foregroundColor(Color.primaryColor) - - HStack (spacing: 0) { - Text("Enter the 4-digit PIN code sent to your email address xxx@example.com.") - .fontWeight(.medium) - .foregroundColor(Color.primaryColor) - Spacer() - } - .padding(.horizontal, 25) - - VStack(alignment: .leading, spacing: 0) { - HStack(spacing: 10) { - ForEach(0..<4, id: \.self) { index in - TextField("", text: $code[index]) - .frame(width: 45, height: 45) - .overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.primary, lineWidth: 1)) - .multilineTextAlignment(.center) - .keyboardType(.numberPad) - .focused($focusedField, equals: Field(rawValue: index)) - .onChange(of: code[index]) { newValue in - if newValue.count == 1 { - // A character is entered in the current field - if index < code.count - 1 { - // Move to the next field only if it's not the last one - focusedField = Field(rawValue: index + 1) - } else { - // Last field - perhaps perform some action or unfocus - focusedField = nil - } - } else if newValue.isEmpty && index > 0 { - // Backspace is pressed, and it's not the first field - // Move to the previous field - focusedField = Field(rawValue: index - 1) - } - } - - - - } - } - .padding(.horizontal, 25) - .padding(.top, 30) - - } - Spacer() - } - - // Bottom content, including the sign-in button - VStack (spacing: 16) { - Button("Verify") { - // Handle sign in - if isSignIn { - // Sign in - print("Sign in") - } else { - withAnimation { - dismiss() - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - path.append("WelcomeView") - } - } - } - } - .buttonStyle(PrimaryButtonStyle(width: 300)) - - Button(action: { - // Handle request new code - }) { - Text("Request new code") - .foregroundColor(Color.primaryColor) - .fontWeight(.semibold) - .underline() // Underlined text - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) // Aligns buttons to the bottom - } - .onTapGesture { - self.hideKeyboard() - } - - } -} - - diff --git a/Rethread/Rethread/VideoPlayer/UIPlayerView.swift b/Rethread/Rethread/VideoPlayer/UIPlayerView.swift index 10ddba6..5dc64f3 100644 --- a/Rethread/Rethread/VideoPlayer/UIPlayerView.swift +++ b/Rethread/Rethread/VideoPlayer/UIPlayerView.swift @@ -1,6 +1,5 @@ -import Foundation -import SwiftUI -import AVKit +import UIKit +import AVFoundation class UIVideoPlayer: UIView { @@ -9,7 +8,15 @@ class UIVideoPlayer: UIView { override init(frame: CGRect) { super.init(frame: frame) - + setupVideoPlayer() + addAppLifecycleObservers() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupVideoPlayer() { guard let url = URL(string: "https://github.com/bbmvicomte/videoOnboardingScreen/blob/master/bounce.mp4?raw=true") else { return } player = AVPlayer(url: url) @@ -17,10 +24,8 @@ class UIVideoPlayer: UIView { playerLayer.player = player playerLayer.videoGravity = .resizeAspectFill - layer.addSublayer(playerLayer) - - // Add observer + NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(notification:)), name: .AVPlayerItemDidPlayToEndTime, @@ -34,18 +39,25 @@ class UIVideoPlayer: UIView { playerLayer.frame = bounds } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + @objc private func playerItemDidReachEnd(notification: Notification) { + player?.seek(to: CMTime.zero) + player?.play() } - @objc func playerItemDidReachEnd(notification: Notification) { - // Restart video from the beginning - player?.seek(to: CMTime.zero) + private func addAppLifecycleObservers() { + NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(appWillResignActive), name: UIApplication.willResignActiveNotification, object: nil) + } + + @objc private func appDidBecomeActive() { player?.play() } + @objc private func appWillResignActive() { + player?.pause() + } + deinit { - // Remove observer NotificationCenter.default.removeObserver(self) } } diff --git a/Rethread/Rethread/Views/.DS_Store b/Rethread/Rethread/Views/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Rethread/Rethread/Views/.DS_Store differ diff --git a/Rethread/Rethread/Views/ClothingItemView.swift b/Rethread/Rethread/Views/ClothingItemView.swift new file mode 100644 index 0000000..4e885d4 --- /dev/null +++ b/Rethread/Rethread/Views/ClothingItemView.swift @@ -0,0 +1,122 @@ +// ClothingItemView.swift + +import SwiftUI + +struct ClothingItemView: View { + let columns: [GridItem] = [ + GridItem(.flexible()), + GridItem(.flexible()), + ] + + @State private var isHidden = false + + + var body: some View { + + VStack { + VStack { + HomeBarView() + MainSearchBar() + + ScrollView(.horizontal, showsIndicators: false) { + HStack { + Button(action: { + withAnimation { + isHidden.toggle() + } + }, label: { + Text("Category") + Image(systemName: "chevron.down") + }) + .buttonStyle(.borderedProminent) + .tint(.white) + .foregroundStyle(Color(hex: "#2C4C52")) + .overlay( + RoundedRectangle(cornerSize: CGSize(width: 5, height: 5)) + .stroke(Color(hex: "#2C4C52")) + ) + + + + Button(action: { + }, label: { + Text("Color") + Image(systemName: "chevron.down") + }) + .buttonStyle(.borderedProminent) + .tint(.white) + .foregroundStyle(Color(hex: "#2C4C52")) + .overlay( + RoundedRectangle(cornerSize: CGSize(width: 5, height: 5)) + .stroke(Color(hex: "#2C4C52")) + ) + + + Button(action: {}, label: { + Text("Gender") + Image(systemName: "chevron.down") + + }) + .buttonStyle(.borderedProminent) + .tint(.white) + .foregroundStyle(Color(hex: "#2C4C52")) + .overlay( + RoundedRectangle(cornerSize: CGSize(width: 5, height: 5)) + .stroke(Color(hex: "#2C4C52")) + ) + + } + } + .padding(.horizontal) + } + + ZStack(alignment: .leading) { + VStack { + VStack() { + Text("PLACEHOLDER") + .padding() + Spacer() + + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.white) + VStack { + Text("") + + } + .frame(maxWidth: .infinity, maxHeight: 300) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .zIndex(5) + .opacity(isHidden ? 0 : 1) + .transition(.slide) + + + + + VStack { + HStack { + Text("Shirts") + .font(.title) + .fontWeight(.bold) + Spacer() + } + .padding(.horizontal) + + + LazyVGrid(columns: columns) { + ForEach(0..<3) {index in + ClothCard(width: 160, height: 150, clothingItem: Image("sweatshirt")) + } + } + .zIndex(-1) + Spacer() + } + } + } + } +} + +#Preview { + ClothingItemView() +} diff --git a/Rethread/Rethread/Views/HomeView.swift b/Rethread/Rethread/Views/HomeView.swift new file mode 100644 index 0000000..f1d32c6 --- /dev/null +++ b/Rethread/Rethread/Views/HomeView.swift @@ -0,0 +1,317 @@ +// HomeView.swift + +import SwiftUI +import MapKit + +struct HomeView: View { + var body: some View { + TabView { + Group { + ZStack { + ScrollView(.vertical, showsIndicators: false) { + VStack { + HomeBarView() + + MainSearchBar() + + ScrollText() // This is just the"sustainable brands text" + BrandCardScrollView() + + ShopByClothingText() + + ClothingCardView() + + SaveWithUsText() + + ScrollView(.horizontal, showsIndicators: false) { + HStack { + ForEach (0 ..< 3) { index in + ClothCard(width: 150, height: 150, clothingItem: Image("sweatshirt") // This isnt the "shop by clothing card" its the real clothing + )} + } + } + .padding(.horizontal) + + + } + } + + } + .padding(.bottom) + .tabItem { + Image(systemName: "house") + } + MapView() + .tabItem { + Spacer() + Image(systemName: "qrcode") + + } + + MapView() + .tabItem { + Image(systemName: "mappin.circle.fill") + } + MapView() + .tabItem { + Image(systemName: "person") + .padding(.vertical) + } + .foregroundStyle(.green) + } + .accentColor(.purple) + .toolbarBackground(.white, for: .tabBar) + + + + } + } +} + +#Preview { + HomeView() +} + +struct HomeBarView: View { + @State var isShowingSheet = false + var body: some View { + HStack { + Text("Hey Morteza!") + .font(.title2) + .titleText() + Spacer() + Button { + isShowingSheet.toggle() + } label: { + Image(systemName: "slider.horizontal.3") + .foregroundStyle(Color(hex: "#2C4C52")) + } + .sheet(isPresented: $isShowingSheet, content: { + FilterView() + .presentationDetents([.medium]) + }) + + + } + .padding(.horizontal) + } +} + + + +extension Color { + init(hex: String) { + var cleanHexCode = hex.trimmingCharacters(in: .whitespacesAndNewlines) + cleanHexCode = cleanHexCode.replacingOccurrences(of: "#", with: "") + print(cleanHexCode) + var rgb: UInt64 = 0 + + Scanner(string: cleanHexCode).scanHexInt64(&rgb) + + let redValue = Double((rgb >> 16) & 0xFF) / 255.0 + let greenValue = Double((rgb >> 8) & 0xFF) / 255.0 + let blueValue = Double(rgb & 0xFF) / 255.0 + self.init(red: redValue, green: greenValue, blue: blueValue) + } +} + +struct MainSearchBar: View { + @State private var search: String = "" + var body: some View { + HStack { + HStack { + TextField("Search Clothes", text: $search) + Image(systemName: "magnifyingglass") + .foregroundStyle(Color(hex: "#2C4C52")) + + } + .padding(.vertical, 10) + .padding(.horizontal, 10) + .background(.white) + .cornerRadius(5) + .overlay( + RoundedRectangle(cornerSize: CGSize(width: 5, height: 5)) + .stroke(Color(hex: "#2C4C52")) + ) + } + .padding() + + + } +} + +struct ScrollText: View { + var body: some View { + HStack { + Text("Sustainable Brands") + .titleText() + + } + .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, alignment: .leading) + .padding(.horizontal) + } +} + +struct SaveWithUsText: View { + var body: some View { + HStack { + Text("Save With Us!") + .titleText() + Spacer() + NavigationStack { + NavigationLink(destination: ProductView()) { + Text("View All") + .foregroundStyle(Color(hex: "#2C4C52")) + .fontWeight(.semibold) + .underline() + } + } + + } + .padding(.horizontal) + } +} + +struct FilterView: View { + var body: some View { + VStack { + CustomDropdownMenu(items: [ + DropdownItem(id: 1, title: "Category", onSelect: {}), + DropdownItem(id: 2, title: "Medium", onSelect: {}), + DropdownItem(id: 3, title: "Large", onSelect: {}), + DropdownItem(id: 4, title: "X-Large", onSelect: {}), + ]) + .frame(maxHeight: .maximum(100, 100)) + + + CustomDropdownMenu(items: [ + DropdownItem(id: 1, title: "Category", onSelect: {}), + DropdownItem(id: 2, title: "Medium", onSelect: {}), + DropdownItem(id: 3, title: "Large", onSelect: {}), + DropdownItem(id: 4, title: "X-Large", onSelect: {}), + ]) + .frame(maxHeight: .maximum(100, 100)) + + + } + .padding() + } +} + +struct BrandImageCardView: View { + let brandCard: Image + var body: some View { + HStack { + brandCard + .brandCard() + } + } +} + +struct ClothingImageCardView: View { + let clothingCard: Image + var body: some View { + HStack { + clothingCard + .clothingCard() + } + } +} + + +struct BrandCardScrollView: View { + var body: some View { + ScrollView (.horizontal, showsIndicators: false) { + HStack{ + ForEach(0 ..< 3) { index in + BrandImageCardView(brandCard: Image("brandCard_\(index + 1)")) + } + } + } + .padding(.horizontal) + .padding(.bottom) + } +} + +// MARK: EXTENSIONS +extension Image { + func brandCard() -> some View { + self + .resizable() + .frame(width: 200, height: 110) + .clipShape(RoundedRectangle(cornerRadius: 5)) + } +} + +extension Image { + func clothingCard() -> some View { + self + .resizable() + .frame(width: 100, height: 250) + .clipShape(RoundedRectangle(cornerRadius: 5)) + } + +} + +extension Text { + func titleText() -> some View { + self + .foregroundStyle(Color(hex: "#2C4C52")) + .fontWeight(.semibold) + .font(.title3) + } +} + +struct ShopByClothingText: View { + var body: some View { + Text("Shop By Clothing") + .titleText() + .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, alignment: .leading) + .padding(.horizontal) + } +} + +struct ClothingCardView: View { + var body: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack { + ForEach (0 ..< 4) { index in + ClothingImageCardView(clothingCard: Image ("clothingCard_1")) + } + } + } + .padding(.horizontal) + .padding(.bottom) + } +} + +struct ClothCard: View { + let width: CGFloat + let height: CGFloat + let clothingItem: Image + var body: some View { + VStack (alignment: .leading) { + clothingItem + .resizable() + .frame(width: width, height: height) + .clipShape(RoundedRectangle(cornerRadius: 8)) + Text("Sweat Shirt") + .font(.subheadline) + Text("$55") + .font(.subheadline) + } + } +} + +struct BottomNavBarItem: View { + let image: Image + let action: ()-> Void + var body: some View { + Button(action: action, label: { + image + .frame(maxWidth: .infinity) + .foregroundStyle(Color(hex: "#2C4C52")) + .fontWeight(.semibold) + }) + } +} diff --git a/Rethread/Rethread/Views/MainView.swift b/Rethread/Rethread/Views/MainView.swift new file mode 100644 index 0000000..768983d --- /dev/null +++ b/Rethread/Rethread/Views/MainView.swift @@ -0,0 +1,109 @@ +import SwiftUI +import NavigationTransitions + +#if canImport(UIKit) +extension View { + func hideKeyboard() { + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } +} +#endif + +struct MainView: View { + @State private var path: [String] = [] + + var body: some View { + NavigationStack (path: $path) { + ZStack (alignment: .bottom) { + // Add Image + Image("flowerMainPage") + .resizable() + .overlay(Color.black.opacity(0.1)) + .clipped() + .edgesIgnoringSafeArea(.all) + .padding(.bottom, 220) + + // Botom Part + VStack (spacing: 50) { + + HStack { + Text("Get involved with" + "\n" + "sustainable fashion") + .font(.system(size: 20)) + .fontWeight(.semibold) + .foregroundColor(Color.primaryDark) + .opacity(0.5) + .multilineTextAlignment(.leading) + .lineSpacing(6) + Spacer() + } + .padding(.horizontal, 35) + .padding(.top, 25) + + + + VStack (spacing: 17) { + Button(action: { + path.append("SignInView") + }) { + HStack { + Text("Log In") + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + .buttonStyle(PrimaryButtonStyle(width: 300)) + + HStack { + Spacer() + + Button(action: { + path.append("SignUpView") + }) { + Text("Create Account") + .foregroundColor(Color.primaryDark) + .fontWeight(.semibold) + .underline() + } + } + .padding(.horizontal, 35) + } + .navigationDestination(for: String.self) { view in + if view == "SignInView" { + SignInView(path: $path) + } else if view == "SignUpView" { + SignUpView(path: $path) + } else if view == "WelcomeView" { + WelcomeView() + } + } + } + .background(RoundedCorners( + color: .white, + tl: 20, + tr: 20 + )) + .frame(height: 270) + } + .frame(maxHeight: .infinity) + } + .navigationTransition(.slide(axis: .vertical)) + // Safe area for iPhone X and above + .edgesIgnoringSafeArea(.all) // This will extend the content to the edges + .background(Color(UIColor.systemGray6)) + .overlay( + GeometryReader { geometry in + Color.white.opacity(0.3) // Adjust the opacity here for semi-transparency + .frame(width: geometry.size.width, height: geometry.safeAreaInsets.top) + .edgesIgnoringSafeArea(.top) + }, alignment: .top + ) + } +} + +#if DEBUG +struct MainView_Previews: PreviewProvider { + static var previews: some View { + MainView() + } +} +#endif + diff --git a/Rethread/Rethread/Views/MapView.swift b/Rethread/Rethread/Views/MapView.swift new file mode 100644 index 0000000..998084f --- /dev/null +++ b/Rethread/Rethread/Views/MapView.swift @@ -0,0 +1,90 @@ +// MapView.swift + +import SwiftUI +import MapKit +import CoreLocation + +struct MapView: View { + @StateObject private var viewModel = MapViewModel() // MapViewModel can be fouund in Models/MapViewModels in the directory + @State private var cameraPos: MapCameraPosition = .userLocation(fallback: .automatic) + var body: some View { + + VStack { + Text("Use your current postal code or enter a new one to see locations near you!") + .padding() + .foregroundStyle(Color(hex: "#2C4C52")) + + LocationSearchBar() + + Text("Locations Around you") + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal) + .foregroundStyle(Color(hex: "#2C4C52")) + + CustomDropdownMenu(items: [ + DropdownItem(id: 1, title: "24 Ave. NW", onSelect: {}), + DropdownItem(id: 2, title: "32 Deer foot trail NE", onSelect: {}), + DropdownItem(id: 3, title: "18 Blvd. Road W", onSelect: {}) + ]) + .zIndex(1000) + .frame(maxHeight: .maximum(100, 100)) + .padding(.horizontal) + + + Map(position: $cameraPos) { + + } + .mapControls { + MapCompass() + MapUserLocationButton() + MapPitchToggle() + } + .accentColor(Color(hex: "#2C4C52")) + .onAppear { + viewModel.isUserLocationOn() + } + } + + + } +} + +struct LocationSearchBar: View { + @State private var search: String = "" + var body: some View { + HStack { + HStack { + TextField("Enter New Postal Code", text: $search) + Image(systemName: "mappin.circle") + .foregroundStyle(Color(hex: "#2C4C52")) + + } + .padding(.vertical, 10) + .padding(.horizontal, 10) + .background(.white) + .cornerRadius(5) + .overlay( + RoundedRectangle(cornerSize: CGSize(width: 8, height: 8)) + .stroke(Color(hex: "#2C4C52")) + ) + } + .padding() + + + } +} + + + + + + + + + + + + +#Preview { + MapView() +} diff --git a/Rethread/Rethread/OnboardingView.swift b/Rethread/Rethread/Views/OnboardingView.swift similarity index 76% rename from Rethread/Rethread/OnboardingView.swift rename to Rethread/Rethread/Views/OnboardingView.swift index 303e0a4..e141975 100644 --- a/Rethread/Rethread/OnboardingView.swift +++ b/Rethread/Rethread/Views/OnboardingView.swift @@ -6,18 +6,19 @@ struct OnboardingStep { let maxSelections: Int } +// MARK: Onboarding Questions let onboardingSteps = [ - OnboardingStep(question: "What is your favorite color?", - options: ["Red", "Green", "Blue", "Purple"], + OnboardingStep(question: "Which description best matches your style preference?", + options: ["Activewear", "Classic", "Minimalist", "Others"], maxSelections: 1), - OnboardingStep(question: "What is your favorite animal?", - options: ["Dog", "Cat", "Bird"], - maxSelections: 2), + OnboardingStep(question: "What are your main goals for sustainable consumption?", + options: ["Reduce carbon footprint", "Support ethical labour practices", "Reduce waste"], + maxSelections: 3), - OnboardingStep(question: "What is your favorite food?", - options: ["Pizza", "Pasta", "Burgers"], - maxSelections: 1) + OnboardingStep(question: "Who's the best?", + options: ["Parsa", "Parsa!", "Parsa!!"], + maxSelections: 2) ] struct OnboardingView: View { @@ -25,6 +26,7 @@ struct OnboardingView: View { @State private var selectedOptions = [[String]](repeating: [], count: onboardingSteps.count) let onboardingStepsCount = onboardingSteps.count @Environment(\.presentationMode) var presentationMode + @EnvironmentObject var viewModel: AuthViewModel var body: some View { @@ -33,9 +35,10 @@ struct OnboardingView: View { ForEach(0..Bool { + for index in 0..<6 { + if otpFields[index].isEmpty { return true } + } + + return false + } +} + +#if DEBUG +struct VerificationView_Previews: PreviewProvider { + static var previews: some View { + VerificationView(isSignIn: false, path: .constant([""]), formData: nil) + } +} +#endif diff --git a/Rethread/Rethread/WelcomeView.swift b/Rethread/Rethread/Views/WelcomeView.swift similarity index 53% rename from Rethread/Rethread/WelcomeView.swift rename to Rethread/Rethread/Views/WelcomeView.swift index 6692b20..22d7363 100644 --- a/Rethread/Rethread/WelcomeView.swift +++ b/Rethread/Rethread/Views/WelcomeView.swift @@ -2,47 +2,47 @@ import SwiftUI import AVKit struct WelcomeView: View { - @Binding var path: [String] @State private var showOnboarding = false @State private var player = AVPlayer() - + @EnvironmentObject var viewModel: AuthViewModel + var body: some View { ZStack(alignment: .bottom) { PlayerView() - .edgesIgnoringSafeArea(.all) - .padding(.bottom, 290) + .ignoresSafeArea() + .padding(.bottom, 255) Spacer() - VStack(alignment: .center, spacing: 40.0) { - - Text("Hi, Parsa!") - .font(.title) - .fontWeight(.bold) - .foregroundColor(.gray) - .padding(.top, 20) - - Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit purus sit amet luctus venenatis, lectus magna fringilla urna, porttitor.") - .font(.body) - .foregroundColor(.gray) - .multilineTextAlignment(.center) - .padding(.horizontal) - + VStack(alignment: .center, spacing: 40) { + VStack (alignment: .leading, spacing: 20) { + Text("Hi, " + (viewModel.currentUser?.firstname ?? "there") + "!") + .font(.system(size: 32)) + .fontWeight(.bold) + .foregroundColor(Color.primaryDark.opacity(0.5)) + + Text("We connect you to sustainability brands and help you save money!") + .font(.body) + .foregroundColor(Color.primaryDark.opacity(0.5)) + .multilineTextAlignment(.leading) + } + .padding(.top, 25) + .padding(.horizontal, 30) Button("Get Started", action: { withAnimation { showOnboarding.toggle() } }) - .buttonStyle(PrimaryButtonStyle(width: 200, height: 20)) - .padding(.bottom, 40.0) + .buttonStyle(PrimaryButtonStyle(width: 300)) + .padding(.bottom, 45) .padding(.top) } .frame(maxWidth: .infinity) - .background(Color.white) // Apply background and corner radius - .cornerRadius(15) // Adjust the corner radius as needed + .background(Color.white) + .cornerRadius(15) } .fullScreenCover(isPresented: $showOnboarding) { @@ -62,9 +62,9 @@ struct WelcomeView: View { } #if DEBUG -struct MainView23_Previews: PreviewProvider { +struct WelcomeView_Previews: PreviewProvider { static var previews: some View { - WelcomeView(path: .constant(["WelcomeView"])) + WelcomeView() } } #endif diff --git a/Rethread/Rethread/Views/testest.swift b/Rethread/Rethread/Views/testest.swift new file mode 100644 index 0000000..2302cfd --- /dev/null +++ b/Rethread/Rethread/Views/testest.swift @@ -0,0 +1,13 @@ +// testest.swift + +import SwiftUI + +struct testest: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + testest() +}