├── .swiftlint.yml ├── Project SF ├── Assets.xcassets │ ├── Contents.json │ ├── ActivityRings │ │ ├── Contents.json │ │ ├── moveIcon.imageset │ │ │ ├── move.png │ │ │ └── Contents.json │ │ ├── standIcon.imageset │ │ │ ├── stand.png │ │ │ └── Contents.json │ │ ├── exerciseIcon.imageset │ │ │ ├── exercise.png │ │ │ └── Contents.json │ │ ├── move.colorset │ │ │ └── Contents.json │ │ ├── exercise.colorset │ │ │ └── Contents.json │ │ ├── moveDark.colorset │ │ │ └── Contents.json │ │ ├── stand.colorset │ │ │ └── Contents.json │ │ ├── standDark.colorset │ │ │ └── Contents.json │ │ └── exerciseDark.colorset │ │ │ └── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── Support │ ├── TestApp.swift │ ├── ProjectSFApp.swift │ └── Main.swift ├── Utilities │ ├── Extensions │ │ ├── View+ForegroundModifier.swift │ │ ├── UIApplication+IsTesting.swift │ │ └── Double+ConvertFromRangeToRange.swift │ └── VisualEffectView.swift ├── Models │ ├── CloudKit │ │ ├── Records │ │ │ └── User.swift │ │ └── CloudKitStore.swift │ ├── Networking │ │ └── NetworkManager.swift │ └── HealthKitController.swift ├── Project SF.entitlements ├── Views │ ├── NavigationLabel.swift │ ├── Tabs │ │ ├── TeamsView.swift │ │ ├── Settings │ │ │ ├── ProfileSettingsView.swift │ │ │ └── SettingsView.swift │ │ └── CompetitionsView.swift │ ├── ContentView.swift │ ├── Splash Screen │ │ ├── SignIn.swift │ │ ├── InfoCell.swift │ │ ├── PrivacyView.swift │ │ └── IntroView.swift │ ├── ActivityRings.swift │ ├── RoundedButton.swift │ └── ActivityRing.swift └── Info.plist ├── Project SF.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ ├── privitec.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ └── grantgordinier.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ ├── privitec.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── grantgordinier.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ └── Project SF.xcscheme └── project.pbxproj ├── .github ├── workflows │ ├── lint.yml │ ├── test.yml │ └── build.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── CONTRIBUTING.md ├── Project SFTests ├── Info.plist ├── URLSessionMock.swift └── Project_SFTests.swift ├── README.md ├── LICENSE ├── .gitignore └── CODE_OF_CONDUCT.md /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - trailing_whitespace 3 | - multiple_closures_with_trailing_closure 4 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Project SF/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/moveIcon.imageset/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Activity-App/App/HEAD/Project SF/Assets.xcassets/ActivityRings/moveIcon.imageset/move.png -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/standIcon.imageset/stand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Activity-App/App/HEAD/Project SF/Assets.xcassets/ActivityRings/standIcon.imageset/stand.png -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/exerciseIcon.imageset/exercise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Activity-App/App/HEAD/Project SF/Assets.xcassets/ActivityRings/exerciseIcon.imageset/exercise.png -------------------------------------------------------------------------------- /Project SF.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/xcuserdata/privitec.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/project.xcworkspace/xcuserdata/privitec.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Activity-App/App/HEAD/Project SF.xcodeproj/project.xcworkspace/xcuserdata/privitec.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Project SF.xcodeproj/project.xcworkspace/xcuserdata/grantgordinier.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Activity-App/App/HEAD/Project SF.xcodeproj/project.xcworkspace/xcuserdata/grantgordinier.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/moveIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "move.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/standIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "stand.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/exerciseIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "exercise.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | # Lints the project using SwiftLint 2 | 3 | name: SwiftLint 4 | 5 | on: [push] 6 | 7 | jobs: 8 | Lint: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: GitHub Action for SwiftLint 15 | uses: norio-nomura/action-swiftlint@3.1.0 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 1. Clone this repo to your machine 2 | 2. Make a separate branch or use one of the existing ones 3 | 3. Add some cool stuff (take a look at issues for things that need doing) 4 | 4. Don't forget to document your code so everyone understands it 5 | 5. Make a pull request to the development branch 6 | 6. Wait for the code review team to review and merge it. 7 | -------------------------------------------------------------------------------- /Project SF/Support/TestApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestApp.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 11/7/20. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | struct TestApp: App { 12 | 13 | var body: some Scene { 14 | WindowGroup { 15 | Text("Testing") 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Project SF/Utilities/Extensions/View+ForegroundModifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // View+ForegroundModifier.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 10/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | extension View { 11 | 12 | public func foreground(_ overlay: Overlay) -> some View { 13 | self.overlay(overlay).mask(self) 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Project SF/Support/ProjectSFApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProjectSFApp.swift 3 | // Project SF 4 | // 5 | // Created by Christian Privitelli on 10/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ProjectSFApp: App { 11 | 12 | let cloudKitStore = CloudKitStore.shared 13 | 14 | var body: some Scene { 15 | WindowGroup { 16 | ContentView() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Project SF/Support/Main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Main.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 11/7/20. 6 | // 7 | 8 | import Foundation 9 | 10 | @main 11 | struct Main { 12 | 13 | static func main() { 14 | if !ProcessInfo.processInfo.isTesting { 15 | ProjectSFApp.main() 16 | } else { 17 | TestApp.main() 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | **Describe the bug** 2 | A clear and concise description of what the bug is. 3 | 4 | **To Reproduce** 5 | Steps to reproduce the behavior: 6 | 1. Go to '...' 7 | 2. Click on '....' 8 | 3. Scroll down to '....' 9 | 4. See error 10 | 11 | **Expected behavior** 12 | A clear and concise description of what you expected to happen. 13 | 14 | **Screenshots** 15 | If applicable, add screenshots to help explain your problem. 16 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/move.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.521", 9 | "green" : "0.221", 10 | "red" : "0.975" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/xcuserdata/privitec.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Project SF.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/exercise.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.004", 9 | "green" : "1.000", 10 | "red" : "0.848" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/moveDark.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.310", 9 | "green" : "0.067", 10 | "red" : "0.981" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/stand.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.926", 9 | "green" : "0.987", 10 | "red" : "0.005" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/standDark.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "0.848", 10 | "red" : "0.093" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF/Utilities/Extensions/UIApplication+IsTesting.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplication+IsTesting.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 11/7/20. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | extension ProcessInfo { 12 | 13 | var isTesting: Bool { 14 | #if DEBUG 15 | return environment["XCTestConfigurationFilePath"] != nil 16 | #else 17 | return false 18 | #endif 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/ActivityRings/exerciseDark.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.009", 9 | "green" : "0.999", 10 | "red" : "0.600" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/xcuserdata/grantgordinier.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Project SF.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Project SF/Models/CloudKit/Records/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 10/7/20. 6 | // 7 | 8 | import Foundation 9 | import CloudKit 10 | 11 | class UserRecord { 12 | 13 | private let record: CKRecord 14 | 15 | var nickname: String? { 16 | get { record["nickname"] as? String } 17 | set { record.setValue(newValue, forKey: "nickname") } 18 | } 19 | 20 | init(record: CKRecord) { 21 | self.record = record 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | **Is your feature request related to a problem? Please describe.** 2 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 3 | 4 | **Describe the solution you'd like** 5 | A clear and concise description of what you want to happen. 6 | 7 | **Describe alternatives you've considered** 8 | A clear and concise description of any alternative solutions or features you've considered. 9 | 10 | **Additional context** 11 | Add any other context or screenshots about the feature request here. 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # Tests the project 2 | 3 | name: UnitTesting 4 | 5 | on: [push] 6 | 7 | jobs: 8 | Build: 9 | runs-on: macos-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Select latest Xcode 15 | run: "sudo xcode-select -s /Applications/Xcode_12_beta.app" 16 | 17 | - name: Run Tests 18 | run: "xcodebuild -project 'Project SF.xcodeproj' -scheme 'Project SF' -destination platform='iOS Simulator',OS=14.0,name='iPhone 11 Pro' clean test | xcpretty && exit ${PIPESTATUS[0]}" 19 | 20 | -------------------------------------------------------------------------------- /Project SF/Project SF.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.healthkit 8 | 9 | com.apple.developer.healthkit.access 10 | 11 | com.apple.developer.icloud-container-identifiers 12 | 13 | com.apple.developer.icloud-services 14 | 15 | CloudKit 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Project SF/Utilities/VisualEffectView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VisualEffectView.swift 3 | // Project SF 4 | // 5 | // Created by Christian Privitelli on 10/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct VisualEffectView: UIViewRepresentable { 11 | var effect: UIVisualEffect? 12 | let effectView = UIVisualEffectView(effect: nil) 13 | 14 | func makeUIView(context: UIViewRepresentableContext) -> UIVisualEffectView { 15 | effectView.effect = effect 16 | return effectView 17 | } 18 | 19 | func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext) { } 20 | } 21 | -------------------------------------------------------------------------------- /Project SF/Utilities/Extensions/Double+ConvertFromRangeToRange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Double+ConvertFromRangeToRange.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 10/7/20. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Double { 11 | 12 | public func convert(fromRange: ClosedRange, toRange: ClosedRange) -> Double { 13 | var value = self 14 | value -= fromRange.lowerBound 15 | value /= Double(fromRange.upperBound - fromRange.lowerBound) 16 | value *= toRange.upperBound - toRange.lowerBound 17 | value += toRange.lowerBound 18 | return value 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Builds the project 2 | 3 | name: XcodeBuild 4 | 5 | on: [push] 6 | 7 | jobs: 8 | Build: 9 | runs-on: macos-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: List Xcodes 15 | run: ls -n /Applications/ | grep Xcode* 16 | 17 | - name: Select latest Xcode 18 | run: "sudo xcode-select -s /Applications/Xcode_12_beta.app" 19 | 20 | - name: Xcode Build 21 | uses: sersoft-gmbh/xcodebuild-action@v1.1 22 | with: 23 | project: Project SF.xcodeproj 24 | scheme: Project SF 25 | destination: platform=iOS Simulator,OS=14.0,name=iPhone 11 Pro 26 | action: build 27 | 28 | -------------------------------------------------------------------------------- /Project SF/Views/NavigationLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationLabel.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct NavigationLabel: View { 11 | let title: String 12 | let systemName: String 13 | let destination: Destination 14 | 15 | var body: some View { 16 | NavigationLink( 17 | destination: destination, 18 | label: { 19 | Label(title, systemImage: systemName) 20 | }) 21 | } 22 | } 23 | 24 | //struct NavigationLabel_Previews: PreviewProvider { 25 | // static var previews: some View { 26 | // NavigationLabel() 27 | // } 28 | //} 29 | -------------------------------------------------------------------------------- /Project SF/Views/Tabs/TeamsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TeamsView.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TeamsView: View { 11 | var body: some View { 12 | NavigationView { 13 | Text("Teams") 14 | .navigationBarTitle("Teams") 15 | } 16 | .tabItem { 17 | VStack { 18 | Image(systemName: "person.3.fill") 19 | .font(.system(size: 18)) 20 | Text("Teams") 21 | } 22 | } 23 | } 24 | } 25 | 26 | struct TeamsView_Previews: PreviewProvider { 27 | static var previews: some View { 28 | TeamsView() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Project SF/Views/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // Project SF 4 | // 5 | // Created by Christian Privitelli on 10/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | 12 | @State var page = 1 13 | 14 | var body: some View { 15 | TabView(selection: $page) { 16 | CompetitionsView() 17 | .tag(1) 18 | 19 | TeamsView() 20 | .tag(2) 21 | 22 | SettingsView() 23 | .tag(3) 24 | } 25 | .accentColor(.init(red: 1, green: 0.4, blue: 0.4)) 26 | } 27 | } 28 | 29 | struct ContentView_Previews: PreviewProvider { 30 | static var previews: some View { 31 | ContentView() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Project SFTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Project SF/Views/Splash Screen/SignIn.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SignIn.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SignIn: View { 11 | 12 | @State var username = "" 13 | 14 | var body: some View { 15 | VStack { 16 | Spacer() 17 | GroupBox { 18 | TextField("Enter your name", text: $username) { (didChange) in 19 | print(didChange) 20 | } onCommit: { 21 | print("Commited") 22 | } 23 | } 24 | .padding() 25 | Spacer() 26 | RoundedButton("Continue") { 27 | print(123) 28 | } 29 | } 30 | } 31 | } 32 | 33 | struct SignIn_Previews: PreviewProvider { 34 | static var previews: some View { 35 | SignIn() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project SF App 2 | ![SwiftLint](https://github.com/Activity-App/App/workflows/SwiftLint/badge.svg) ![XcodeBuild](https://github.com/Activity-App/App/workflows/XcodeBuild/badge.svg) ![UnitTesting](https://github.com/Activity-App/App/workflows/UnitTesting/badge.svg) 3 | 4 | Project SF is an app which allows individuals to compete in challenges using their Apple HealthKit data. 5 | 6 | # Requirements 7 | - Xcode 12.0 Beta 8 | - iOS 14.0 9 | 10 | # Connect with developers 11 | Connect with other developers of this project on the official [Discord Server](https://discord.gg/HcGXy3w) 12 | # Contributing 13 | 1. Clone this repo to your machine 14 | 2. Make a separate branch or use one of the existing ones 15 | 3. Add some cool stuff (take a look at issues for things that need doing) 16 | 4. Don't forget to document your code so everyone understands it 17 | 5. Make a pull request to the development branch 18 | 6. Wait for the code review team to review and merge it. 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Project SF 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Project SF/Views/Splash Screen/InfoCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfoCell.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct InfoCell: View { 11 | var title: String 12 | var subTitle: String 13 | var imageName: String 14 | 15 | var body: some View { 16 | HStack(alignment: .center) { 17 | Image(systemName: imageName) 18 | .font(.largeTitle) 19 | .foregroundColor(.blue) 20 | .padding() 21 | .frame(width: 60, height: 60) 22 | .aspectRatio(contentMode: .fit) 23 | 24 | VStack(alignment: .leading) { 25 | Text(title) 26 | .font(.headline) 27 | .foregroundColor(.primary) 28 | 29 | Text(subTitle) 30 | .font(.body) 31 | .foregroundColor(.secondary) 32 | } 33 | } 34 | .padding(.top) 35 | } 36 | } 37 | 38 | struct InfoCell_Previews: PreviewProvider { 39 | static var previews: some View { 40 | InfoCell(title: "dsafs", subTitle: "112rqwff", imageName: "pencil") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Project SF/Views/Tabs/Settings/ProfileSettingsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProfileSettingsView.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ProfileSettingsView: View { 11 | 12 | @State var username = "" 13 | 14 | @State var isShowingAlert = false 15 | 16 | var body: some View { 17 | VStack { 18 | Form { 19 | TextField("Enter your name", text: $username) { (didChange) in 20 | print(didChange) 21 | } onCommit: { 22 | guard !username.isEmpty else { 23 | isShowingAlert = true 24 | return 25 | } 26 | } 27 | } 28 | } 29 | .alert(isPresented: $isShowingAlert) { 30 | Alert(title: Text("Please, fill in your name"), message: nil, dismissButton: .default(Text("Ok"))) 31 | } 32 | } 33 | 34 | init() { 35 | username = UserDefaults.standard.string(forKey: "username") ?? "" 36 | } 37 | } 38 | 39 | struct ProfileSettingsView_Previews: PreviewProvider { 40 | static var previews: some View { 41 | ProfileSettingsView() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Project SF/Views/Splash Screen/PrivacyView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrivacyView.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PrivacyView: View { 11 | var body: some View { 12 | VStack(alignment: .leading) { 13 | Spacer() 14 | Text("We value your privacy.") 15 | .font(.title) 16 | .fontWeight(.bold) 17 | 18 | InfoCell(title: "Sharing", 19 | subTitle: "We don't share your data with other companies", 20 | imageName: "square.and.arrow.up.on.square") 21 | InfoCell(title: "This is a splash screen", 22 | subTitle: "something about using the apple watch trainings", 23 | imageName: "applewatch.watchface") 24 | InfoCell(title: "Test", 25 | subTitle: "idk maybe something else", 26 | imageName: "pencil") 27 | Spacer() 28 | 29 | RoundedNavigationLink("Continue", destination: Text("asd")) 30 | }.padding(.horizontal) 31 | .navigationTitle("Privacy") 32 | } 33 | } 34 | 35 | struct PrivacyView_Previews: PreviewProvider { 36 | static var previews: some View { 37 | PrivacyView() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Project SF/Views/ActivityRings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityRings.swift 3 | // Project SF 4 | // 5 | // Created by Christian Privitelli on 10/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ActivityRings: View { 11 | 12 | @ObservedObject var healthKit: HealthKitController 13 | 14 | var body: some View { 15 | ZStack { 16 | ActivityRing( 17 | ringColor: .move, 18 | ringWidth: 14, 19 | current: $healthKit.moveCurrent, 20 | goal: $healthKit.moveGoal 21 | ) 22 | .frame(width: 110, height: 110) 23 | ActivityRing( 24 | ringColor: .exercise, 25 | ringWidth: 14, 26 | current: $healthKit.exerciseCurrent, 27 | goal: $healthKit.exerciseGoal 28 | ) 29 | .frame(width: 78, height: 78) 30 | ActivityRing( 31 | ringColor: .stand, 32 | ringWidth: 14, 33 | current: $healthKit.standCurrent, 34 | goal: $healthKit.standGoal 35 | ) 36 | .frame(width: 46, height: 46) 37 | } 38 | } 39 | } 40 | 41 | struct ActivityRings_Previews: PreviewProvider { 42 | static var previews: some View { 43 | ActivityRings(healthKit: HealthKitController()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Project SFTests/URLSessionMock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLSessionMock.swift 3 | // Project SFTests 4 | // 5 | // Created by William Taylor on 11/7/20. 6 | // 7 | 8 | import Foundation 9 | 10 | class URLSessionDataTaskMock: URLSessionDataTask { 11 | 12 | // MARK: Properties 13 | 14 | private let completion: () -> Void 15 | 16 | // MARK: Init 17 | 18 | init(completion: @escaping () -> Void) { 19 | self.completion = completion 20 | } 21 | 22 | // MARK: Overriden Methods 23 | 24 | override func resume() { 25 | completion() 26 | } 27 | 28 | } 29 | 30 | class URLSessionMock: URLSession { 31 | 32 | // MARK: Properties 33 | 34 | var data: Data? 35 | 36 | var urlResponse: URLResponse? 37 | 38 | var error: Error? 39 | 40 | // MARK: Init 41 | 42 | override init() { 43 | super.init() 44 | } 45 | 46 | // MARK: Overriden Methods 47 | 48 | override func dataTask(with url: URL, 49 | completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { 50 | let data = self.data 51 | let urlResponse = self.urlResponse 52 | let error = self.error 53 | 54 | return URLSessionDataTaskMock { 55 | completionHandler(data, urlResponse, error) 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Project SF/Views/Splash Screen/IntroView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IntroView.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct IntroView: View { 11 | var body: some View { 12 | NavigationView { 13 | VStack(alignment: .leading) { 14 | Spacer() 15 | Text("This is an app about fitness challanges.") 16 | .font(.title) 17 | .fontWeight(.bold) 18 | 19 | InfoCell(title: "Test title", 20 | subTitle: "Some text that we use the data phom the phone", 21 | imageName: "iphone") 22 | InfoCell(title: "This is a splash screen", 23 | subTitle: "something about using the apple watch trainings", 24 | imageName: "applewatch.watchface") 25 | InfoCell(title: "Lightning fast", 26 | subTitle: "I hope everything will work as fast as possible..", 27 | imageName: "paperplane") 28 | Spacer() 29 | 30 | RoundedNavigationLink("Continue", destination: PrivacyView()) 31 | }.padding(.horizontal) 32 | .navigationTitle("Welcome") 33 | } 34 | } 35 | } 36 | 37 | struct IntroView_Previews: PreviewProvider { 38 | static var previews: some View { 39 | IntroView() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Project SF/Views/Tabs/Settings/SettingsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsView.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SettingsView: View { 11 | var body: some View { 12 | NavigationView { 13 | List { 14 | Section(header: Text("General"), content: { 15 | // TODO: Work on ProfileSettings view. 16 | NavigationLabel(title: "Profile", 17 | systemName: "person.crop.circle", 18 | destination: Text("destination")) 19 | // TODO: Create Notification settings. 20 | NavigationLabel(title: "Notifications", 21 | systemName: "app.badge", 22 | destination: Text("destination")) 23 | }) 24 | 25 | Section(header: Text("Privacy"), content: { 26 | // TODO: Create Alter settings . 27 | NavigationLabel(title: "Alter permissions", 28 | systemName: "heart.text.square", 29 | destination: Text("destination")) 30 | // TODO: Create Learn about privacy screen settings. 31 | NavigationLabel(title: "Learn about privacy", 32 | systemName: "key", 33 | destination: Text("destination")) 34 | }) 35 | } 36 | .listStyle(InsetGroupedListStyle()) 37 | .navigationBarTitle("Settings") 38 | } 39 | .tabItem { 40 | VStack { 41 | Image(systemName: "gearshape.fill") 42 | .font(.system(size: 18)) 43 | Text("Settings") 44 | } 45 | } 46 | } 47 | } 48 | 49 | struct SettingsView_Previews: PreviewProvider { 50 | static var previews: some View { 51 | SettingsView() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Project SF/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Project SF/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSHealthClinicalHealthRecordsShareUsageDescription 24 | Project SF requires your health data to compete with your friends. 25 | NSHealthShareUsageDescription 26 | Project SF requires your health data to compete with your friends. 27 | NSHealthUpdateUsageDescription 28 | Project SF requires your health data to compete with your friends. 29 | UIApplicationSceneManifest 30 | 31 | UIApplicationSupportsMultipleScenes 32 | 33 | 34 | UIApplicationSupportsIndirectInputEvents 35 | 36 | UILaunchScreen 37 | 38 | UIRequiredDeviceCapabilities 39 | 40 | armv7 41 | 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | UISupportedInterfaceOrientations~ipad 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationPortraitUpsideDown 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Project SF/Views/RoundedButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RoundedButton.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// A custom button with Text inside a rounded rect 11 | /// which spans across the whole width of the screen. 12 | struct RoundedButton: View { 13 | let title: String 14 | let action: () -> Void 15 | 16 | var body: some View { 17 | Button(action: action) { 18 | Text(title) 19 | .font(.system(.title2)) 20 | .fontWeight(.medium) 21 | .padding(12) 22 | .frame(maxWidth: .infinity) 23 | .background(Color.blue) 24 | .foregroundColor(.white) 25 | .cornerRadius(16) 26 | .padding() 27 | } 28 | } 29 | 30 | /// Basic Init method. 31 | /// - Parameters: 32 | /// - title: The title of the button. 33 | /// - action: The action that'll be performed on tap. 34 | init(_ title: String, action: @escaping () -> Void = {}) { 35 | self.title = title 36 | self.action = action 37 | } 38 | } 39 | 40 | /// A custom NavigationLink with Text inside a rounded rect 41 | /// which spans across the whole width of the screen. 42 | struct RoundedNavigationLink: View { 43 | let title: String 44 | let destination: Destination 45 | 46 | var body: some View { 47 | NavigationLink( 48 | destination: destination, 49 | label: { 50 | Text(title) 51 | .font(.system(.title2)) 52 | .fontWeight(.medium) 53 | .padding(12) 54 | .frame(maxWidth: .infinity) 55 | .background(Color.blue) 56 | .foregroundColor(.white) 57 | .cornerRadius(16) 58 | .padding() 59 | }) 60 | } 61 | 62 | init(_ title: String, destination: Destination) { 63 | self.title = title 64 | self.destination = destination 65 | } 66 | } 67 | 68 | struct RoundedButton_Previews: PreviewProvider { 69 | static var previews: some View { 70 | RoundedButton("Button title") 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Project SF/Models/Networking/NetworkManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkManager.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 10.07.2020. 6 | // 7 | 8 | import Foundation 9 | 10 | class NetworkManager { 11 | 12 | // MARK: Type Aliases 13 | 14 | typealias DataResult = Result 15 | typealias DecodedResult = Result 16 | 17 | // MARK: Static Properties 18 | 19 | static let shared = NetworkManager(urlSession: URLSession.shared) 20 | 21 | // MARK: Properties 22 | 23 | let urlSession: URLSession 24 | 25 | // MARK: Init 26 | 27 | init(urlSession: URLSession) { 28 | self.urlSession = urlSession 29 | } 30 | 31 | // MARK: Data Request 32 | 33 | func request(_ url: URL?, _ completion: @escaping (DataResult) -> Void) { 34 | guard let url = url else { 35 | completion(.failure(.invalidURL)) 36 | return 37 | } 38 | 39 | urlSession.dataTask(with: url) { (data, _, error) in 40 | if error != nil { 41 | completion(.failure(.networkError)) 42 | return 43 | } 44 | 45 | guard let data = data else { 46 | completion(.failure(.noDataInResponse)) 47 | return 48 | } 49 | 50 | completion(.success(data)) 51 | }.resume() 52 | } 53 | 54 | // MARK: Decoded Request 55 | 56 | func request(_ url: URL?, 57 | decode type: T.Type, 58 | completion: @escaping (DecodedResult) -> Void) { 59 | request(url) { (result) in 60 | switch result { 61 | case .success(let data): 62 | do { 63 | let decoded = try JSONDecoder().decode(type, from: data) 64 | completion(.success(decoded)) 65 | } catch { 66 | completion(.failure(.decodingError)) 67 | } 68 | case .failure(let error): 69 | completion(.failure(error)) 70 | } 71 | } 72 | } 73 | 74 | // MARK: - Network Error 75 | 76 | enum NetworkError: Error { 77 | case invalidURL 78 | case networkError 79 | case noDataInResponse 80 | case decodingError 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | 92 | # DS Store 93 | 94 | .DS_Store 95 | -------------------------------------------------------------------------------- /Project SF/Views/Tabs/CompetitionsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CompetitionsView.swift 3 | // Project SF 4 | // 5 | // Created by Roman Esin on 11.07.2020. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CompetitionsView: View { 11 | 12 | @StateObject var healthKit = HealthKitController() 13 | 14 | var body: some View { 15 | NavigationView { 16 | ZStack { 17 | VStack { 18 | Text("Competitions") 19 | .navigationBarTitle("Competitions") 20 | if !healthKit.success { 21 | Button("Try HealthKit Auth") { 22 | healthKit.authorizeHealthKit() 23 | } 24 | } 25 | Text(healthKit.success ? "Successfully Authorized" : 26 | healthKit.processBegan ? "Something went wrong" : "") 27 | if healthKit.success { 28 | Button("Read data") { 29 | healthKit.updateAllActivityData() 30 | } 31 | } 32 | if healthKit.processBegan && healthKit.success { 33 | HStack { 34 | ActivityRings(healthKit: healthKit) 35 | VStack(alignment: .leading) { 36 | HStack { 37 | Text("Move: ") 38 | .bold() 39 | .foregroundColor(Color("move")) 40 | Text("\(Int(healthKit.moveCurrent))/\(Int(healthKit.moveGoal))") 41 | } 42 | HStack { 43 | Text("Exercise: ") 44 | .bold() 45 | .foregroundColor(Color("exercise")) 46 | Text("\(Int(healthKit.exerciseCurrent))/\(Int(healthKit.exerciseGoal))") 47 | } 48 | HStack { 49 | Text("Stand: ") 50 | .bold() 51 | .foregroundColor(Color("stand")) 52 | Text("\(Int(healthKit.standCurrent))/\(Int(healthKit.standGoal))") 53 | } 54 | } 55 | } 56 | } 57 | } 58 | if healthKit.processBegan && !healthKit.success { 59 | ProgressView() 60 | } 61 | } 62 | 63 | } 64 | .tabItem { 65 | VStack { 66 | Image(systemName: "star.fill") 67 | .font(.system(size: 18)) 68 | Text("Competitions") 69 | } 70 | } 71 | } 72 | } 73 | 74 | struct CompetitionsView_Previews: PreviewProvider { 75 | static var previews: some View { 76 | CompetitionsView() 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/xcshareddata/xcschemes/Project SF.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for **everyone**, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Additional Considerations 35 | 36 | Many of our contributors may still be students, including those that are still minors. 37 | In regards to this, please be mindful when initiating and/or engaging in a conversation 38 | with other contributors. Particularly, be mindful of the language you use, and the 39 | appropriateness of your messaging with them. 40 | 41 | ## Our Responsibilities 42 | 43 | Project maintainers are responsible for clarifying the standards of acceptable 44 | behavior and are expected to take appropriate and fair corrective action in 45 | response to any instances of unacceptable behavior. 46 | 47 | Project maintainers have the right and responsibility to remove, edit, or 48 | reject comments, commits, code, wiki edits, issues, and other contributions 49 | that are not aligned to this Code of Conduct, or to ban temporarily or 50 | permanently any contributor for other behaviors that they deem inappropriate, 51 | threatening, offensive, or harmful. 52 | 53 | ## Scope 54 | 55 | This Code of Conduct applies both within project spaces and in public spaces 56 | when an individual is representing the project or its community. Examples of 57 | representing a project or community include using an official project e-mail 58 | address, posting via an official social media account, or acting as an appointed 59 | representative at an online or offline event. Representation of a project may be 60 | further defined and clarified by project maintainers. 61 | 62 | ## Enforcement 63 | 64 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 65 | reported by contacting a member of the project team on the Discord. All 66 | complaints will be reviewed and investigated and will result in a response that 67 | is deemed necessary and appropriate to the circumstances. The project team is 68 | obligated to maintain confidentiality with regard to the reporter of an incident. 69 | Further details of specific enforcement policies may be posted separately. 70 | 71 | Project maintainers who do not follow or enforce the Code of Conduct in good 72 | faith may face temporary or permanent repercussions as determined by other 73 | members of the project's leadership. 74 | 75 | ## Attribution 76 | 77 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 78 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 79 | 80 | [homepage]: https://www.contributor-covenant.org 81 | 82 | For answers to common questions about this code of conduct, see 83 | https://www.contributor-covenant.org/faq 84 | -------------------------------------------------------------------------------- /Project SF/Views/ActivityRing.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityRing.swift 3 | // Project SF 4 | // 5 | // Created by Christian Privitelli on 10/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | enum RingColor: String { 11 | 12 | case move 13 | case exercise 14 | case stand 15 | 16 | var color: Color { Color(rawValue) } 17 | var darkColor: Color { Color(rawValue + "Dark") } 18 | var icon: Image { Image(rawValue + "Icon") } 19 | } 20 | 21 | struct ActivityRing: View { 22 | 23 | var ringColor: RingColor 24 | var ringWidth: CGFloat 25 | 26 | @Binding var current: Double 27 | @Binding var goal: Double 28 | 29 | @State var fill: Double = 0 30 | 31 | var body: some View { 32 | GeometryReader { geometry in 33 | VStack { 34 | ZStack { 35 | 36 | // Ring outline 37 | Circle() 38 | .stroke(lineWidth: ringWidth) 39 | .opacity(0.3) 40 | .foregroundColor(ringColor.darkColor) 41 | 42 | // The activity ring 43 | Circle() 44 | .trim(from: 0, to: CGFloat(fill)) 45 | .stroke( 46 | AngularGradient( 47 | gradient: Gradient(colors: [ringColor.darkColor, ringColor.color]), 48 | center: .center, 49 | startAngle: .degrees(0), 50 | endAngle: .degrees(360 * fill) 51 | ), 52 | style: StrokeStyle(lineWidth: ringWidth, lineCap: .round)) 53 | .opacity(1) 54 | .rotationEffect(.degrees(-90)) 55 | .animation(.easeInOut(duration: 2.5)) 56 | 57 | // Fixes gradient when at 0 position 58 | Circle() 59 | .frame(width: ringWidth, height: ringWidth) 60 | .offset(y: -geometry.size.height/2) 61 | .foregroundColor( 62 | fill > 0.1 ? .clear : ringColor.darkColor 63 | ) 64 | 65 | // Ring shadow 66 | Circle() 67 | .frame(width: ringWidth, height: ringWidth) 68 | .offset(y: -geometry.size.height/2) 69 | .foregroundColor( 70 | fill > 0.96 ? ringColor.color : .clear 71 | ) 72 | .shadow( 73 | color: Color.black.opacity(0.15), 74 | radius: ringWidth/8, 75 | x: ringWidth/3.5, 76 | y: 0 77 | ) 78 | .rotationEffect(.degrees(360 * fill)) 79 | .animation(.easeInOut(duration: 2.5)) 80 | 81 | ringColor.icon 82 | .resizable() 83 | .frame(width: ringWidth-4, height: ringWidth-4) 84 | .offset(y: -geometry.size.height/2) 85 | } 86 | } 87 | } 88 | .onAppear { 89 | fill = current/goal + 0.001 90 | } 91 | .onChange(of: current) { newCurrent in 92 | fill = newCurrent/goal + 0.001 93 | } 94 | .onChange(of: goal) { newGoal in 95 | fill = current/newGoal + 0.001 96 | } 97 | } 98 | } 99 | 100 | struct ActivityRing_Previews: PreviewProvider { 101 | static var previews: some View { 102 | ActivityRing(ringColor: .stand, ringWidth: 30, current: .constant(19), goal: .constant(100)) 103 | .frame(width: 300, height: 300) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Project SFTests/Project_SFTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Project_SFTests.swift 3 | // Project SFTests 4 | // 5 | // Created by William Taylor on 10/7/20. 6 | // 7 | 8 | import XCTest 9 | @testable import Project_SF 10 | 11 | class ProjectSFTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | // MARK: Utilities 22 | 23 | func testRangeConversion() throws { 24 | XCTAssertEqual(1.0.convert(fromRange: 0...10, toRange: 0...1), 0.1) 25 | XCTAssertEqual(0.25.convert(fromRange: 0...1, toRange: 0...100), 25.0) 26 | XCTAssertEqual(0.1.convert(fromRange: 0...1, toRange: 0...10), 1.0) 27 | XCTAssertEqual(0.convert(fromRange: 0...5, toRange: 0...10), 0) 28 | XCTAssertEqual(5.convert(fromRange: 0...5, toRange: 0...10), 10) 29 | } 30 | 31 | // MARK: Network Manager 32 | 33 | func testNetworkManagerSuccessfulRequest() throws { 34 | let expect = XCTestExpectation() 35 | 36 | let mock = URLSessionMock() 37 | mock.data = Data([1, 0, 1, 1, 0]) 38 | 39 | let networkManager = NetworkManager(urlSession: mock) 40 | 41 | networkManager.request(URL(string: "fake")) { result in 42 | switch result { 43 | case .success(let data): 44 | XCTAssertEqual(data, mock.data) 45 | expect.fulfill() 46 | default: return 47 | } 48 | } 49 | 50 | wait(for: [expect], timeout: 1) 51 | } 52 | 53 | func testNetworkManagerErrorRequest() throws { 54 | let expect = XCTestExpectation() 55 | 56 | let mock = URLSessionMock() 57 | mock.error = FakeError() 58 | 59 | let networkManager = NetworkManager(urlSession: mock) 60 | 61 | networkManager.request(URL(string: "fake")) { result in 62 | switch result { 63 | case .failure(let error): 64 | XCTAssertEqual(error, NetworkManager.NetworkError.networkError) 65 | expect.fulfill() 66 | default: expect.fulfill() 67 | } 68 | } 69 | 70 | wait(for: [expect], timeout: 1) 71 | } 72 | 73 | func testNetworkManagerNoDataRequest() throws { 74 | let expect = XCTestExpectation() 75 | 76 | let mock = URLSessionMock() 77 | 78 | let networkManager = NetworkManager(urlSession: mock) 79 | 80 | networkManager.request(URL(string: "fake")) { result in 81 | switch result { 82 | case .failure(let error): 83 | XCTAssertEqual(error, NetworkManager.NetworkError.noDataInResponse) 84 | expect.fulfill() 85 | default: return 86 | } 87 | 88 | } 89 | 90 | wait(for: [expect], timeout: 1) 91 | } 92 | 93 | func testNetworkManagerRequestDecode() throws { 94 | let expect = XCTestExpectation() 95 | 96 | let mock = URLSessionMock() 97 | mock.data = """ 98 | { 99 | "name": "test", 100 | "count": 10123 101 | } 102 | """.data(using: .utf8) 103 | 104 | let networkManager = NetworkManager(urlSession: mock) 105 | 106 | networkManager.request(URL(string: "fake"), decode: SampleDataStruct.self) { result in 107 | switch result { 108 | case .success(let decodedObject): 109 | XCTAssertEqual(decodedObject.name, "test") 110 | XCTAssertEqual(decodedObject.count, 10123) 111 | expect.fulfill() 112 | default: return 113 | } 114 | } 115 | 116 | wait(for: [expect], timeout: 1) 117 | } 118 | 119 | // MARK: Performance 120 | 121 | func testPerformanceExample() throws { 122 | // This is an example of a performance test case. 123 | measure { 124 | // Put the code you want to measure the time of here. 125 | } 126 | } 127 | 128 | // MARK: Fake Error 129 | 130 | private struct FakeError: Error { 131 | 132 | let uuid = UUID() 133 | 134 | } 135 | 136 | // MARK: Sample Data Struct 137 | 138 | private struct SampleDataStruct: Codable { 139 | 140 | let name: String 141 | 142 | let count: Int 143 | 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /Project SF/Models/CloudKit/CloudKitStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CloudKitStore.swift 3 | // Project SF 4 | // 5 | // Created by William Taylor on 10/7/20. 6 | // 7 | 8 | import Foundation 9 | import CloudKit 10 | 11 | class CloudKitStore { 12 | 13 | // MARK: Static Properties 14 | 15 | static let shared = CloudKitStore(container: CKContainer.default()) 16 | 17 | private static let queue = DispatchQueue(label: "com.wwdc.Project-SF.cloudkitqueue") 18 | 19 | // MARK: Properties 20 | 21 | private let container: CKContainer 22 | 23 | // MARK: Init 24 | 25 | init(container: CKContainer) { 26 | self.container = container 27 | } 28 | 29 | // MARK: Methods 30 | 31 | /// Asynchronously fetches records from the CloudKit database. 32 | /// Current Limitation: Doesn't handle paging correctly 33 | /// - Parameters: 34 | /// - recordType: The type of record to fetch. 35 | /// - predicate: Condition for records to be fetched. 36 | /// - scope: The database scope. 37 | /// - handler: Called with the result of the operation. Not guaranteed to be on the main thread. 38 | func fetchRecords(with recordType: CKRecord.RecordType, 39 | predicate: NSPredicate = NSPredicate(value: true), 40 | scope: CKDatabase.Scope, 41 | then handler: @escaping (Result<[CKRecord], Error>) -> Void) { 42 | let query = CKQuery(recordType: recordType, predicate: predicate) 43 | let queryOperation = CKQueryOperation(query: query) 44 | 45 | var records = [CKRecord]() 46 | 47 | queryOperation.recordFetchedBlock = { record in 48 | Self.queue.sync { 49 | records.append(record) 50 | } 51 | } 52 | 53 | queryOperation.queryCompletionBlock = { cursor, error in 54 | Self.queue.sync { 55 | // TODO: Need to properly handle paging 56 | if let error = error { 57 | handler(.failure(error)) 58 | return 59 | } 60 | 61 | handler(.success(records)) 62 | } 63 | } 64 | 65 | let database = container.database(with: scope) 66 | database.add(queryOperation) 67 | } 68 | 69 | /// Asynchronously fetches a single record from the CloudKit database. 70 | /// - Parameters: 71 | /// - recordID: The ID of the record you want to fetch. 72 | /// - scope: The database scope 73 | /// - handler: Called with the result of the operation. Not guaranteed to be on the main thread. 74 | func fetchRecord(with recordID: CKRecord.ID, 75 | scope: CKDatabase.Scope, 76 | then handler: @escaping (Result) -> Void) { 77 | let database = container.database(with: scope) 78 | 79 | database.fetch(withRecordID: recordID) { record, error in 80 | if let error = error { 81 | handler(.failure(error)) 82 | return 83 | } 84 | guard let record = record else { 85 | handler(.failure(CloudKitStoreError.missingRecord)) 86 | return 87 | } 88 | 89 | handler(.success(record)) 90 | } 91 | } 92 | 93 | /// Asynchronously saves a single record to the CloudKit database, with a low priority. 94 | /// - Parameters: 95 | /// - record: The record to save. 96 | /// - scope: The database scope. 97 | /// - handler: Called with the result of the operation. Not guaranteed to be on the main thread. 98 | func saveRecord(_ record: CKRecord, 99 | scope: CKDatabase.Scope, 100 | then handler: @escaping (Result) -> Void) { 101 | let database = container.database(with: scope) 102 | 103 | database.save(record) { _, error in 104 | if let error = error { 105 | handler(.failure(error)) 106 | return 107 | } 108 | handler(.success(())) 109 | } 110 | } 111 | 112 | /// Asynchronously deletes a single record to the CloudKit database, with a low priority. 113 | /// - Parameters: 114 | /// - recordID: The ID of the record you want to delete. 115 | /// - scope: The database scope. 116 | /// - handler: Called with the result of the operation. Not guaranteed to be on the main thread. 117 | func deleteRecord(with recordID: CKRecord.ID, 118 | scope: CKDatabase.Scope, 119 | then handler: @escaping (Result) -> Void) { 120 | let database = container.database(with: scope) 121 | 122 | database.delete(withRecordID: recordID) { _, error in 123 | if let error = error { 124 | handler(.failure(error)) 125 | return 126 | } 127 | handler(.success(())) 128 | } 129 | } 130 | 131 | // MARK: - CloudKitStoreError 132 | 133 | enum CloudKitStoreError: Error { 134 | case missingRecord 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /Project SF/Models/HealthKitController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HealthKitController.swift 3 | // Project SF 4 | // 5 | // Created by Christian Privitelli on 10/7/20. 6 | // 7 | 8 | import Foundation 9 | import HealthKit 10 | 11 | class HealthKitController: ObservableObject { 12 | 13 | // MARK: Properties 14 | 15 | let healthStore: HKHealthStore 16 | 17 | // MARK: Published Properties 18 | 19 | @Published var processBegan = false 20 | @Published var success = false 21 | 22 | @Published var moveCurrent = 0.0 23 | @Published var moveGoal = 1.0 24 | 25 | @Published var exerciseCurrent = 0.0 26 | @Published var exerciseGoal = 30.0 27 | 28 | @Published var standCurrent = 0.0 29 | @Published var standGoal = 12.0 30 | 31 | // MARK: Init 32 | 33 | init(healthStore: HKHealthStore = .init()) { 34 | self.healthStore = healthStore 35 | } 36 | 37 | // MARK: Methods 38 | 39 | /// Authorize HealthKit with specified types. Will present a screen to give access if not previously enabled. 40 | func authorizeHealthKit() { 41 | DispatchQueue.main.async { 42 | self.processBegan = true 43 | } 44 | 45 | let healthKitTypes: Set = [ 46 | HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!, 47 | HKObjectType.quantityType(forIdentifier: .appleExerciseTime)!, 48 | HKObjectType.quantityType(forIdentifier: .appleStandTime)!, 49 | HKObjectType.quantityType(forIdentifier: .stepCount)!, 50 | HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!, 51 | HKObjectType.activitySummaryType() 52 | ] 53 | 54 | healthStore.requestAuthorization(toShare: nil, read: healthKitTypes, completion: { success, _ in 55 | if success { 56 | print("Success! HK is working") 57 | DispatchQueue.main.async { 58 | self.success = true 59 | } 60 | } 61 | }) 62 | } 63 | 64 | /// Gets activity data for current day, and stores the new values in the published vars. 65 | func updateAllActivityData() { 66 | 67 | let resultHandler: (HKActivitySummaryQuery, [HKActivitySummary]?, Error?) -> Void = { query, result, error in 68 | 69 | if let results = result { 70 | if !results.isEmpty { 71 | DispatchQueue.main.async { 72 | let moveUnits = HKUnit.largeCalorie() 73 | self.moveCurrent = results.last!.activeEnergyBurned.doubleValue(for: moveUnits) 74 | self.moveGoal = results.last!.activeEnergyBurnedGoal.doubleValue(for: moveUnits) 75 | 76 | let exerciseUnits = HKUnit.minute() 77 | self.exerciseCurrent = results.last!.appleExerciseTime.doubleValue(for: exerciseUnits) 78 | self.exerciseGoal = results.last!.appleExerciseTimeGoal.doubleValue(for: exerciseUnits) 79 | 80 | let standUnits = HKUnit.count() 81 | self.standCurrent = results.last!.appleStandHours.doubleValue(for: standUnits) 82 | self.standGoal = results.last!.appleStandHoursGoal.doubleValue(for: standUnits) 83 | } 84 | print("Move: \(self.moveCurrent)/\(self.moveGoal)") 85 | print("Exercise: \(self.exerciseCurrent)/\(self.exerciseGoal)") 86 | print("Stand: \(self.standCurrent)/\(self.standGoal)") 87 | } else { 88 | print("No results!") 89 | } 90 | } 91 | 92 | if error != nil { 93 | print("Error: \(error!)") 94 | } 95 | } 96 | 97 | let query = HKActivitySummaryQuery(predicate: nil, resultsHandler: resultHandler) 98 | healthStore.execute(query) 99 | } 100 | 101 | func update(data: HKQuantityTypeIdentifier, for day: Date) { 102 | let dataType = HKQuantityType.quantityType(forIdentifier: data) 103 | 104 | let calendar = Calendar(identifier: .gregorian) 105 | let startOfDay = calendar.startOfDay(for: day) 106 | 107 | let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: day, options: .strictStartDate) 108 | var interval = DateComponents() 109 | interval.day = 1 110 | 111 | let query = HKStatisticsCollectionQuery( 112 | quantityType: dataType!, 113 | quantitySamplePredicate: predicate, 114 | options: [.cumulativeSum], 115 | anchorDate: startOfDay as Date, 116 | intervalComponents: interval 117 | ) 118 | 119 | query.initialResultsHandler = { query, result, error in 120 | if let results = result { 121 | results.enumerateStatistics(from: startOfDay, to: day) { statistics, _ in 122 | if let quantity = statistics.sumQuantity() { 123 | let dataResult = quantity.doubleValue(for: HKUnit.meter()) 124 | 125 | print("Result = \(dataResult)") 126 | } 127 | } 128 | } 129 | if error != nil { 130 | print("Error: \(error!)") 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Project SF.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 308FAD8B24B97E7E00126F3F /* InfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD8A24B97E7E00126F3F /* InfoCell.swift */; }; 11 | 308FAD8D24B97E8A00126F3F /* PrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD8C24B97E8A00126F3F /* PrivacyView.swift */; }; 12 | 308FAD9124B987F000126F3F /* SignIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD9024B987F000126F3F /* SignIn.swift */; }; 13 | 308FAD9424B989DE00126F3F /* CompetitionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD9324B989DE00126F3F /* CompetitionsView.swift */; }; 14 | 308FAD9624B989EF00126F3F /* TeamsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD9524B989EF00126F3F /* TeamsView.swift */; }; 15 | 308FAD9824B989FF00126F3F /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD9724B989FF00126F3F /* SettingsView.swift */; }; 16 | 308FAD9C24B99AA700126F3F /* ProfileSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD9B24B99AA700126F3F /* ProfileSettingsView.swift */; }; 17 | 308FAD9E24B9A0DC00126F3F /* NavigationLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FAD9D24B9A0DC00126F3F /* NavigationLabel.swift */; }; 18 | 3090918224B9480F000E3B11 /* RoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3090918124B9480F000E3B11 /* RoundedButton.swift */; }; 19 | 30BFC8CE24B75E6C00DAC6D9 /* ProjectSFApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BFC8CD24B75E6C00DAC6D9 /* ProjectSFApp.swift */; }; 20 | 30BFC8D024B75E6C00DAC6D9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BFC8CF24B75E6C00DAC6D9 /* ContentView.swift */; }; 21 | 30BFC8D224B75E6F00DAC6D9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 30BFC8D124B75E6F00DAC6D9 /* Assets.xcassets */; }; 22 | 30BFC8D524B75E6F00DAC6D9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 30BFC8D424B75E6F00DAC6D9 /* Preview Assets.xcassets */; }; 23 | 30BFC8DF24B7637F00DAC6D9 /* VisualEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BFC8DE24B7637F00DAC6D9 /* VisualEffectView.swift */; }; 24 | 30BFC8E324B76BB900DAC6D9 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30BFC8E224B76BB900DAC6D9 /* HealthKit.framework */; }; 25 | 30BFC8E724B8041C00DAC6D9 /* ActivityRings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BFC8E624B8041C00DAC6D9 /* ActivityRings.swift */; }; 26 | 30BFC8E924B804CC00DAC6D9 /* ActivityRing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BFC8E824B804CC00DAC6D9 /* ActivityRing.swift */; }; 27 | 30F1EA3B24B951CA00FF89FC /* IntroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F1EA3A24B951CA00FF89FC /* IntroView.swift */; }; 28 | 9C7B4D0624B89AC700FC4456 /* View+ForegroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7B4D0524B89AC700FC4456 /* View+ForegroundModifier.swift */; }; 29 | 9C7B4D0824B89AF100FC4456 /* Double+ConvertFromRangeToRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C7B4D0724B89AF100FC4456 /* Double+ConvertFromRangeToRange.swift */; }; 30 | 9CCFDD0724B95E9600162B0F /* URLSessionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD0624B95E9600162B0F /* URLSessionMock.swift */; }; 31 | 9CCFDD1D24B971D600162B0F /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD1824B971D600162B0F /* User.swift */; }; 32 | 9CCFDD1E24B971D600162B0F /* CloudKitStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD1924B971D600162B0F /* CloudKitStore.swift */; }; 33 | 9CCFDD1F24B971D600162B0F /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD1B24B971D600162B0F /* NetworkManager.swift */; }; 34 | 9CCFDD2024B971D600162B0F /* HealthKitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD1C24B971D600162B0F /* HealthKitController.swift */; }; 35 | 9CCFDD2224B973EB00162B0F /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9CCFDD2124B973EB00162B0F /* CloudKit.framework */; }; 36 | 9CCFDD2424B9745E00162B0F /* UIApplication+IsTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD2324B9745E00162B0F /* UIApplication+IsTesting.swift */; }; 37 | 9CCFDD2624B9753F00162B0F /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD2524B9753F00162B0F /* Main.swift */; }; 38 | 9CCFDD2824B9758A00162B0F /* TestApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCFDD2724B9758A00162B0F /* TestApp.swift */; }; 39 | 9CD7F11E24B89C5000DDAD8C /* Project_SFTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD7F11D24B89C5000DDAD8C /* Project_SFTests.swift */; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXContainerItemProxy section */ 43 | 9CD7F12024B89C5000DDAD8C /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 30BFC8C224B75E6C00DAC6D9 /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = 30BFC8C924B75E6C00DAC6D9; 48 | remoteInfo = "Project SF"; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 308FAD8A24B97E7E00126F3F /* InfoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoCell.swift; sourceTree = ""; }; 54 | 308FAD8C24B97E8A00126F3F /* PrivacyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivacyView.swift; sourceTree = ""; }; 55 | 308FAD9024B987F000126F3F /* SignIn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignIn.swift; sourceTree = ""; }; 56 | 308FAD9324B989DE00126F3F /* CompetitionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompetitionsView.swift; sourceTree = ""; }; 57 | 308FAD9524B989EF00126F3F /* TeamsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamsView.swift; sourceTree = ""; }; 58 | 308FAD9724B989FF00126F3F /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 59 | 308FAD9B24B99AA700126F3F /* ProfileSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSettingsView.swift; sourceTree = ""; }; 60 | 308FAD9D24B9A0DC00126F3F /* NavigationLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationLabel.swift; sourceTree = ""; }; 61 | 3090918124B9480F000E3B11 /* RoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedButton.swift; sourceTree = ""; }; 62 | 30BFC8CA24B75E6C00DAC6D9 /* Project SF.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Project SF.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 30BFC8CD24B75E6C00DAC6D9 /* ProjectSFApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectSFApp.swift; sourceTree = ""; }; 64 | 30BFC8CF24B75E6C00DAC6D9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 65 | 30BFC8D124B75E6F00DAC6D9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 66 | 30BFC8D424B75E6F00DAC6D9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 67 | 30BFC8D624B75E6F00DAC6D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68 | 30BFC8DE24B7637F00DAC6D9 /* VisualEffectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualEffectView.swift; sourceTree = ""; }; 69 | 30BFC8E024B76BB800DAC6D9 /* Project SF.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Project SF.entitlements"; sourceTree = ""; }; 70 | 30BFC8E224B76BB900DAC6D9 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; 71 | 30BFC8E624B8041C00DAC6D9 /* ActivityRings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRings.swift; sourceTree = ""; }; 72 | 30BFC8E824B804CC00DAC6D9 /* ActivityRing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRing.swift; sourceTree = ""; }; 73 | 30F1EA3A24B951CA00FF89FC /* IntroView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroView.swift; sourceTree = ""; }; 74 | 9C7B4D0524B89AC700FC4456 /* View+ForegroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ForegroundModifier.swift"; sourceTree = ""; }; 75 | 9C7B4D0724B89AF100FC4456 /* Double+ConvertFromRangeToRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+ConvertFromRangeToRange.swift"; sourceTree = ""; }; 76 | 9CCFDD0624B95E9600162B0F /* URLSessionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionMock.swift; sourceTree = ""; }; 77 | 9CCFDD1824B971D600162B0F /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 78 | 9CCFDD1924B971D600162B0F /* CloudKitStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitStore.swift; sourceTree = ""; }; 79 | 9CCFDD1B24B971D600162B0F /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; 80 | 9CCFDD1C24B971D600162B0F /* HealthKitController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HealthKitController.swift; sourceTree = ""; }; 81 | 9CCFDD2124B973EB00162B0F /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; 82 | 9CCFDD2324B9745E00162B0F /* UIApplication+IsTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+IsTesting.swift"; sourceTree = ""; }; 83 | 9CCFDD2524B9753F00162B0F /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; }; 84 | 9CCFDD2724B9758A00162B0F /* TestApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestApp.swift; sourceTree = ""; }; 85 | 9CD7F11B24B89C5000DDAD8C /* Project SFTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Project SFTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | 9CD7F11D24B89C5000DDAD8C /* Project_SFTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Project_SFTests.swift; sourceTree = ""; }; 87 | 9CD7F11F24B89C5000DDAD8C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 88 | /* End PBXFileReference section */ 89 | 90 | /* Begin PBXFrameworksBuildPhase section */ 91 | 30BFC8C724B75E6C00DAC6D9 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | 30BFC8E324B76BB900DAC6D9 /* HealthKit.framework in Frameworks */, 96 | 9CCFDD2224B973EB00162B0F /* CloudKit.framework in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | 9CD7F11824B89C5000DDAD8C /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 2147483647; 103 | files = ( 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | /* End PBXFrameworksBuildPhase section */ 108 | 109 | /* Begin PBXGroup section */ 110 | 3029AF5024B8869E003F0324 /* Views */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 30BFC8CF24B75E6C00DAC6D9 /* ContentView.swift */, 114 | 308FAD9224B989BD00126F3F /* Tabs */, 115 | 308FAD8924B97E5500126F3F /* Splash Screen */, 116 | 30BFC8E624B8041C00DAC6D9 /* ActivityRings.swift */, 117 | 30BFC8E824B804CC00DAC6D9 /* ActivityRing.swift */, 118 | 3090918124B9480F000E3B11 /* RoundedButton.swift */, 119 | 308FAD9D24B9A0DC00126F3F /* NavigationLabel.swift */, 120 | ); 121 | path = Views; 122 | sourceTree = ""; 123 | }; 124 | 3029AF5124B886A7003F0324 /* Extensions */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 9C7B4D0724B89AF100FC4456 /* Double+ConvertFromRangeToRange.swift */, 128 | 9C7B4D0524B89AC700FC4456 /* View+ForegroundModifier.swift */, 129 | 9CCFDD2324B9745E00162B0F /* UIApplication+IsTesting.swift */, 130 | ); 131 | path = Extensions; 132 | sourceTree = ""; 133 | }; 134 | 3029AF5224B886CB003F0324 /* Support */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 9CCFDD2524B9753F00162B0F /* Main.swift */, 138 | 30BFC8CD24B75E6C00DAC6D9 /* ProjectSFApp.swift */, 139 | 9CCFDD2724B9758A00162B0F /* TestApp.swift */, 140 | ); 141 | path = Support; 142 | sourceTree = ""; 143 | }; 144 | 308FAD8924B97E5500126F3F /* Splash Screen */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 308FAD8A24B97E7E00126F3F /* InfoCell.swift */, 148 | 30F1EA3A24B951CA00FF89FC /* IntroView.swift */, 149 | 308FAD8C24B97E8A00126F3F /* PrivacyView.swift */, 150 | 308FAD9024B987F000126F3F /* SignIn.swift */, 151 | ); 152 | path = "Splash Screen"; 153 | sourceTree = ""; 154 | }; 155 | 308FAD9224B989BD00126F3F /* Tabs */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 308FAD9324B989DE00126F3F /* CompetitionsView.swift */, 159 | 308FAD9524B989EF00126F3F /* TeamsView.swift */, 160 | 308FAD9A24B999DC00126F3F /* Settings */, 161 | ); 162 | path = Tabs; 163 | sourceTree = ""; 164 | }; 165 | 308FAD9A24B999DC00126F3F /* Settings */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 308FAD9724B989FF00126F3F /* SettingsView.swift */, 169 | 308FAD9B24B99AA700126F3F /* ProfileSettingsView.swift */, 170 | ); 171 | path = Settings; 172 | sourceTree = ""; 173 | }; 174 | 30BFC8C124B75E6C00DAC6D9 = { 175 | isa = PBXGroup; 176 | children = ( 177 | 30BFC8CC24B75E6C00DAC6D9 /* Project SF */, 178 | 9CD7F11C24B89C5000DDAD8C /* Project SFTests */, 179 | 30BFC8CB24B75E6C00DAC6D9 /* Products */, 180 | 30BFC8E124B76BB900DAC6D9 /* Frameworks */, 181 | ); 182 | sourceTree = ""; 183 | }; 184 | 30BFC8CB24B75E6C00DAC6D9 /* Products */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 30BFC8CA24B75E6C00DAC6D9 /* Project SF.app */, 188 | 9CD7F11B24B89C5000DDAD8C /* Project SFTests.xctest */, 189 | ); 190 | name = Products; 191 | sourceTree = ""; 192 | }; 193 | 30BFC8CC24B75E6C00DAC6D9 /* Project SF */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 30BFC8E024B76BB800DAC6D9 /* Project SF.entitlements */, 197 | 3029AF5224B886CB003F0324 /* Support */, 198 | 3029AF5024B8869E003F0324 /* Views */, 199 | 9CCFDD1524B971D600162B0F /* Models */, 200 | 9C7B4D0A24B89B0F00FC4456 /* Utilities */, 201 | 30BFC8D124B75E6F00DAC6D9 /* Assets.xcassets */, 202 | 30BFC8D624B75E6F00DAC6D9 /* Info.plist */, 203 | 30BFC8D324B75E6F00DAC6D9 /* Preview Content */, 204 | ); 205 | path = "Project SF"; 206 | sourceTree = ""; 207 | }; 208 | 30BFC8D324B75E6F00DAC6D9 /* Preview Content */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | 30BFC8D424B75E6F00DAC6D9 /* Preview Assets.xcassets */, 212 | ); 213 | path = "Preview Content"; 214 | sourceTree = ""; 215 | }; 216 | 30BFC8E124B76BB900DAC6D9 /* Frameworks */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | 9CCFDD2124B973EB00162B0F /* CloudKit.framework */, 220 | 30BFC8E224B76BB900DAC6D9 /* HealthKit.framework */, 221 | ); 222 | name = Frameworks; 223 | sourceTree = ""; 224 | }; 225 | 9C7B4D0A24B89B0F00FC4456 /* Utilities */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 30BFC8DE24B7637F00DAC6D9 /* VisualEffectView.swift */, 229 | 3029AF5124B886A7003F0324 /* Extensions */, 230 | ); 231 | path = Utilities; 232 | sourceTree = ""; 233 | }; 234 | 9CCFDD1524B971D600162B0F /* Models */ = { 235 | isa = PBXGroup; 236 | children = ( 237 | 9CCFDD1624B971D600162B0F /* CloudKit */, 238 | 9CCFDD1A24B971D600162B0F /* Networking */, 239 | 9CCFDD1C24B971D600162B0F /* HealthKitController.swift */, 240 | ); 241 | path = Models; 242 | sourceTree = ""; 243 | }; 244 | 9CCFDD1624B971D600162B0F /* CloudKit */ = { 245 | isa = PBXGroup; 246 | children = ( 247 | 9CCFDD1724B971D600162B0F /* Records */, 248 | 9CCFDD1924B971D600162B0F /* CloudKitStore.swift */, 249 | ); 250 | path = CloudKit; 251 | sourceTree = ""; 252 | }; 253 | 9CCFDD1724B971D600162B0F /* Records */ = { 254 | isa = PBXGroup; 255 | children = ( 256 | 9CCFDD1824B971D600162B0F /* User.swift */, 257 | ); 258 | path = Records; 259 | sourceTree = ""; 260 | }; 261 | 9CCFDD1A24B971D600162B0F /* Networking */ = { 262 | isa = PBXGroup; 263 | children = ( 264 | 9CCFDD1B24B971D600162B0F /* NetworkManager.swift */, 265 | ); 266 | path = Networking; 267 | sourceTree = ""; 268 | }; 269 | 9CD7F11C24B89C5000DDAD8C /* Project SFTests */ = { 270 | isa = PBXGroup; 271 | children = ( 272 | 9CD7F11D24B89C5000DDAD8C /* Project_SFTests.swift */, 273 | 9CCFDD0624B95E9600162B0F /* URLSessionMock.swift */, 274 | 9CD7F11F24B89C5000DDAD8C /* Info.plist */, 275 | ); 276 | path = "Project SFTests"; 277 | sourceTree = ""; 278 | }; 279 | /* End PBXGroup section */ 280 | 281 | /* Begin PBXNativeTarget section */ 282 | 30BFC8C924B75E6C00DAC6D9 /* Project SF */ = { 283 | isa = PBXNativeTarget; 284 | buildConfigurationList = 30BFC8D924B75E6F00DAC6D9 /* Build configuration list for PBXNativeTarget "Project SF" */; 285 | buildPhases = ( 286 | 9CD6F92B24B7E9C400F167FC /* Run SwiftLint */, 287 | 30BFC8C624B75E6C00DAC6D9 /* Sources */, 288 | 30BFC8C724B75E6C00DAC6D9 /* Frameworks */, 289 | 30BFC8C824B75E6C00DAC6D9 /* Resources */, 290 | ); 291 | buildRules = ( 292 | ); 293 | dependencies = ( 294 | ); 295 | name = "Project SF"; 296 | productName = "Project SF"; 297 | productReference = 30BFC8CA24B75E6C00DAC6D9 /* Project SF.app */; 298 | productType = "com.apple.product-type.application"; 299 | }; 300 | 9CD7F11A24B89C5000DDAD8C /* Project SFTests */ = { 301 | isa = PBXNativeTarget; 302 | buildConfigurationList = 9CD7F12424B89C5000DDAD8C /* Build configuration list for PBXNativeTarget "Project SFTests" */; 303 | buildPhases = ( 304 | 9CD7F11724B89C5000DDAD8C /* Sources */, 305 | 9CD7F11824B89C5000DDAD8C /* Frameworks */, 306 | 9CD7F11924B89C5000DDAD8C /* Resources */, 307 | ); 308 | buildRules = ( 309 | ); 310 | dependencies = ( 311 | 9CD7F12124B89C5000DDAD8C /* PBXTargetDependency */, 312 | ); 313 | name = "Project SFTests"; 314 | productName = "Project SFTests"; 315 | productReference = 9CD7F11B24B89C5000DDAD8C /* Project SFTests.xctest */; 316 | productType = "com.apple.product-type.bundle.unit-test"; 317 | }; 318 | /* End PBXNativeTarget section */ 319 | 320 | /* Begin PBXProject section */ 321 | 30BFC8C224B75E6C00DAC6D9 /* Project object */ = { 322 | isa = PBXProject; 323 | attributes = { 324 | LastSwiftUpdateCheck = 1200; 325 | LastUpgradeCheck = 1200; 326 | TargetAttributes = { 327 | 30BFC8C924B75E6C00DAC6D9 = { 328 | CreatedOnToolsVersion = 12.0; 329 | }; 330 | 9CD7F11A24B89C5000DDAD8C = { 331 | CreatedOnToolsVersion = 12.0; 332 | TestTargetID = 30BFC8C924B75E6C00DAC6D9; 333 | }; 334 | }; 335 | }; 336 | buildConfigurationList = 30BFC8C524B75E6C00DAC6D9 /* Build configuration list for PBXProject "Project SF" */; 337 | compatibilityVersion = "Xcode 9.3"; 338 | developmentRegion = en; 339 | hasScannedForEncodings = 0; 340 | knownRegions = ( 341 | en, 342 | Base, 343 | ); 344 | mainGroup = 30BFC8C124B75E6C00DAC6D9; 345 | productRefGroup = 30BFC8CB24B75E6C00DAC6D9 /* Products */; 346 | projectDirPath = ""; 347 | projectRoot = ""; 348 | targets = ( 349 | 30BFC8C924B75E6C00DAC6D9 /* Project SF */, 350 | 9CD7F11A24B89C5000DDAD8C /* Project SFTests */, 351 | ); 352 | }; 353 | /* End PBXProject section */ 354 | 355 | /* Begin PBXResourcesBuildPhase section */ 356 | 30BFC8C824B75E6C00DAC6D9 /* Resources */ = { 357 | isa = PBXResourcesBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | 30BFC8D524B75E6F00DAC6D9 /* Preview Assets.xcassets in Resources */, 361 | 30BFC8D224B75E6F00DAC6D9 /* Assets.xcassets in Resources */, 362 | ); 363 | runOnlyForDeploymentPostprocessing = 0; 364 | }; 365 | 9CD7F11924B89C5000DDAD8C /* Resources */ = { 366 | isa = PBXResourcesBuildPhase; 367 | buildActionMask = 2147483647; 368 | files = ( 369 | ); 370 | runOnlyForDeploymentPostprocessing = 0; 371 | }; 372 | /* End PBXResourcesBuildPhase section */ 373 | 374 | /* Begin PBXShellScriptBuildPhase section */ 375 | 9CD6F92B24B7E9C400F167FC /* Run SwiftLint */ = { 376 | isa = PBXShellScriptBuildPhase; 377 | buildActionMask = 2147483647; 378 | files = ( 379 | ); 380 | inputFileListPaths = ( 381 | ); 382 | inputPaths = ( 383 | ); 384 | name = "Run SwiftLint"; 385 | outputFileListPaths = ( 386 | ); 387 | outputPaths = ( 388 | ); 389 | runOnlyForDeploymentPostprocessing = 0; 390 | shellPath = /bin/sh; 391 | shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; 392 | }; 393 | /* End PBXShellScriptBuildPhase section */ 394 | 395 | /* Begin PBXSourcesBuildPhase section */ 396 | 30BFC8C624B75E6C00DAC6D9 /* Sources */ = { 397 | isa = PBXSourcesBuildPhase; 398 | buildActionMask = 2147483647; 399 | files = ( 400 | 308FAD9E24B9A0DC00126F3F /* NavigationLabel.swift in Sources */, 401 | 9C7B4D0824B89AF100FC4456 /* Double+ConvertFromRangeToRange.swift in Sources */, 402 | 30BFC8D024B75E6C00DAC6D9 /* ContentView.swift in Sources */, 403 | 308FAD9424B989DE00126F3F /* CompetitionsView.swift in Sources */, 404 | 30BFC8CE24B75E6C00DAC6D9 /* ProjectSFApp.swift in Sources */, 405 | 9CCFDD1F24B971D600162B0F /* NetworkManager.swift in Sources */, 406 | 9CCFDD2624B9753F00162B0F /* Main.swift in Sources */, 407 | 30BFC8E924B804CC00DAC6D9 /* ActivityRing.swift in Sources */, 408 | 30BFC8DF24B7637F00DAC6D9 /* VisualEffectView.swift in Sources */, 409 | 9CCFDD1D24B971D600162B0F /* User.swift in Sources */, 410 | 308FAD8D24B97E8A00126F3F /* PrivacyView.swift in Sources */, 411 | 308FAD8B24B97E7E00126F3F /* InfoCell.swift in Sources */, 412 | 308FAD9124B987F000126F3F /* SignIn.swift in Sources */, 413 | 9CCFDD1E24B971D600162B0F /* CloudKitStore.swift in Sources */, 414 | 30F1EA3B24B951CA00FF89FC /* IntroView.swift in Sources */, 415 | 9CCFDD2024B971D600162B0F /* HealthKitController.swift in Sources */, 416 | 308FAD9624B989EF00126F3F /* TeamsView.swift in Sources */, 417 | 9C7B4D0624B89AC700FC4456 /* View+ForegroundModifier.swift in Sources */, 418 | 30BFC8E724B8041C00DAC6D9 /* ActivityRings.swift in Sources */, 419 | 308FAD9C24B99AA700126F3F /* ProfileSettingsView.swift in Sources */, 420 | 3090918224B9480F000E3B11 /* RoundedButton.swift in Sources */, 421 | 9CCFDD2424B9745E00162B0F /* UIApplication+IsTesting.swift in Sources */, 422 | 9CCFDD2824B9758A00162B0F /* TestApp.swift in Sources */, 423 | 308FAD9824B989FF00126F3F /* SettingsView.swift in Sources */, 424 | ); 425 | runOnlyForDeploymentPostprocessing = 0; 426 | }; 427 | 9CD7F11724B89C5000DDAD8C /* Sources */ = { 428 | isa = PBXSourcesBuildPhase; 429 | buildActionMask = 2147483647; 430 | files = ( 431 | 9CCFDD0724B95E9600162B0F /* URLSessionMock.swift in Sources */, 432 | 9CD7F11E24B89C5000DDAD8C /* Project_SFTests.swift in Sources */, 433 | ); 434 | runOnlyForDeploymentPostprocessing = 0; 435 | }; 436 | /* End PBXSourcesBuildPhase section */ 437 | 438 | /* Begin PBXTargetDependency section */ 439 | 9CD7F12124B89C5000DDAD8C /* PBXTargetDependency */ = { 440 | isa = PBXTargetDependency; 441 | target = 30BFC8C924B75E6C00DAC6D9 /* Project SF */; 442 | targetProxy = 9CD7F12024B89C5000DDAD8C /* PBXContainerItemProxy */; 443 | }; 444 | /* End PBXTargetDependency section */ 445 | 446 | /* Begin XCBuildConfiguration section */ 447 | 30BFC8D724B75E6F00DAC6D9 /* Debug */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | ALWAYS_SEARCH_USER_PATHS = NO; 451 | CLANG_ANALYZER_NONNULL = YES; 452 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 453 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 454 | CLANG_CXX_LIBRARY = "libc++"; 455 | CLANG_ENABLE_MODULES = YES; 456 | CLANG_ENABLE_OBJC_ARC = YES; 457 | CLANG_ENABLE_OBJC_WEAK = YES; 458 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 459 | CLANG_WARN_BOOL_CONVERSION = YES; 460 | CLANG_WARN_COMMA = YES; 461 | CLANG_WARN_CONSTANT_CONVERSION = YES; 462 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 463 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 464 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 465 | CLANG_WARN_EMPTY_BODY = YES; 466 | CLANG_WARN_ENUM_CONVERSION = YES; 467 | CLANG_WARN_INFINITE_RECURSION = YES; 468 | CLANG_WARN_INT_CONVERSION = YES; 469 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 470 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 471 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 472 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 473 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 474 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 475 | CLANG_WARN_STRICT_PROTOTYPES = YES; 476 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 477 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 478 | CLANG_WARN_UNREACHABLE_CODE = YES; 479 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 480 | COPY_PHASE_STRIP = NO; 481 | DEBUG_INFORMATION_FORMAT = dwarf; 482 | ENABLE_STRICT_OBJC_MSGSEND = YES; 483 | ENABLE_TESTABILITY = YES; 484 | GCC_C_LANGUAGE_STANDARD = gnu11; 485 | GCC_DYNAMIC_NO_PIC = NO; 486 | GCC_NO_COMMON_BLOCKS = YES; 487 | GCC_OPTIMIZATION_LEVEL = 0; 488 | GCC_PREPROCESSOR_DEFINITIONS = ( 489 | "DEBUG=1", 490 | "$(inherited)", 491 | ); 492 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 493 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 494 | GCC_WARN_UNDECLARED_SELECTOR = YES; 495 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 496 | GCC_WARN_UNUSED_FUNCTION = YES; 497 | GCC_WARN_UNUSED_VARIABLE = YES; 498 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 499 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 500 | MTL_FAST_MATH = YES; 501 | ONLY_ACTIVE_ARCH = YES; 502 | SDKROOT = iphoneos; 503 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 504 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 505 | }; 506 | name = Debug; 507 | }; 508 | 30BFC8D824B75E6F00DAC6D9 /* Release */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | ALWAYS_SEARCH_USER_PATHS = NO; 512 | CLANG_ANALYZER_NONNULL = YES; 513 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 514 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 515 | CLANG_CXX_LIBRARY = "libc++"; 516 | CLANG_ENABLE_MODULES = YES; 517 | CLANG_ENABLE_OBJC_ARC = YES; 518 | CLANG_ENABLE_OBJC_WEAK = YES; 519 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 520 | CLANG_WARN_BOOL_CONVERSION = YES; 521 | CLANG_WARN_COMMA = YES; 522 | CLANG_WARN_CONSTANT_CONVERSION = YES; 523 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 524 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 525 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 526 | CLANG_WARN_EMPTY_BODY = YES; 527 | CLANG_WARN_ENUM_CONVERSION = YES; 528 | CLANG_WARN_INFINITE_RECURSION = YES; 529 | CLANG_WARN_INT_CONVERSION = YES; 530 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 531 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 532 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 533 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 534 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 535 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 536 | CLANG_WARN_STRICT_PROTOTYPES = YES; 537 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 538 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 539 | CLANG_WARN_UNREACHABLE_CODE = YES; 540 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 541 | COPY_PHASE_STRIP = NO; 542 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 543 | ENABLE_NS_ASSERTIONS = NO; 544 | ENABLE_STRICT_OBJC_MSGSEND = YES; 545 | GCC_C_LANGUAGE_STANDARD = gnu11; 546 | GCC_NO_COMMON_BLOCKS = YES; 547 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 548 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 549 | GCC_WARN_UNDECLARED_SELECTOR = YES; 550 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 551 | GCC_WARN_UNUSED_FUNCTION = YES; 552 | GCC_WARN_UNUSED_VARIABLE = YES; 553 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 554 | MTL_ENABLE_DEBUG_INFO = NO; 555 | MTL_FAST_MATH = YES; 556 | SDKROOT = iphoneos; 557 | SWIFT_COMPILATION_MODE = wholemodule; 558 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 559 | VALIDATE_PRODUCT = YES; 560 | }; 561 | name = Release; 562 | }; 563 | 30BFC8DA24B75E6F00DAC6D9 /* Debug */ = { 564 | isa = XCBuildConfiguration; 565 | buildSettings = { 566 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 567 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 568 | CODE_SIGN_ENTITLEMENTS = "Project SF/Project SF.entitlements"; 569 | CODE_SIGN_STYLE = Automatic; 570 | DEVELOPMENT_ASSET_PATHS = "\"Project SF/Preview Content\""; 571 | DEVELOPMENT_TEAM = W9K99K5JN4; 572 | ENABLE_PREVIEWS = YES; 573 | INFOPLIST_FILE = "Project SF/Info.plist"; 574 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 575 | LD_RUNPATH_SEARCH_PATHS = ( 576 | "$(inherited)", 577 | "@executable_path/Frameworks", 578 | ); 579 | PRODUCT_BUNDLE_IDENTIFIER = com.RomanEsin.ProjectSF; 580 | PRODUCT_NAME = "$(TARGET_NAME)"; 581 | SWIFT_VERSION = 5.0; 582 | TARGETED_DEVICE_FAMILY = "1,2"; 583 | }; 584 | name = Debug; 585 | }; 586 | 30BFC8DB24B75E6F00DAC6D9 /* Release */ = { 587 | isa = XCBuildConfiguration; 588 | buildSettings = { 589 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 590 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 591 | CODE_SIGN_ENTITLEMENTS = "Project SF/Project SF.entitlements"; 592 | CODE_SIGN_STYLE = Automatic; 593 | DEVELOPMENT_ASSET_PATHS = "\"Project SF/Preview Content\""; 594 | DEVELOPMENT_TEAM = W9K99K5JN4; 595 | ENABLE_PREVIEWS = YES; 596 | INFOPLIST_FILE = "Project SF/Info.plist"; 597 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 598 | LD_RUNPATH_SEARCH_PATHS = ( 599 | "$(inherited)", 600 | "@executable_path/Frameworks", 601 | ); 602 | PRODUCT_BUNDLE_IDENTIFIER = com.RomanEsin.ProjectSF; 603 | PRODUCT_NAME = "$(TARGET_NAME)"; 604 | SWIFT_VERSION = 5.0; 605 | TARGETED_DEVICE_FAMILY = "1,2"; 606 | }; 607 | name = Release; 608 | }; 609 | 9CD7F12224B89C5000DDAD8C /* Debug */ = { 610 | isa = XCBuildConfiguration; 611 | buildSettings = { 612 | BUNDLE_LOADER = "$(TEST_HOST)"; 613 | CODE_SIGN_STYLE = Automatic; 614 | DEVELOPMENT_TEAM = W9K99K5JN4; 615 | INFOPLIST_FILE = "Project SFTests/Info.plist"; 616 | LD_RUNPATH_SEARCH_PATHS = ( 617 | "$(inherited)", 618 | "@executable_path/Frameworks", 619 | "@loader_path/Frameworks", 620 | ); 621 | PRODUCT_BUNDLE_IDENTIFIER = "au.com.wttech.Project-SFTests"; 622 | PRODUCT_NAME = "$(TARGET_NAME)"; 623 | SWIFT_VERSION = 5.0; 624 | TARGETED_DEVICE_FAMILY = "1,2"; 625 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Project SF.app/Project SF"; 626 | }; 627 | name = Debug; 628 | }; 629 | 9CD7F12324B89C5000DDAD8C /* Release */ = { 630 | isa = XCBuildConfiguration; 631 | buildSettings = { 632 | BUNDLE_LOADER = "$(TEST_HOST)"; 633 | CODE_SIGN_STYLE = Automatic; 634 | DEVELOPMENT_TEAM = W9K99K5JN4; 635 | INFOPLIST_FILE = "Project SFTests/Info.plist"; 636 | LD_RUNPATH_SEARCH_PATHS = ( 637 | "$(inherited)", 638 | "@executable_path/Frameworks", 639 | "@loader_path/Frameworks", 640 | ); 641 | PRODUCT_BUNDLE_IDENTIFIER = "au.com.wttech.Project-SFTests"; 642 | PRODUCT_NAME = "$(TARGET_NAME)"; 643 | SWIFT_VERSION = 5.0; 644 | TARGETED_DEVICE_FAMILY = "1,2"; 645 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Project SF.app/Project SF"; 646 | }; 647 | name = Release; 648 | }; 649 | /* End XCBuildConfiguration section */ 650 | 651 | /* Begin XCConfigurationList section */ 652 | 30BFC8C524B75E6C00DAC6D9 /* Build configuration list for PBXProject "Project SF" */ = { 653 | isa = XCConfigurationList; 654 | buildConfigurations = ( 655 | 30BFC8D724B75E6F00DAC6D9 /* Debug */, 656 | 30BFC8D824B75E6F00DAC6D9 /* Release */, 657 | ); 658 | defaultConfigurationIsVisible = 0; 659 | defaultConfigurationName = Release; 660 | }; 661 | 30BFC8D924B75E6F00DAC6D9 /* Build configuration list for PBXNativeTarget "Project SF" */ = { 662 | isa = XCConfigurationList; 663 | buildConfigurations = ( 664 | 30BFC8DA24B75E6F00DAC6D9 /* Debug */, 665 | 30BFC8DB24B75E6F00DAC6D9 /* Release */, 666 | ); 667 | defaultConfigurationIsVisible = 0; 668 | defaultConfigurationName = Release; 669 | }; 670 | 9CD7F12424B89C5000DDAD8C /* Build configuration list for PBXNativeTarget "Project SFTests" */ = { 671 | isa = XCConfigurationList; 672 | buildConfigurations = ( 673 | 9CD7F12224B89C5000DDAD8C /* Debug */, 674 | 9CD7F12324B89C5000DDAD8C /* Release */, 675 | ); 676 | defaultConfigurationIsVisible = 0; 677 | defaultConfigurationName = Release; 678 | }; 679 | /* End XCConfigurationList section */ 680 | }; 681 | rootObject = 30BFC8C224B75E6C00DAC6D9 /* Project object */; 682 | } 683 | --------------------------------------------------------------------------------