From cc3b1777569104d3f89b144064730a4c3c77375e Mon Sep 17 00:00:00 2001
From: Peter Nash <480796+pablonosh@users.noreply.github.com>
Date: Tue, 6 Jun 2023 20:24:57 +0100
Subject: [PATCH 1/2] after tidy up
---
.../contents.xcworkspacedata | 4 -
.../AccentColor.colorset/Contents.json | 4 +
FitCount/ContentView.swift | 22 +-
FitCount/FitCountApp.swift | 4 +-
FitCount/History/HistoryView.swift | 2 +-
.../Preview Assets.xcassets/Contents.json | 6 -
FitCount/Workout/BoundingBoxView.swift | 42 --
FitCount/Workout/ExerciseDetailsView.swift | 6 +-
FitCount/Workout/InstructionsView.swift | 6 -
FitCount/Workout/QuickPoseBasicView.swift | 358 +++++++++---------
FitCount/Workout/VolumeChangeView.swift | 61 ++-
FitCount/Workout/Workout.swift | 14 -
FitCount/Workout/WorkoutResultsView.swift | 9 +-
FitCountTests/FitCountTests.swift | 36 --
FitCountUITests/FitCountUITests.swift | 41 --
.../FitCountUITestsLaunchTests.swift | 32 --
.../project.pbxproj | 272 +------------
.../xcshareddata/swiftpm/Package.resolved | 2 +-
.../xcschemes/FitCounter.xcscheme | 5 +-
19 files changed, 244 insertions(+), 682 deletions(-)
delete mode 100644 FitCount.xcodeproj/project.xcworkspace/contents.xcworkspacedata
delete mode 100644 FitCount/Preview Content/Preview Assets.xcassets/Contents.json
delete mode 100644 FitCount/Workout/BoundingBoxView.swift
delete mode 100644 FitCount/Workout/Workout.swift
delete mode 100644 FitCountTests/FitCountTests.swift
delete mode 100644 FitCountUITests/FitCountUITests.swift
delete mode 100644 FitCountUITests/FitCountUITestsLaunchTests.swift
diff --git a/FitCount.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/FitCount.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 94b2795..0000000
--- a/FitCount.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/FitCount/Assets.xcassets/AccentColor.colorset/Contents.json b/FitCount/Assets.xcassets/AccentColor.colorset/Contents.json
index eb87897..4bf40ac 100644
--- a/FitCount/Assets.xcassets/AccentColor.colorset/Contents.json
+++ b/FitCount/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -1,6 +1,10 @@
{
"colors" : [
{
+ "color" : {
+ "platform" : "universal",
+ "reference" : "systemIndigoColor"
+ },
"idiom" : "universal"
}
],
diff --git a/FitCount/ContentView.swift b/FitCount/ContentView.swift
index 755778a..451f5d6 100644
--- a/FitCount/ContentView.swift
+++ b/FitCount/ContentView.swift
@@ -12,15 +12,13 @@ class SessionConfig: ObservableObject {
@Published var nReps : Int = 1
@Published var nMinutes : Int = 0
@Published var nSeconds : Int = 1
-
@Published var useReps: Bool = true
@Published var exercise: Exercise = exercises[0] // use first exercise by default but change in the ExerciseDetailsView
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
- @StateObject var sessionConfig: SessionConfig = SessionConfig()
-
+ @StateObject var sessionConfig = SessionConfig()
var body: some View {
NavigationStack(path: $viewModel.path) {
@@ -34,9 +32,11 @@ struct ContentView: View {
.font(.headline)
}
.padding()
- .cornerRadius(8) // Add corner radius for a rounded look
+ .cornerRadius(8)
}.navigationDestination(for: Exercise.self) { exercise in
- ExerciseDetailsView(exercise: exercise).environmentObject(viewModel).environmentObject(sessionConfig)
+ ExerciseDetailsView(exercise: exercise)
+ .environmentObject(viewModel)
+ .environmentObject(sessionConfig)
}
}
.background(.white)
@@ -60,13 +60,9 @@ struct ContentView: View {
class ViewModel: ObservableObject {
- @Published var path: NavigationPath = NavigationPath()
-}
-
-struct ContentView_Previews: PreviewProvider {
- static var previews: some View {
- ContentView()
+ @Published var path = NavigationPath()
+
+ func popToRoot(){
+ path.removeLast(path.count) // pop to root
}
}
-
-
diff --git a/FitCount/FitCountApp.swift b/FitCount/FitCountApp.swift
index a6df980..4abf301 100644
--- a/FitCount/FitCountApp.swift
+++ b/FitCount/FitCountApp.swift
@@ -19,9 +19,9 @@ struct Exercise: Identifiable, Hashable {
let exercises = [
Exercise(
- name: "Biceps Curls",
+ name: "Bicep Curls",
details: "Lift weights in both hands by bending your elbow and lifting them towards your shoulder.",
- features: [.fitness(.bicepsCurls), .overlay(.upperBody)]
+ features: [.fitness(.bicepCurls), .overlay(.upperBody)]
),
Exercise(
name: "Squats",
diff --git a/FitCount/History/HistoryView.swift b/FitCount/History/HistoryView.swift
index b3ad65b..a1455ae 100644
--- a/FitCount/History/HistoryView.swift
+++ b/FitCount/History/HistoryView.swift
@@ -25,7 +25,7 @@ struct HistoryView: View {
Text(sessionData.exercise)
.font(.title)
.fontWeight(.bold)
- .foregroundColor(.indigo)
+ .foregroundColor(Color("AccentColor"))
Text(sessionData.date.formatted(
.dateTime
diff --git a/FitCount/Preview Content/Preview Assets.xcassets/Contents.json b/FitCount/Preview Content/Preview Assets.xcassets/Contents.json
deleted file mode 100644
index 73c0059..0000000
--- a/FitCount/Preview Content/Preview Assets.xcassets/Contents.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/FitCount/Workout/BoundingBoxView.swift b/FitCount/Workout/BoundingBoxView.swift
deleted file mode 100644
index ba7531f..0000000
--- a/FitCount/Workout/BoundingBoxView.swift
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// BoundingBoxView.swift
-// FitCount
-//
-// Created by QuickPose.ai on 25.05.2023.
-//
-
-import SwiftUI
-
-struct BoundingBoxView: View {
- var isInBBox: Bool
- var indicatorWidth: Double
-
- init(isInBBox:Bool, indicatorWidth: Double) {
- self.isInBBox = isInBBox
- self.indicatorWidth = indicatorWidth
- }
-
- var body: some View {
- GeometryReader { geometry in
- VStack {
- RoundedRectangle(cornerRadius: 15)
- .stroke(isInBBox ? Color.green : Color.red, lineWidth: 5)
- .frame(width: geometry.size.width * 0.6, height: geometry.size.height * 0.8)
- .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
-
- }
- }.overlay(
- GeometryReader { geometry in
- VStack {
- if (indicatorWidth > 0) {
- RoundedRectangle(cornerRadius: 15)
- .fill(.green.opacity(0.5))
- .frame(width: geometry.size.width * 0.6 * indicatorWidth, height: geometry.size.height * 0.8)
- .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
- }
- }
- }
- )
-
- }
-}
diff --git a/FitCount/Workout/ExerciseDetailsView.swift b/FitCount/Workout/ExerciseDetailsView.swift
index 78ab09c..892593d 100644
--- a/FitCount/Workout/ExerciseDetailsView.swift
+++ b/FitCount/Workout/ExerciseDetailsView.swift
@@ -8,7 +8,6 @@
import SwiftUI
import PagerTabStripView
-
struct TitleNavBarItem: View {
let title: String
@@ -36,7 +35,6 @@ struct ExerciseDetailsView: View {
.font(.body)
.padding()
-
Spacer()
PagerTabStripView(
@@ -117,8 +115,8 @@ struct ExerciseDetailsView: View {
Text("Start workout")
.foregroundColor(.white)
.padding()
- .background(.indigo) // Set background color to the main color
- .cornerRadius(8) // Add corner radius for a rounded look
+ .background(Color("AccentColor"))
+ .cornerRadius(8)
}
.navigationDestination(for: String.self) { _ in
diff --git a/FitCount/Workout/InstructionsView.swift b/FitCount/Workout/InstructionsView.swift
index 3a6fa75..9462a17 100644
--- a/FitCount/Workout/InstructionsView.swift
+++ b/FitCount/Workout/InstructionsView.swift
@@ -31,9 +31,3 @@ struct InstructionsView: View {
}
}
-
-struct InstructionsView_Previews: PreviewProvider {
- static var previews: some View {
- InstructionsView()
- }
-}
diff --git a/FitCount/Workout/QuickPoseBasicView.swift b/FitCount/Workout/QuickPoseBasicView.swift
index 0b1889b..5c5034a 100644
--- a/FitCount/Workout/QuickPoseBasicView.swift
+++ b/FitCount/Workout/QuickPoseBasicView.swift
@@ -8,21 +8,34 @@
import SwiftUI
import QuickPoseCore
import QuickPoseSwiftUI
+import AVFoundation
-struct VoiceCommands {
- public static let standInsideBBox = "Stand so that your whole body is inside the bounding box"
+struct SessionData: Equatable {
+ let count: Int
+ let seconds: Int
}
-class SessionData: ObservableObject {
- @Published var count = 0
- @Published var seconds = 0
-}
-
-enum WorkoutState {
- case volume
+enum ViewState: Equatable {
+ case startVolume
case instructions
- case bbox
- case exercise
+ case introBoundingBox
+ case boundingBox(enterTime: Date)
+ case introExercise(Exercise)
+ case exercise(SessionData, enterTime: Date)
+ case results(SessionData)
+
+ var speechPrompt: String? {
+ switch self {
+ case .introBoundingBox:
+ return "Stand so that your whole body is inside the bounding box"
+ case .introExercise(let exercise):
+ return "Now let's start the \(exercise.name) exercise"
+ case .exercise(let results, _):
+ return "\(results.count)"
+ default:
+ return nil
+ }
+ }
}
struct QuickPoseBasicView: View {
@@ -31,48 +44,25 @@ struct QuickPoseBasicView: View {
@EnvironmentObject var sessionConfig: SessionConfig
@State private var overlayImage: UIImage?
-
@State private var feedbackText: String? = nil
- @State var counter = QuickPoseThresholdCounter()
- @State var measure: Double = 0
- @State var count: Int = 0
- @State var seconds: Int = 0
- let exerciseTimer = TimerManager()
-
- @State var isInBBox = false
- @State var state = WorkoutState.volume
-
- @State private var indicatorWidth: CGFloat = 0.0
-
- @StateObject var sessionData = SessionData()
-
- @State var countScale = 1.0
-
- @State private var isActive: Bool = false
+ @State private var counter = QuickPoseThresholdCounter()
+ @State private var state: ViewState = .startVolume
- let bboxTimer = TimerManager()
-
- func goToResults() {
- DispatchQueue.main.async {
- sessionData.seconds = Int(exerciseTimer.getTotalSeconds())
- sessionData.count = Int(counter.getCount())
-
- isActive = true // Set the state variable to trigger the navigation
- }
+ @State private var countScale = 1.0
+ @State private var boundingBoxMaskWidth = 0.0
+
+ func canMoveFromBoundingBox(landmarks: QuickPose.Landmarks) -> Bool {
+
+ let xsInBox = landmarks.poseLandmarks.allSatisfy { 0.5 - (0.6/2) < $0[0] && $0[0] < 0.5 + (0.6/2) }
+ let ysInBox = landmarks.poseLandmarks.allSatisfy { 0.5 - (0.8/2) < $0[1] && $0[1] < 0.5 + (0.8/2) }
+
+ return xsInBox && ysInBox
}
var body: some View {
- VStack{
- NavigationLink(value: "Workout results") {
- EmptyView()
- }.navigationDestination(isPresented: $isActive) {
- WorkoutResultsView()
- .environmentObject(sessionData)
- .environmentObject(viewModel)
- }
-
- GeometryReader { geometry in
+ GeometryReader { geometry in
+ VStack {
ZStack(alignment: .top) {
QuickPoseCameraView(useFrontCamera: true, delegate: quickPose)
QuickPoseOverlayView(overlayImage: $overlayImage)
@@ -80,68 +70,97 @@ struct QuickPoseBasicView: View {
.frame(width: geometry.safeAreaInsets.leading + geometry.size.width + geometry.safeAreaInsets.trailing)
.edgesIgnoringSafeArea(.all)
.overlay() {
- if (state == WorkoutState.volume) {
- VolumeChangeView().overlay(alignment: .bottom) {
- Button (action: {
- state = WorkoutState.instructions
-
- }) {
- Text("Continue").foregroundColor(.white)
- .padding()
- .background(.indigo) // Set background color to the main color
- .cornerRadius(8) // Add corner radius for a rounded look
+ switch state {
+ case .startVolume:
+ VolumeChangeView()
+ .overlay(alignment: .bottom) {
+ Button (action: {
+ state = .instructions
+ }) {
+ Text("Continue").foregroundColor(.white)
+ .padding()
+ .background(Color("AccentColor"))
+ .cornerRadius(8)
+ }
}
- }
- }
-
- if (state == WorkoutState.instructions) {
- InstructionsView().overlay(alignment: .bottom) {
- Button (action: {
- state = WorkoutState.bbox
- Text2Speech(text: VoiceCommands.standInsideBBox).say()
- }) {
- Text("Start Workout").foregroundColor(.white)
- .padding()
- .background(.indigo) // Set background color to the main color
- .cornerRadius(8) // Add corner radius for a rounded look
+ case .instructions:
+ InstructionsView()
+ .overlay(alignment: .bottom) {
+ Button (action: {
+ state = .introBoundingBox
+ }) {
+ Text("Start Workout").foregroundColor(.white)
+ .padding()
+ .background(Color("AccentColor"))
+ .cornerRadius(8)
}
+ }
+ case .introBoundingBox:
+ ZStack {
+ RoundedRectangle(cornerRadius: 15)
+ .stroke(.red, lineWidth: 5)
}
- }
-
- if (state == WorkoutState.bbox) {
- BoundingBoxView(isInBBox: isInBBox, indicatorWidth: indicatorWidth)
+ .frame(width: geometry.size.width * 0.6, height: geometry.size.height * 0.8)
+ .padding(.horizontal, (geometry.size.width * 1 - 0.6)/2)
+
+ case .boundingBox:
+ ZStack {
+ RoundedRectangle(cornerRadius: 15)
+ .stroke(.green, lineWidth: 5)
+
+ RoundedRectangle(cornerRadius: 15)
+ .fill(.green.opacity(0.5))
+ .mask(alignment: .leading) {
+ Rectangle()
+ .frame(width: geometry.size.width * 0.6 * boundingBoxMaskWidth)
+ }
+ }
+ .frame(width: geometry.size.width * 0.6, height: geometry.size.height * 0.8)
+ .padding(.horizontal, (geometry.size.width * 1 - 0.6)/2)
+
+ case .results(let results):
+ WorkoutResultsView(sessionData: results)
+ .environmentObject(viewModel)
+
+ default:
+ EmptyView()
}
}
+
.overlay(alignment: .topTrailing) {
Button(action: {
- goToResults()
+ if case .results = state {
+ viewModel.popToRoot()
+ } else {
+ state = .results(SessionData(count: counter.state.count, seconds: 0))
+ }
}) {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 44))
- .foregroundColor(.indigo)
+ .foregroundColor(Color("AccentColor"))
}
.padding()
}
-
+
.overlay(alignment: .bottom) {
- if (state == WorkoutState.exercise) {
+ if case .exercise(let results, let enterTime) = state {
HStack {
- Text(String(count) + (sessionConfig.useReps ? " \\ " + String(sessionConfig.nReps) : "") + " reps")
+ Text(String(results.count) + (sessionConfig.useReps ? " \\ " + String(sessionConfig.nReps) : "") + " reps")
.font(.system(size: 30, weight: .semibold))
.padding(16)
.scaleEffect(countScale)
-
- Text(String(seconds) + (!sessionConfig.useReps ? " \\ " + String(sessionConfig.nSeconds + sessionConfig.nMinutes * 60) : "") + " sec")
+
+ Text(String(format: "%.0f",-enterTime.timeIntervalSinceNow) + (!sessionConfig.useReps ? " \\ " + String(sessionConfig.nSeconds + sessionConfig.nMinutes * 60) : "") + " sec")
.font(.system(size: 30, weight: .semibold))
.padding(16)
}
.frame(maxWidth: .infinity)
.foregroundColor(.white)
- .background(.indigo)
+ .background(Color("AccentColor"))
}
}
.overlay(alignment: .center) {
- if (state == WorkoutState.exercise) {
+ if case .exercise = state {
if let feedbackText = feedbackText {
Text(feedbackText)
.font(.system(size: 26, weight: .semibold)).foregroundColor(.white)
@@ -149,108 +168,105 @@ struct QuickPoseBasicView: View {
}
}
}
- .onAppear {
- quickPose.start(features: sessionConfig.exercise.features, onFrame: { status, image, features, feedback, landmarks in
-
-
-
- let width = geometry.size.width * 0.6
- let height = geometry.size.height * 0.8
- let x0 = geometry.size.width / 2
- let y0 = geometry.size.height / 2
-
- // all xs in [x0 - (width/2), x0 + (width/2)]
- // all ys in [y0 - (height/2), y0 + (height/2)]
-
- let scaleToView = CGAffineTransform(scaleX: geometry.size.width, y:geometry.size.height)
-
- if (state == WorkoutState.bbox && landmarks != nil) {
- let scaledLandmarks = landmarks!.poseLandmarks.map {
- let point = CGPoint(x: $0[0], y: $0[1]).applying(scaleToView)
- return [point.x, point.y, $0[2]]
- }
-
- let xsInBox = scaledLandmarks.allSatisfy { x0 - (width/2) < $0[0] && $0[0] < x0 + (width/2) }
- let ysInBox = scaledLandmarks.allSatisfy { y0 - (height/2) < $0[1] && $0[1] < y0 + (height/2) }
-
- isInBBox = xsInBox && ysInBox
- }
-
- if (!isInBBox && bboxTimer.isRunning()) {
- bboxTimer.pause()
- bboxTimer.reset()
- indicatorWidth = 0
- }
-
- if (isInBBox && !bboxTimer.isRunning()) {
- bboxTimer.start()
- }
-
- if (bboxTimer.isRunning()) {
- indicatorWidth = bboxTimer.getTotalSeconds() / 2
- }
-
- if (bboxTimer.isRunning() && bboxTimer.getTotalSeconds() > 2) {
- bboxTimer.pause()
- bboxTimer.reset()
-
- state = WorkoutState.exercise
- }
-
- if (state == WorkoutState.exercise && !exerciseTimer.isRunning()) {
- Text2Speech(text: "Now let's start the \(sessionConfig.exercise.name) exercise").say()
- exerciseTimer.start()
- }
-
- if (state == WorkoutState.exercise) {
- seconds = Int(exerciseTimer.getTotalSeconds())
-
- if let feedback = feedback[.fitness(.bicepsCurls)] {
- feedbackText = feedback.displayString
- } else {
- feedbackText = nil
- }
-
- if case .fitness = sessionConfig.exercise.features.first, let result = features[sessionConfig.exercise.features.first!]{
- counter.count(probability: result.value)
- if (counter.getCount() > count) {
- Text2Speech(text: String(counter.getCount())).say()
- withAnimation(.easeInOut(duration: 0.1)) {
- countScale = 2.0
+
+ .onChange(of: state) { _ in
+
+ if let speechPrompt = state.speechPrompt {
+ let utterance = AVSpeechUtterance(string: speechPrompt)
+ AVSpeechSynthesizer().speak(utterance)
+ }
+
+ if state == .introBoundingBox {
+ quickPose.start(features: sessionConfig.exercise.features, onFrame: { status, image, features, feedback, landmarks in
+ overlayImage = image
+ if case .success(_,_) = status {
+
+ switch state {
+ case .introBoundingBox:
+
+ if let landmarks = landmarks, canMoveFromBoundingBox(landmarks: landmarks) {
+
+ state = .boundingBox(enterTime: Date())
+ boundingBoxMaskWidth = 0
+ withAnimation(.easeInOut(duration: 2)) {
+ boundingBoxMaskWidth = 1.0
+ }
}
+ case .boundingBox(let enterDate):
+ if let landmarks = landmarks, canMoveFromBoundingBox(landmarks: landmarks) {
+ if -enterDate.timeIntervalSinceNow > 2 {
+ state = .introExercise(sessionConfig.exercise)
+ }
+ } else {
+ state = .introBoundingBox
+ }
+
+ case .introExercise(_):
DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
- withAnimation(.easeInOut(duration: 0.2)) {
- countScale = 1.0
+ state = .exercise(SessionData(count: 0, seconds: 0), enterTime: Date())
+ }
+ case .exercise(_, let enterDate):
+ let secondsElapsed = Int(-enterDate.timeIntervalSinceNow)
+
+ if let feedback = feedback[.fitness(.bicepCurls)] {
+ feedbackText = feedback.displayString
+ } else {
+ feedbackText = nil
+
+ if case .fitness = sessionConfig.exercise.features.first, let result = features[sessionConfig.exercise.features.first!] {
+ _ = counter.count(result.value) { newState in
+ if !newState.isEntered {
+ DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
+ withAnimation(.easeInOut(duration: 0.1)) {
+ countScale = 2.0
+ }
+ DispatchQueue.main.asyncAfter(deadline: .now()+0.4) {
+ withAnimation(.easeInOut(duration: 0.2)) {
+ countScale = 1.0
+ }
+ }
+ }
+ }
+ }
}
}
+
+ let newResults = SessionData(count: counter.state.count, seconds: secondsElapsed)
+ state = .exercise(newResults, enterTime: enterDate) // refresh view for every updated second
+ var hasFinished = false
+ if sessionConfig.useReps {
+ hasFinished = counter.state.count >= sessionConfig.nReps
+ } else {
+ hasFinished = secondsElapsed >= sessionConfig.nSeconds + sessionConfig.nMinutes * 60
+ }
+
+ if hasFinished {
+ state = .results(newResults)
+ }
+ default:
+ break
}
- count = counter.getCount()
-
- if (sessionConfig.useReps && count >= sessionConfig.nReps || !sessionConfig.useReps && Int(exerciseTimer.getTotalSeconds()) >= (sessionConfig.nSeconds + sessionConfig.nMinutes * 60)) {
- goToResults()
- }
- measure = result.value
+ } else {
+ state = .introBoundingBox
}
- }
- if case .success(_,_) = status {
- overlayImage = image
- } else {
- overlayImage = nil
- }
- })
- }.onAppear() {
+ })
+ }
+
+ if case .results(let result) = state {
+ let sessionDataDump = SessionDataModel(exercise: sessionConfig.exercise.name, count: result.count, seconds: result.seconds, date: Date())
+ appendToJson(sessionData: sessionDataDump)
+ }
+ }
+ .onAppear() {
UIApplication.shared.isIdleTimerDisabled = true
}
.onDisappear {
- let sessionDataDump = SessionDataModel(exercise: sessionConfig.exercise.name, count: Int(counter.getCount()), seconds: Int(exerciseTimer.getTotalSeconds()), date: Date())
- appendToJson(sessionData: sessionDataDump)
-
quickPose.stop()
UIApplication.shared.isIdleTimerDisabled = false
}
}
- }
.navigationBarBackButtonHidden(true)
.toolbar(.hidden, for: .tabBar)
+ }
}
}
diff --git a/FitCount/Workout/VolumeChangeView.swift b/FitCount/Workout/VolumeChangeView.swift
index ba37f20..ca6dc9e 100644
--- a/FitCount/Workout/VolumeChangeView.swift
+++ b/FitCount/Workout/VolumeChangeView.swift
@@ -9,33 +9,6 @@ import SwiftUI
import MediaPlayer
import AVFoundation
-
-func setSystemVolume(_ volume: Float) {
- let volumeView = MPVolumeView()
- let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider
-
- DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
- slider?.setValue(volume, animated: false)
- }
-}
-
-
-
-func getCurrentVolume() -> Float {
- let audioSession = AVAudioSession.sharedInstance()
-
- do {
- try audioSession.setActive(true)
-
- let volume = audioSession.outputVolume
- return volume
- } catch {
- print("Failed to get current volume: \(error)")
- return 0.0
- }
-}
-
-
struct VolumeChangeView: View {
@State private var soundLevel: Float = getCurrentVolume()
@@ -55,26 +28,46 @@ struct VolumeChangeView: View {
HStack {
Image(systemName: "speaker.wave.1")
.font(.system(size: 30))
- .foregroundColor(.indigo)
+ .foregroundColor(Color("AccentColor"))
Slider(value: $soundLevel, in: 0...1, step: 0.01, onEditingChanged: { data in
- setSystemVolume(self.soundLevel)
+ VolumeChangeView.setSystemVolume(self.soundLevel)
})
.tint(soundLevel < 0.5 ? .red : .green)
Image(systemName: "speaker.wave.3")
.font(.system(size: 30))
- .foregroundColor(.indigo)
+ .foregroundColor(Color("AccentColor"))
}
}.frame(width: 300)
)
}
}
-}
+
+ static func setSystemVolume(_ volume: Float) {
+ let volumeView = MPVolumeView()
+ let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider
+
+ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
+ slider?.setValue(volume, animated: false)
+ }
+ }
-struct VolumeChangeView_Previews: PreviewProvider {
- static var previews: some View {
- VolumeChangeView()
+ static func getCurrentVolume() -> Float {
+ let audioSession = AVAudioSession.sharedInstance()
+
+ do {
+ try audioSession.setActive(true)
+
+ let volume = audioSession.outputVolume
+ return volume
+ } catch {
+ print("Failed to get current volume: \(error)")
+ return 0.0
+ }
}
}
+
+
+
diff --git a/FitCount/Workout/Workout.swift b/FitCount/Workout/Workout.swift
deleted file mode 100644
index 52d83e8..0000000
--- a/FitCount/Workout/Workout.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Workout.swift
-// FitCount
-//
-// Created by QuickPose.ai on 25.05.2023.
-//
-
-import Foundation
-
-
-//class Workout {
-// var date: Date
-// var
-//}
diff --git a/FitCount/Workout/WorkoutResultsView.swift b/FitCount/Workout/WorkoutResultsView.swift
index c3cfb66..f6e1f2d 100644
--- a/FitCount/Workout/WorkoutResultsView.swift
+++ b/FitCount/Workout/WorkoutResultsView.swift
@@ -8,13 +8,14 @@
import SwiftUI
struct WorkoutResultsView: View {
- @EnvironmentObject var sessionData: SessionData
+ let sessionData: SessionData
+
@EnvironmentObject var viewModel: ViewModel
var body: some View {
NavigationView{
VStack(spacing: 20) {
- Text("Your workour results")
+ Text("Your workout results")
.font(.largeTitle)
.padding(.top, 50)
@@ -28,14 +29,14 @@ struct WorkoutResultsView: View {
.padding(.bottom, 40)
Button(action: {
- viewModel.path.removeLast(viewModel.path.count)
+ viewModel.popToRoot()
}) {
Text("Finish Workout")
.foregroundColor(.white)
.font(.title2)
.padding()
.frame(maxWidth: .infinity)
- .background(Color.indigo)
+ .background(Color("AccentColor"))
.cornerRadius(8)
}
.padding()
diff --git a/FitCountTests/FitCountTests.swift b/FitCountTests/FitCountTests.swift
deleted file mode 100644
index 0eb3c07..0000000
--- a/FitCountTests/FitCountTests.swift
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// FitCountTests.swift
-// FitCountTests
-//
-// Created by Денис Волхонский on 22.05.2023.
-//
-
-import XCTest
-@testable import FitCount
-
-final class FitCountTests: XCTestCase {
-
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
-
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
-
- func testExample() throws {
- // This is an example of a functional test case.
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- // Any test you write for XCTest can be annotated as throws and async.
- // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
- // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
- }
-
- func testPerformanceExample() throws {
- // This is an example of a performance test case.
- self.measure {
- // Put the code you want to measure the time of here.
- }
- }
-
-}
diff --git a/FitCountUITests/FitCountUITests.swift b/FitCountUITests/FitCountUITests.swift
deleted file mode 100644
index 4a2a4fa..0000000
--- a/FitCountUITests/FitCountUITests.swift
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// FitCountUITests.swift
-// FitCountUITests
-//
-// Created by Денис Волхонский on 22.05.2023.
-//
-
-import XCTest
-
-final class FitCountUITests: XCTestCase {
-
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
-
- // In UI tests it is usually best to stop immediately when a failure occurs.
- continueAfterFailure = false
-
- // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
- }
-
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
-
- func testExample() throws {
- // UI tests must launch the application that they test.
- let app = XCUIApplication()
- app.launch()
-
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- }
-
- func testLaunchPerformance() throws {
- if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
- // This measures how long it takes to launch your application.
- measure(metrics: [XCTApplicationLaunchMetric()]) {
- XCUIApplication().launch()
- }
- }
- }
-}
diff --git a/FitCountUITests/FitCountUITestsLaunchTests.swift b/FitCountUITests/FitCountUITestsLaunchTests.swift
deleted file mode 100644
index aa12e80..0000000
--- a/FitCountUITests/FitCountUITestsLaunchTests.swift
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// FitCountUITestsLaunchTests.swift
-// FitCountUITests
-//
-// Created by Денис Волхонский on 22.05.2023.
-//
-
-import XCTest
-
-final class FitCountUITestsLaunchTests: XCTestCase {
-
- override class var runsForEachTargetApplicationUIConfiguration: Bool {
- true
- }
-
- override func setUpWithError() throws {
- continueAfterFailure = false
- }
-
- func testLaunch() throws {
- let app = XCUIApplication()
- app.launch()
-
- // Insert steps here to perform after app launch but before taking a screenshot,
- // such as logging into a test account or navigating somewhere in the app
-
- let attachment = XCTAttachment(screenshot: app.screenshot())
- attachment.name = "Launch Screen"
- attachment.lifetime = .keepAlways
- add(attachment)
- }
-}
diff --git a/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj b/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj
index abbdd6e..9555aee 100644
--- a/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj
+++ b/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj
@@ -8,9 +8,7 @@
/* Begin PBXBuildFile section */
920A3EEC2A1F6E0E00EC6FC9 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920A3EEB2A1F6E0E00EC6FC9 /* Timer.swift */; };
- 920A3EEF2A1F76F800EC6FC9 /* BoundingBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920A3EEE2A1F76F800EC6FC9 /* BoundingBoxView.swift */; };
920A3EF12A1F7C2300EC6FC9 /* WorkoutResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920A3EF02A1F7C2300EC6FC9 /* WorkoutResultsView.swift */; };
- 920A3EF32A1F801A00EC6FC9 /* Workout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920A3EF22A1F801A00EC6FC9 /* Workout.swift */; };
920A3EF62A20B14100EC6FC9 /* PagerTabStripView in Frameworks */ = {isa = PBXBuildFile; productRef = 920A3EF52A20B14100EC6FC9 /* PagerTabStripView */; };
9215905F2A2A10BF001254BC /* InstructionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9215905E2A2A10BF001254BC /* InstructionsView.swift */; };
924D6E222A264B3600227183 /* JsonWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924D6E212A264B3600227183 /* JsonWriter.swift */; };
@@ -25,54 +23,24 @@
92CACFD12A1B7DD100DA2B40 /* FitCountApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFD02A1B7DD100DA2B40 /* FitCountApp.swift */; };
92CACFD32A1B7DD100DA2B40 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFD22A1B7DD100DA2B40 /* ContentView.swift */; };
92CACFD52A1B7DD100DA2B40 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92CACFD42A1B7DD100DA2B40 /* Assets.xcassets */; };
- 92CACFD82A1B7DD100DA2B40 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92CACFD72A1B7DD100DA2B40 /* Preview Assets.xcassets */; };
- 92CACFE22A1B7DD200DA2B40 /* FitCountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFE12A1B7DD200DA2B40 /* FitCountTests.swift */; };
- 92CACFEC2A1B7DD200DA2B40 /* FitCountUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFEB2A1B7DD200DA2B40 /* FitCountUITests.swift */; };
- 92CACFEE2A1B7DD200DA2B40 /* FitCountUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFED2A1B7DD200DA2B40 /* FitCountUITestsLaunchTests.swift */; };
92CACFFB2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFFA2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift */; };
92CACFFD2A1B99A500DA2B40 /* WorkoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFFC2A1B99A500DA2B40 /* WorkoutView.swift */; };
92F2D1FB2A1D0C8400EC1B81 /* Text2Speech.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F2D1FA2A1D0C8400EC1B81 /* Text2Speech.swift */; };
/* End PBXBuildFile section */
-/* Begin PBXContainerItemProxy section */
- 92CACFDE2A1B7DD200DA2B40 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 92CACFC52A1B7DD000DA2B40 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 92CACFCC2A1B7DD100DA2B40;
- remoteInfo = FitCount;
- };
- 92CACFE82A1B7DD200DA2B40 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 92CACFC52A1B7DD000DA2B40 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 92CACFCC2A1B7DD100DA2B40;
- remoteInfo = FitCount;
- };
-/* End PBXContainerItemProxy section */
-
/* Begin PBXFileReference section */
920A3EEB2A1F6E0E00EC6FC9 /* Timer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Timer.swift; sourceTree = ""; };
- 920A3EEE2A1F76F800EC6FC9 /* BoundingBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoundingBoxView.swift; sourceTree = ""; };
920A3EF02A1F7C2300EC6FC9 /* WorkoutResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutResultsView.swift; sourceTree = ""; };
- 920A3EF22A1F801A00EC6FC9 /* Workout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workout.swift; sourceTree = ""; };
9215905E2A2A10BF001254BC /* InstructionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionsView.swift; sourceTree = ""; };
924D6E212A264B3600227183 /* JsonWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsonWriter.swift; sourceTree = ""; };
924D6E242A289ED700227183 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; };
924D6E272A29F90400227183 /* VolumeChangeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VolumeChangeView.swift; sourceTree = ""; };
927261A32A24EF0B00C3B390 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = ""; };
92C702F82A1BC705002ECC0B /* QuickPoseBasicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickPoseBasicView.swift; sourceTree = ""; };
- 92C703032A1D049E002ECC0B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
92CACFCD2A1B7DD100DA2B40 /* FitCounter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FitCounter.app; sourceTree = BUILT_PRODUCTS_DIR; };
92CACFD02A1B7DD100DA2B40 /* FitCountApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FitCountApp.swift; sourceTree = ""; };
92CACFD22A1B7DD100DA2B40 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
92CACFD42A1B7DD100DA2B40 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- 92CACFD72A1B7DD100DA2B40 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
- 92CACFDD2A1B7DD200DA2B40 /* FitCountTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FitCountTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 92CACFE12A1B7DD200DA2B40 /* FitCountTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FitCountTests.swift; sourceTree = ""; };
- 92CACFE72A1B7DD200DA2B40 /* FitCountUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FitCountUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 92CACFEB2A1B7DD200DA2B40 /* FitCountUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FitCountUITests.swift; sourceTree = ""; };
- 92CACFED2A1B7DD200DA2B40 /* FitCountUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FitCountUITestsLaunchTests.swift; sourceTree = ""; };
92CACFFA2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseDetailsView.swift; sourceTree = ""; };
92CACFFC2A1B99A500DA2B40 /* WorkoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutView.swift; sourceTree = ""; };
92F2D1FA2A1D0C8400EC1B81 /* Text2Speech.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Text2Speech.swift; sourceTree = ""; };
@@ -91,20 +59,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 92CACFDA2A1B7DD200DA2B40 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 92CACFE42A1B7DD200DA2B40 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -114,9 +68,7 @@
92CACFFA2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift */,
92C702F82A1BC705002ECC0B /* QuickPoseBasicView.swift */,
92CACFFC2A1B99A500DA2B40 /* WorkoutView.swift */,
- 920A3EEE2A1F76F800EC6FC9 /* BoundingBoxView.swift */,
920A3EF02A1F7C2300EC6FC9 /* WorkoutResultsView.swift */,
- 920A3EF22A1F801A00EC6FC9 /* Workout.swift */,
924D6E272A29F90400227183 /* VolumeChangeView.swift */,
9215905E2A2A10BF001254BC /* InstructionsView.swift */,
);
@@ -143,8 +95,6 @@
isa = PBXGroup;
children = (
92CACFCF2A1B7DD100DA2B40 /* FitCount */,
- 92CACFE02A1B7DD200DA2B40 /* FitCountTests */,
- 92CACFEA2A1B7DD200DA2B40 /* FitCountUITests */,
92CACFCE2A1B7DD100DA2B40 /* Products */,
);
sourceTree = "";
@@ -153,8 +103,6 @@
isa = PBXGroup;
children = (
92CACFCD2A1B7DD100DA2B40 /* FitCounter.app */,
- 92CACFDD2A1B7DD200DA2B40 /* FitCountTests.xctest */,
- 92CACFE72A1B7DD200DA2B40 /* FitCountUITests.xctest */,
);
name = Products;
sourceTree = "";
@@ -162,9 +110,7 @@
92CACFCF2A1B7DD100DA2B40 /* FitCount */ = {
isa = PBXGroup;
children = (
- 92C703032A1D049E002ECC0B /* Info.plist */,
92CACFD42A1B7DD100DA2B40 /* Assets.xcassets */,
- 92CACFD62A1B7DD100DA2B40 /* Preview Content */,
924D6E262A289F0100227183 /* History */,
920A3EED2A1F76D400EC6FC9 /* Workout */,
924D6E232A289EB600227183 /* About */,
@@ -177,31 +123,6 @@
path = FitCount;
sourceTree = "";
};
- 92CACFD62A1B7DD100DA2B40 /* Preview Content */ = {
- isa = PBXGroup;
- children = (
- 92CACFD72A1B7DD100DA2B40 /* Preview Assets.xcassets */,
- );
- path = "Preview Content";
- sourceTree = "";
- };
- 92CACFE02A1B7DD200DA2B40 /* FitCountTests */ = {
- isa = PBXGroup;
- children = (
- 92CACFE12A1B7DD200DA2B40 /* FitCountTests.swift */,
- );
- path = FitCountTests;
- sourceTree = "";
- };
- 92CACFEA2A1B7DD200DA2B40 /* FitCountUITests */ = {
- isa = PBXGroup;
- children = (
- 92CACFEB2A1B7DD200DA2B40 /* FitCountUITests.swift */,
- 92CACFED2A1B7DD200DA2B40 /* FitCountUITestsLaunchTests.swift */,
- );
- path = FitCountUITests;
- sourceTree = "";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -229,42 +150,6 @@
productReference = 92CACFCD2A1B7DD100DA2B40 /* FitCounter.app */;
productType = "com.apple.product-type.application";
};
- 92CACFDC2A1B7DD200DA2B40 /* FitCountTests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 92CACFF42A1B7DD200DA2B40 /* Build configuration list for PBXNativeTarget "FitCountTests" */;
- buildPhases = (
- 92CACFD92A1B7DD200DA2B40 /* Sources */,
- 92CACFDA2A1B7DD200DA2B40 /* Frameworks */,
- 92CACFDB2A1B7DD200DA2B40 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 92CACFDF2A1B7DD200DA2B40 /* PBXTargetDependency */,
- );
- name = FitCountTests;
- productName = FitCountTests;
- productReference = 92CACFDD2A1B7DD200DA2B40 /* FitCountTests.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
- 92CACFE62A1B7DD200DA2B40 /* FitCountUITests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 92CACFF72A1B7DD200DA2B40 /* Build configuration list for PBXNativeTarget "FitCountUITests" */;
- buildPhases = (
- 92CACFE32A1B7DD200DA2B40 /* Sources */,
- 92CACFE42A1B7DD200DA2B40 /* Frameworks */,
- 92CACFE52A1B7DD200DA2B40 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 92CACFE92A1B7DD200DA2B40 /* PBXTargetDependency */,
- );
- name = FitCountUITests;
- productName = FitCountUITests;
- productReference = 92CACFE72A1B7DD200DA2B40 /* FitCountUITests.xctest */;
- productType = "com.apple.product-type.bundle.ui-testing";
- };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -278,14 +163,6 @@
92CACFCC2A1B7DD100DA2B40 = {
CreatedOnToolsVersion = 14.3;
};
- 92CACFDC2A1B7DD200DA2B40 = {
- CreatedOnToolsVersion = 14.3;
- TestTargetID = 92CACFCC2A1B7DD100DA2B40;
- };
- 92CACFE62A1B7DD200DA2B40 = {
- CreatedOnToolsVersion = 14.3;
- TestTargetID = 92CACFCC2A1B7DD100DA2B40;
- };
};
};
buildConfigurationList = 92CACFC82A1B7DD000DA2B40 /* Build configuration list for PBXProject "FitCounter by QuickPose.ai" */;
@@ -306,8 +183,6 @@
projectRoot = "";
targets = (
92CACFCC2A1B7DD100DA2B40 /* FitCounter */,
- 92CACFDC2A1B7DD200DA2B40 /* FitCountTests */,
- 92CACFE62A1B7DD200DA2B40 /* FitCountUITests */,
);
};
/* End PBXProject section */
@@ -317,25 +192,10 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 92CACFD82A1B7DD100DA2B40 /* Preview Assets.xcassets in Resources */,
92CACFD52A1B7DD100DA2B40 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 92CACFDB2A1B7DD200DA2B40 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 92CACFE52A1B7DD200DA2B40 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -346,8 +206,6 @@
92CACFD32A1B7DD100DA2B40 /* ContentView.swift in Sources */,
9215905F2A2A10BF001254BC /* InstructionsView.swift in Sources */,
92CACFD12A1B7DD100DA2B40 /* FitCountApp.swift in Sources */,
- 920A3EEF2A1F76F800EC6FC9 /* BoundingBoxView.swift in Sources */,
- 920A3EF32A1F801A00EC6FC9 /* Workout.swift in Sources */,
924D6E282A29F90400227183 /* VolumeChangeView.swift in Sources */,
924D6E252A289ED700227183 /* AboutView.swift in Sources */,
920A3EF12A1F7C2300EC6FC9 /* WorkoutResultsView.swift in Sources */,
@@ -361,38 +219,8 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 92CACFD92A1B7DD200DA2B40 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 92CACFE22A1B7DD200DA2B40 /* FitCountTests.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 92CACFE32A1B7DD200DA2B40 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 92CACFEE2A1B7DD200DA2B40 /* FitCountUITestsLaunchTests.swift in Sources */,
- 92CACFEC2A1B7DD200DA2B40 /* FitCountUITests.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXSourcesBuildPhase section */
-/* Begin PBXTargetDependency section */
- 92CACFDF2A1B7DD200DA2B40 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 92CACFCC2A1B7DD100DA2B40 /* FitCounter */;
- targetProxy = 92CACFDE2A1B7DD200DA2B40 /* PBXContainerItemProxy */;
- };
- 92CACFE92A1B7DD200DA2B40 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 92CACFCC2A1B7DD100DA2B40 /* FitCounter */;
- targetProxy = 92CACFE82A1B7DD200DA2B40 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
/* Begin XCBuildConfiguration section */
92CACFEF2A1B7DD200DA2B40 /* Debug */ = {
isa = XCBuildConfiguration;
@@ -515,7 +343,6 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = "\"FitCount/Preview Content\"";
DEVELOPMENT_TEAM = 22W63VGZT5;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -526,7 +353,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
- IPHONEOS_DEPLOYMENT_TARGET = 16.3;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -550,7 +377,6 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = "\"FitCount/Preview Content\"";
DEVELOPMENT_TEAM = 22W63VGZT5;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -561,7 +387,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
- IPHONEOS_DEPLOYMENT_TARGET = 16.3;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -578,82 +404,6 @@
};
name = Release;
};
- 92CACFF52A1B7DD200DA2B40 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- BUNDLE_LOADER = "$(TEST_HOST)";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = 22W63VGZT5;
- GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.4;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = ai.quickpose.FitCountTests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FitCount.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/FitCount";
- };
- name = Debug;
- };
- 92CACFF62A1B7DD200DA2B40 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- BUNDLE_LOADER = "$(TEST_HOST)";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = 22W63VGZT5;
- GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.4;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = ai.quickpose.FitCountTests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FitCount.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/FitCount";
- };
- name = Release;
- };
- 92CACFF82A1B7DD200DA2B40 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = 22W63VGZT5;
- GENERATE_INFOPLIST_FILE = YES;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = ai.quickpose.FitCountUITests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_TARGET_NAME = FitCount;
- };
- name = Debug;
- };
- 92CACFF92A1B7DD200DA2B40 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = 22W63VGZT5;
- GENERATE_INFOPLIST_FILE = YES;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = ai.quickpose.FitCountUITests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_TARGET_NAME = FitCount;
- };
- name = Release;
- };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -675,24 +425,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 92CACFF42A1B7DD200DA2B40 /* Build configuration list for PBXNativeTarget "FitCountTests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 92CACFF52A1B7DD200DA2B40 /* Debug */,
- 92CACFF62A1B7DD200DA2B40 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 92CACFF72A1B7DD200DA2B40 /* Build configuration list for PBXNativeTarget "FitCountUITests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 92CACFF82A1B7DD200DA2B40 /* Debug */,
- 92CACFF92A1B7DD200DA2B40 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
diff --git a/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 8cebcaa..705be83 100644
--- a/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -15,7 +15,7 @@
"location" : "https://github.com/quickpose/quickpose-ios-sdk.git",
"state" : {
"branch" : "main",
- "revision" : "3997bc1225a29e5a6a8c4c62ebd0b35bf85a81ef"
+ "revision" : "8fb20061d4787bda8250b2e88b0d70f94795efc2"
}
}
],
diff --git a/FitCounter by QuickPose.ai.xcodeproj/xcshareddata/xcschemes/FitCounter.xcscheme b/FitCounter by QuickPose.ai.xcodeproj/xcshareddata/xcschemes/FitCounter.xcscheme
index e8f13b0..b4670b6 100644
--- a/FitCounter by QuickPose.ai.xcodeproj/xcshareddata/xcschemes/FitCounter.xcscheme
+++ b/FitCounter by QuickPose.ai.xcodeproj/xcshareddata/xcschemes/FitCounter.xcscheme
@@ -1,7 +1,7 @@
+ version = "1.8">
@@ -28,6 +28,8 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
+
+
From a75c17df3acebbcc128182b0f7650b0f0e69046e Mon Sep 17 00:00:00 2001
From: Peter Nash <480796+pablonosh@users.noreply.github.com>
Date: Tue, 13 Jun 2023 11:19:56 +0100
Subject: [PATCH 2/2] using inside bounding box
---
FitCount/Workout/QuickPoseBasicView.swift | 172 +++++++++---------
.../project.pbxproj | 63 ++++---
.../xcshareddata/swiftpm/Package.resolved | 9 -
3 files changed, 124 insertions(+), 120 deletions(-)
diff --git a/FitCount/Workout/QuickPoseBasicView.swift b/FitCount/Workout/QuickPoseBasicView.swift
index 5c5034a..f156ef7 100644
--- a/FitCount/Workout/QuickPoseBasicView.swift
+++ b/FitCount/Workout/QuickPoseBasicView.swift
@@ -19,7 +19,7 @@ enum ViewState: Equatable {
case startVolume
case instructions
case introBoundingBox
- case boundingBox(enterTime: Date)
+ case boundingBox
case introExercise(Exercise)
case exercise(SessionData, enterTime: Date)
case results(SessionData)
@@ -36,6 +36,15 @@ enum ViewState: Equatable {
return nil
}
}
+
+ var features: [QuickPose.Feature]? {
+ switch self {
+ case .introBoundingBox, .boundingBox:
+ return [.inside(edgeInsets: QuickPose.RelativeCameraEdgeInsets(top: 0.1, left: 0.2, bottom: 0.01, right: 0.2))]
+ default:
+ return nil
+ }
+ }
}
struct QuickPoseBasicView: View {
@@ -47,18 +56,12 @@ struct QuickPoseBasicView: View {
@State private var feedbackText: String? = nil
@State private var counter = QuickPoseThresholdCounter()
+ @State private var unchanged = QuickPoseDoubleUnchangedDetector(similarDuration: 2, leniency: 0)
@State private var state: ViewState = .startVolume
+ @State private var boundingBoxVisibility = 1.0
@State private var countScale = 1.0
@State private var boundingBoxMaskWidth = 0.0
-
- func canMoveFromBoundingBox(landmarks: QuickPose.Landmarks) -> Bool {
-
- let xsInBox = landmarks.poseLandmarks.allSatisfy { 0.5 - (0.6/2) < $0[0] && $0[0] < 0.5 + (0.6/2) }
- let ysInBox = landmarks.poseLandmarks.allSatisfy { 0.5 - (0.8/2) < $0[1] && $0[1] < 0.5 + (0.8/2) }
-
- return xsInBox && ysInBox
- }
var body: some View {
GeometryReader { geometry in
@@ -102,12 +105,12 @@ struct QuickPoseBasicView: View {
}
.frame(width: geometry.size.width * 0.6, height: geometry.size.height * 0.8)
.padding(.horizontal, (geometry.size.width * 1 - 0.6)/2)
-
+
case .boundingBox:
ZStack {
RoundedRectangle(cornerRadius: 15)
- .stroke(.green, lineWidth: 5)
-
+ .stroke(boundingBoxVisibility == 1 ? .green : .red, lineWidth: 5)
+
RoundedRectangle(cornerRadius: 15)
.fill(.green.opacity(0.5))
.mask(alignment: .leading) {
@@ -117,7 +120,7 @@ struct QuickPoseBasicView: View {
}
.frame(width: geometry.size.width * 0.6, height: geometry.size.height * 0.8)
.padding(.horizontal, (geometry.size.width * 1 - 0.6)/2)
-
+
case .results(let results):
WorkoutResultsView(sessionData: results)
.environmentObject(viewModel)
@@ -176,89 +179,94 @@ struct QuickPoseBasicView: View {
AVSpeechSynthesizer().speak(utterance)
}
- if state == .introBoundingBox {
- quickPose.start(features: sessionConfig.exercise.features, onFrame: { status, image, features, feedback, landmarks in
- overlayImage = image
- if case .success(_,_) = status {
-
- switch state {
- case .introBoundingBox:
-
- if let landmarks = landmarks, canMoveFromBoundingBox(landmarks: landmarks) {
+ if case .results(let result) = state {
+ let sessionDataDump = SessionDataModel(exercise: sessionConfig.exercise.name, count: result.count, seconds: result.seconds, date: Date())
+ appendToJson(sessionData: sessionDataDump)
+ }
+
+ quickPose.update(features: state.features ?? sessionConfig.exercise.features)
+ }
+ .onAppear() {
+ UIApplication.shared.isIdleTimerDisabled = true
+ quickPose.start(features: state.features ?? sessionConfig.exercise.features, onFrame: { status, image, features, feedback, landmarks in
+ overlayImage = image
+ if case .success(_,_) = status {
- state = .boundingBox(enterTime: Date())
- boundingBoxMaskWidth = 0
- withAnimation(.easeInOut(duration: 2)) {
- boundingBoxMaskWidth = 1.0
- }
- }
- case .boundingBox(let enterDate):
- if let landmarks = landmarks, canMoveFromBoundingBox(landmarks: landmarks) {
- if -enterDate.timeIntervalSinceNow > 2 {
- state = .introExercise(sessionConfig.exercise)
+ switch state {
+ case .introBoundingBox:
+
+ if let result = features.first?.value, result.value == 1.0 {
+ unchanged.reset()
+ state = .boundingBox
+ }
+ case .boundingBox:
+ if let dictionaryEntry = features.first {
+ let result = dictionaryEntry.value
+ boundingBoxVisibility = result.value
+ unchanged.count(result: result.value) {
+ if result.value == 1 { // been in for 2 seconds
+ boundingBoxMaskWidth = 0
+ withAnimation(.easeInOut(duration: 1)) {
+ boundingBoxMaskWidth = 1.0
+ }
+ DispatchQueue.main.asyncAfter(deadline: .now()+1) {
+ state = .introExercise(sessionConfig.exercise)
+ }
+ } else {
+ state = .introBoundingBox
}
- } else {
- state = .introBoundingBox
}
+ }
- case .introExercise(_):
- DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
- state = .exercise(SessionData(count: 0, seconds: 0), enterTime: Date())
- }
- case .exercise(_, let enterDate):
- let secondsElapsed = Int(-enterDate.timeIntervalSinceNow)
-
- if let feedback = feedback[.fitness(.bicepCurls)] {
- feedbackText = feedback.displayString
- } else {
- feedbackText = nil
-
- if case .fitness = sessionConfig.exercise.features.first, let result = features[sessionConfig.exercise.features.first!] {
- _ = counter.count(result.value) { newState in
- if !newState.isEntered {
- DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
- withAnimation(.easeInOut(duration: 0.1)) {
- countScale = 2.0
- }
- DispatchQueue.main.asyncAfter(deadline: .now()+0.4) {
- withAnimation(.easeInOut(duration: 0.2)) {
- countScale = 1.0
- }
+ case .introExercise(_):
+ DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
+ state = .exercise(SessionData(count: 0, seconds: 0), enterTime: Date())
+ }
+ case .exercise(_, let enterDate):
+ let secondsElapsed = Int(-enterDate.timeIntervalSinceNow)
+
+ if let feedback = feedback[.fitness(.bicepCurls)] {
+ feedbackText = feedback.displayString
+ } else {
+ feedbackText = nil
+
+ if case .fitness = sessionConfig.exercise.features.first, let result = features[sessionConfig.exercise.features.first!] {
+ _ = counter.count(result.value) { newState in
+ if !newState.isEntered {
+ DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
+ withAnimation(.easeInOut(duration: 0.1)) {
+ countScale = 2.0
+ }
+ DispatchQueue.main.asyncAfter(deadline: .now()+0.4) {
+ withAnimation(.easeInOut(duration: 0.2)) {
+ countScale = 1.0
}
}
}
}
}
}
+ }
- let newResults = SessionData(count: counter.state.count, seconds: secondsElapsed)
- state = .exercise(newResults, enterTime: enterDate) // refresh view for every updated second
- var hasFinished = false
- if sessionConfig.useReps {
- hasFinished = counter.state.count >= sessionConfig.nReps
- } else {
- hasFinished = secondsElapsed >= sessionConfig.nSeconds + sessionConfig.nMinutes * 60
- }
+ let newResults = SessionData(count: counter.state.count, seconds: secondsElapsed)
+ state = .exercise(newResults, enterTime: enterDate) // refresh view for every updated second
+ var hasFinished = false
+ if sessionConfig.useReps {
+ hasFinished = counter.state.count >= sessionConfig.nReps
+ } else {
+ hasFinished = secondsElapsed >= sessionConfig.nSeconds + sessionConfig.nMinutes * 60
+ }
- if hasFinished {
- state = .results(newResults)
- }
- default:
- break
+ if hasFinished {
+ state = .results(newResults)
}
- } else {
- state = .introBoundingBox
+ default:
+ break
}
- })
- }
-
- if case .results(let result) = state {
- let sessionDataDump = SessionDataModel(exercise: sessionConfig.exercise.name, count: result.count, seconds: result.seconds, date: Date())
- appendToJson(sessionData: sessionDataDump)
- }
- }
- .onAppear() {
- UIApplication.shared.isIdleTimerDisabled = true
+ } else if state != .startVolume && state != .instructions{
+ state = .introBoundingBox
+ }
+ })
}
.onDisappear {
quickPose.stop()
diff --git a/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj b/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj
index 9555aee..7cfe2cc 100644
--- a/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj
+++ b/FitCounter by QuickPose.ai.xcodeproj/project.pbxproj
@@ -16,16 +16,16 @@
924D6E282A29F90400227183 /* VolumeChangeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924D6E272A29F90400227183 /* VolumeChangeView.swift */; };
927261A42A24EF0B00C3B390 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927261A32A24EF0B00C3B390 /* HistoryView.swift */; };
92C702F92A1BC705002ECC0B /* QuickPoseBasicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92C702F82A1BC705002ECC0B /* QuickPoseBasicView.swift */; };
- 92C702FC2A1BC74A002ECC0B /* QuickPoseCamera in Frameworks */ = {isa = PBXBuildFile; productRef = 92C702FB2A1BC74A002ECC0B /* QuickPoseCamera */; };
- 92C702FE2A1BC74A002ECC0B /* QuickPoseCore in Frameworks */ = {isa = PBXBuildFile; productRef = 92C702FD2A1BC74A002ECC0B /* QuickPoseCore */; };
- 92C703002A1BC74A002ECC0B /* QuickPoseMP in Frameworks */ = {isa = PBXBuildFile; productRef = 92C702FF2A1BC74A002ECC0B /* QuickPoseMP */; };
- 92C703022A1BC74A002ECC0B /* QuickPoseSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 92C703012A1BC74A002ECC0B /* QuickPoseSwiftUI */; };
92CACFD12A1B7DD100DA2B40 /* FitCountApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFD02A1B7DD100DA2B40 /* FitCountApp.swift */; };
92CACFD32A1B7DD100DA2B40 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFD22A1B7DD100DA2B40 /* ContentView.swift */; };
92CACFD52A1B7DD100DA2B40 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92CACFD42A1B7DD100DA2B40 /* Assets.xcassets */; };
92CACFFB2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFFA2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift */; };
92CACFFD2A1B99A500DA2B40 /* WorkoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92CACFFC2A1B99A500DA2B40 /* WorkoutView.swift */; };
92F2D1FB2A1D0C8400EC1B81 /* Text2Speech.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92F2D1FA2A1D0C8400EC1B81 /* Text2Speech.swift */; };
+ D06C7CD82A373D18001B4508 /* QuickPoseCamera in Frameworks */ = {isa = PBXBuildFile; productRef = D06C7CD72A373D18001B4508 /* QuickPoseCamera */; };
+ D06C7CDA2A373D18001B4508 /* QuickPoseCore in Frameworks */ = {isa = PBXBuildFile; productRef = D06C7CD92A373D18001B4508 /* QuickPoseCore */; };
+ D06C7CDC2A373D18001B4508 /* QuickPoseMP in Frameworks */ = {isa = PBXBuildFile; productRef = D06C7CDB2A373D18001B4508 /* QuickPoseMP */; };
+ D06C7CDE2A373D18001B4508 /* QuickPoseSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06C7CDD2A373D18001B4508 /* QuickPoseSwiftUI */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -44,6 +44,7 @@
92CACFFA2A1B8F9D00DA2B40 /* ExerciseDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseDetailsView.swift; sourceTree = ""; };
92CACFFC2A1B99A500DA2B40 /* WorkoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutView.swift; sourceTree = ""; };
92F2D1FA2A1D0C8400EC1B81 /* Text2Speech.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Text2Speech.swift; sourceTree = ""; };
+ D06C7CD52A373CFA001B4508 /* quickpose-ios-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "quickpose-ios-sdk"; path = "../../quickpose-ios-sdk-private/quickpose-ios-sdk"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -51,11 +52,11 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 92C702FE2A1BC74A002ECC0B /* QuickPoseCore in Frameworks */,
- 92C703002A1BC74A002ECC0B /* QuickPoseMP in Frameworks */,
- 92C702FC2A1BC74A002ECC0B /* QuickPoseCamera in Frameworks */,
+ D06C7CDE2A373D18001B4508 /* QuickPoseSwiftUI in Frameworks */,
+ D06C7CDC2A373D18001B4508 /* QuickPoseMP in Frameworks */,
+ D06C7CD82A373D18001B4508 /* QuickPoseCamera in Frameworks */,
920A3EF62A20B14100EC6FC9 /* PagerTabStripView in Frameworks */,
- 92C703022A1BC74A002ECC0B /* QuickPoseSwiftUI in Frameworks */,
+ D06C7CDA2A373D18001B4508 /* QuickPoseCore in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -94,8 +95,10 @@
92CACFC42A1B7DD000DA2B40 = {
isa = PBXGroup;
children = (
+ D06C7CD42A373CFA001B4508 /* Packages */,
92CACFCF2A1B7DD100DA2B40 /* FitCount */,
92CACFCE2A1B7DD100DA2B40 /* Products */,
+ D06C7CD62A373D18001B4508 /* Frameworks */,
);
sourceTree = "";
};
@@ -123,6 +126,21 @@
path = FitCount;
sourceTree = "";
};
+ D06C7CD42A373CFA001B4508 /* Packages */ = {
+ isa = PBXGroup;
+ children = (
+ D06C7CD52A373CFA001B4508 /* quickpose-ios-sdk */,
+ );
+ name = Packages;
+ sourceTree = "";
+ };
+ D06C7CD62A373D18001B4508 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -140,11 +158,11 @@
);
name = FitCounter;
packageProductDependencies = (
- 92C702FB2A1BC74A002ECC0B /* QuickPoseCamera */,
- 92C702FD2A1BC74A002ECC0B /* QuickPoseCore */,
- 92C702FF2A1BC74A002ECC0B /* QuickPoseMP */,
- 92C703012A1BC74A002ECC0B /* QuickPoseSwiftUI */,
920A3EF52A20B14100EC6FC9 /* PagerTabStripView */,
+ D06C7CD72A373D18001B4508 /* QuickPoseCamera */,
+ D06C7CD92A373D18001B4508 /* QuickPoseCore */,
+ D06C7CDB2A373D18001B4508 /* QuickPoseMP */,
+ D06C7CDD2A373D18001B4508 /* QuickPoseSwiftUI */,
);
productName = FitCount;
productReference = 92CACFCD2A1B7DD100DA2B40 /* FitCounter.app */;
@@ -175,7 +193,6 @@
);
mainGroup = 92CACFC42A1B7DD000DA2B40;
packageReferences = (
- 92C702FA2A1BC74A002ECC0B /* XCRemoteSwiftPackageReference "quickpose-ios-sdk" */,
920A3EF42A20B14000EC6FC9 /* XCRemoteSwiftPackageReference "PagerTabStripView" */,
);
productRefGroup = 92CACFCE2A1B7DD100DA2B40 /* Products */;
@@ -436,14 +453,6 @@
minimumVersion = 4.0.0;
};
};
- 92C702FA2A1BC74A002ECC0B /* XCRemoteSwiftPackageReference "quickpose-ios-sdk" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/quickpose/quickpose-ios-sdk.git";
- requirement = {
- branch = main;
- kind = branch;
- };
- };
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@@ -452,24 +461,20 @@
package = 920A3EF42A20B14000EC6FC9 /* XCRemoteSwiftPackageReference "PagerTabStripView" */;
productName = PagerTabStripView;
};
- 92C702FB2A1BC74A002ECC0B /* QuickPoseCamera */ = {
+ D06C7CD72A373D18001B4508 /* QuickPoseCamera */ = {
isa = XCSwiftPackageProductDependency;
- package = 92C702FA2A1BC74A002ECC0B /* XCRemoteSwiftPackageReference "quickpose-ios-sdk" */;
productName = QuickPoseCamera;
};
- 92C702FD2A1BC74A002ECC0B /* QuickPoseCore */ = {
+ D06C7CD92A373D18001B4508 /* QuickPoseCore */ = {
isa = XCSwiftPackageProductDependency;
- package = 92C702FA2A1BC74A002ECC0B /* XCRemoteSwiftPackageReference "quickpose-ios-sdk" */;
productName = QuickPoseCore;
};
- 92C702FF2A1BC74A002ECC0B /* QuickPoseMP */ = {
+ D06C7CDB2A373D18001B4508 /* QuickPoseMP */ = {
isa = XCSwiftPackageProductDependency;
- package = 92C702FA2A1BC74A002ECC0B /* XCRemoteSwiftPackageReference "quickpose-ios-sdk" */;
productName = QuickPoseMP;
};
- 92C703012A1BC74A002ECC0B /* QuickPoseSwiftUI */ = {
+ D06C7CDD2A373D18001B4508 /* QuickPoseSwiftUI */ = {
isa = XCSwiftPackageProductDependency;
- package = 92C702FA2A1BC74A002ECC0B /* XCRemoteSwiftPackageReference "quickpose-ios-sdk" */;
productName = QuickPoseSwiftUI;
};
/* End XCSwiftPackageProductDependency section */
diff --git a/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 705be83..3f53c04 100644
--- a/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/FitCounter by QuickPose.ai.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -8,15 +8,6 @@
"revision" : "39ec00d2577adf75d82d1c7023c56950b96d2298",
"version" : "4.0.0"
}
- },
- {
- "identity" : "quickpose-ios-sdk",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/quickpose/quickpose-ios-sdk.git",
- "state" : {
- "branch" : "main",
- "revision" : "8fb20061d4787bda8250b2e88b0d70f94795efc2"
- }
}
],
"version" : 2