Skip to content

Commit

Permalink
Move data class extensions to TrackWorkout file. Setup position track…
Browse files Browse the repository at this point in the history
…ing to run in background.
  • Loading branch information
deb761 committed Nov 6, 2017
1 parent cb6f974 commit a8647f3
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 112 deletions.
4 changes: 4 additions & 0 deletions Trainer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
87B8B8F71F6D8F4D00A6989A /* IntervalsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B8B8F61F6D8F4D00A6989A /* IntervalsViewController.swift */; };
87B8B8F91F6D9A2400A6989A /* RepeatCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B8B8F81F6D9A2400A6989A /* RepeatCell.swift */; };
87B8B8FB1F6DDC1500A6989A /* WorkoutNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B8B8FA1F6DDC1500A6989A /* WorkoutNameCell.swift */; };
87D3C9ED1FACBE6D0074C7AC /* Intervals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D3C9EC1FACBE6D0074C7AC /* Intervals.swift */; };
87FD010A1F6B32830076D6E4 /* PhasesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FD01091F6B32830076D6E4 /* PhasesViewController.swift */; };
87FD010C1F6B34AC0076D6E4 /* PhaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FD010B1F6B34AC0076D6E4 /* PhaseCell.swift */; };
87FD01111F6B852E0076D6E4 /* PhaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FD010F1F6B852E0076D6E4 /* PhaseViewController.swift */; };
Expand Down Expand Up @@ -80,6 +81,7 @@
87B8B8F61F6D8F4D00A6989A /* IntervalsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntervalsViewController.swift; sourceTree = "<group>"; };
87B8B8F81F6D9A2400A6989A /* RepeatCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatCell.swift; sourceTree = "<group>"; };
87B8B8FA1F6DDC1500A6989A /* WorkoutNameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutNameCell.swift; sourceTree = "<group>"; };
87D3C9EC1FACBE6D0074C7AC /* Intervals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Intervals.swift; path = Model/Intervals.swift; sourceTree = "<group>"; };
87FD01091F6B32830076D6E4 /* PhasesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhasesViewController.swift; sourceTree = "<group>"; };
87FD010B1F6B34AC0076D6E4 /* PhaseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhaseCell.swift; sourceTree = "<group>"; };
87FD010F1F6B852E0076D6E4 /* PhaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhaseViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -149,6 +151,7 @@
87AD14891F644852009D778A /* Trainer.xcdatamodeld */,
870193101F6722750095D847 /* TrackWorkout.swift */,
87AD14B51F64788A009D778A /* TrackPhase.swift */,
87D3C9EC1FACBE6D0074C7AC /* Intervals.swift */,
87A4CF2F1F6AF8FE004D49D1 /* WorkoutsViewController.swift */,
87A4CF311F6B15F3004D49D1 /* WorkoutCell.swift */,
87FD01091F6B32830076D6E4 /* PhasesViewController.swift */,
Expand Down Expand Up @@ -341,6 +344,7 @@
87A4CF321F6B15F3004D49D1 /* WorkoutCell.swift in Sources */,
87FD010A1F6B32830076D6E4 /* PhasesViewController.swift in Sources */,
87FD011A1F6C206D0076D6E4 /* PhaseSection.swift in Sources */,
87D3C9ED1FACBE6D0074C7AC /* Intervals.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
104 changes: 1 addition & 103 deletions Trainer/DataAccess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,106 +145,4 @@ class DataAccess {
return workouts
}
}
extension Phase {
// Text description for a phase
public override var description:String {
get {
let time = self.duration.format() ?? "*"
//User region setting
let locale = Locale.current
let dist = Measurement(value: self.distance, unit: UnitLength.meters)
var distance = ""
let activity = self.activity?.name ?? ""
if locale.usesMetricSystem {
distance = "\(dist.converted(to: UnitLength.kilometers))"
}
else {
distance = "\(dist.converted(to: UnitLength.miles))"
}
switch EndType(rawValue: Int(self.end))! {
case EndType.Duration:
return activity + " for \(time)"
case EndType.Distance:
return activity + " for \(distance)"
case EndType.Either:
return activity + " for \(time) or \(distance)"
case EndType.Both:
return activity + " for \(time) and \(distance)"
}
}
}
// Expected time for a phase or NaN if based only on
// distance
@objc public var time:TimeInterval {
get {
if self.end == Int32(EndType.Distance.rawValue) {
return Double.nan
}
return TimeInterval(duration)
}
}
}
extension Intervals {
// Text description for intervals
public override var description:String {
get {
var text:String = "Repeat "
for object in self.phases! {
if let phase = object as? Phase {
text += "\(phase.description), "
}
}
text += "\(self.repeats) times"
return text
}
}
// Expected time for an interval or NaN if based only on
// distance
public override var time:TimeInterval {
get {
duration = 0.0
for object in self.phases! {
if let phase = object as? Phase {
duration += phase.duration
}
}
duration *= Double(self.repeats)
return TimeInterval(duration)
}
}
}
extension Workout {
// Text description for a workout
public override var description:String {
get {
var text = "Warmup \(warmup?.activity?.name ?? "") for \(warmup?.duration.format() ?? ""), "
for object in phases! {
if let intervals = object as? Intervals {
text += intervals.description + ", "
}
else if let phase = object as? Phase {
text += "\(phase.description), "
}
}
text += "Cooldown \(cooldown?.description ?? "")"
return text
}
}
// Expected time for a workout or NaN if based only on
// distance
public var time:TimeInterval {
get {
var duration:TimeInterval = TimeInterval((warmup?.duration)!)
duration += TimeInterval((cooldown?.duration) ?? 0.0)
for object in phases! {
if let phase = object as? Phase {
duration += phase.time
if duration.isNaN {
break
}
}
}
return duration
}
}
}

8 changes: 5 additions & 3 deletions Trainer/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class ViewController: UIViewController, CLLocationManagerDelegate, WorkoutDelega
locationManager.activityType = .fitness
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
}
// Let the user know that a new phase is beginning
Expand All @@ -137,7 +138,6 @@ class ViewController: UIViewController, CLLocationManagerDelegate, WorkoutDelega
}
// Create the workout tracker if this is a different workout, then fill in the labels
// for the workout
// TODO prevent changing workouts while one is in progress
@objc func fillLabels() {
if workoutData != ViewController.workout?.data || ViewController.workout == nil {
if let data = workoutData {
Expand Down Expand Up @@ -269,7 +269,7 @@ class ViewController: UIViewController, CLLocationManagerDelegate, WorkoutDelega
else {
workout.resume()
}
if isGrantedNotificationAccess {
if isGrantedNotificationAccess && CLLocationManager.authorizationStatus() != .authorizedAlways {
createNotifications(workout)
}
timer = Timer.scheduledTimer(timeInterval: 1, target: self,
Expand Down Expand Up @@ -341,4 +341,6 @@ class ViewController: UIViewController, CLLocationManagerDelegate, WorkoutDelega
self.present(alert, animated: true, completion: nil)
}
}

enum WorkoutError : Error {
case workoutRunning
}
39 changes: 39 additions & 0 deletions Trainer/Model/Intervals.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// Intervals.swift
// Trainer
//
// Created by Deborah Engelmeyer on 11/3/17.
// Copyright © 2017 The Inquisitive Introvert. All rights reserved.
//

import Foundation

extension Intervals {
// Text description for intervals
public override var description:String {
get {
var text:String = "Repeat "
for object in self.phases! {
if let phase = object as? Phase {
text += "\(phase.description), "
}
}
text += "\(self.repeats) times"
return text
}
}
// Expected time for an interval or NaN if based only on
// distance
public override var time:TimeInterval {
get {
duration = 0.0
for object in self.phases! {
if let phase = object as? Phase {
duration += phase.duration
}
}
duration *= Double(self.repeats)
return TimeInterval(duration)
}
}
}
39 changes: 39 additions & 0 deletions Trainer/TrackPhase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,45 @@ import Foundation
public enum EndType:Int {
case Duration = 0, Distance, Either, Both
}
extension Phase {
// Text description for a phase
public override var description:String {
get {
let time = self.duration.format() ?? "*"
//User region setting
let locale = Locale.current
let dist = Measurement(value: self.distance, unit: UnitLength.meters)
var distance = ""
let activity = self.activity?.name ?? ""
if locale.usesMetricSystem {
distance = "\(dist.converted(to: UnitLength.kilometers))"
}
else {
distance = "\(dist.converted(to: UnitLength.miles))"
}
switch EndType(rawValue: Int(self.end))! {
case EndType.Duration:
return activity + " for \(time)"
case EndType.Distance:
return activity + " for \(distance)"
case EndType.Either:
return activity + " for \(time) or \(distance)"
case EndType.Both:
return activity + " for \(time) and \(distance)"
}
}
}
// Expected time for a phase or NaN if based only on
// distance
@objc public var time:TimeInterval {
get {
if self.end == Int32(EndType.Distance.rawValue) {
return Double.nan
}
return TimeInterval(duration)
}
}
}
// Phase class to track the beginning, end, and progress of a phase
public class TrackPhase {
// Database record for the phase
Expand Down
48 changes: 42 additions & 6 deletions Trainer/TrackWorkout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,41 @@ protocol WorkoutDelegate {
func processPhaseChange()
func processComplete()
}
extension Workout {
// Text description for a workout
public override var description:String {
get {
var text = "Warmup \(warmup?.activity?.name ?? "") for \(warmup?.duration.format() ?? ""), "
for object in phases! {
if let intervals = object as? Intervals {
text += intervals.description + ", "
}
else if let phase = object as? Phase {
text += "\(phase.description), "
}
}
text += "Cooldown \(cooldown?.description ?? "")"
return text
}
}
// Expected time for a workout or NaN if based only on
// distance
public var time:TimeInterval {
get {
var duration:TimeInterval = TimeInterval((warmup?.duration)!)
duration += TimeInterval((cooldown?.duration) ?? 0.0)
for object in phases! {
if let phase = object as? Phase {
duration += phase.time
if duration.isNaN {
break
}
}
}
return duration
}
}
}
// Workout class to track the progress of a workout
class TrackWorkout {
public var description:String {
Expand Down Expand Up @@ -59,6 +94,7 @@ class TrackWorkout {
while one is in progress.
*/
fileprivate func createPhases(_ data: Workout) {
phases = []
let warmup = TrackPhase(data: (data.warmup)!)
phases.append(warmup)
for object in data.phases! {
Expand All @@ -80,12 +116,6 @@ class TrackWorkout {
let cooldown = TrackPhase(data: data.cooldown!)
phases.append(cooldown)
currentPhase = phases[0]
if let remaining = endTime?.timeIntervalSinceNow {
if remaining > 0.0 {
start(at: endTime! - duration)
update(distance: 0.0)
}
}
}

public init(data:Workout, delegate:WorkoutDelegate) {
Expand Down Expand Up @@ -114,6 +144,11 @@ class TrackWorkout {
endTime = startTime! + duration
data.last = endTime
timeStamp = Date()
if let remaining = endTime?.timeIntervalSinceNow {
if remaining > 0.0 {
update(distance: 0.0)
}
}
}
// Calculate a new end time
func updateEndTime() {
Expand Down Expand Up @@ -181,6 +216,7 @@ class TrackWorkout {
// stop the workout
public func stop() {
endTime = nil
running = false
}
public var ttg:TimeInterval {
get {
Expand Down

0 comments on commit a8647f3

Please sign in to comment.