├── .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 |   
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 |
--------------------------------------------------------------------------------