Skip to content

Commit

Permalink
History Log Feature (#2)
Browse files Browse the repository at this point in the history
Lots of changes for this feature.
  • Loading branch information
reedes authored Jan 11, 2023
1 parent 067e2db commit f6591df
Show file tree
Hide file tree
Showing 8 changed files with 648 additions and 23 deletions.
37 changes: 33 additions & 4 deletions Gym Routine Tracker Plus.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

/* Begin PBXBuildFile section */
4011EECD2961C9B000A36D87 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 4011EECC2961C9B000A36D87 /* LICENSE */; };
40245EF6296BE7D4007B5DAB /* ExerciseRunList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40245EF5296BE7D4007B5DAB /* ExerciseRunList.swift */; };
402A5F2F296B7FE000A43DB3 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402A5F2E296B7F7B00A43DB3 /* HistoryView.swift */; };
402A5F32296B835B00A43DB3 /* Tabler in Frameworks */ = {isa = PBXBuildFile; productRef = 402A5F31296B835B00A43DB3 /* Tabler */; };
408FACFE296CAC9300D02C9C /* RoutineRunList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 408FACFD296CABC400D02C9C /* RoutineRunList.swift */; };
40B51E45294549DF0047377A /* GroutUI in Frameworks */ = {isa = PBXBuildFile; productRef = 40B51E44294549DF0047377A /* GroutUI */; };
40CCF3F629454D2B007DDE69 /* GroutLib in Frameworks */ = {isa = PBXBuildFile; productRef = 40CCF3F529454D2B007DDE69 /* GroutLib */; };
40E347BE29452CF1003A19B9 /* PlusApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40E347BD29452CF1003A19B9 /* PlusApp.swift */; };
Expand All @@ -21,6 +25,9 @@
/* Begin PBXFileReference section */
4011EECC2961C9B000A36D87 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
4011EECE2961C9BC00A36D87 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
40245EF5296BE7D4007B5DAB /* ExerciseRunList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseRunList.swift; sourceTree = "<group>"; };
402A5F2E296B7F7B00A43DB3 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = "<group>"; };
408FACFD296CABC400D02C9C /* RoutineRunList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutineRunList.swift; sourceTree = "<group>"; };
40E347BA29452CF1003A19B9 /* Gym Routine Tracker Plus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Gym Routine Tracker Plus.app"; sourceTree = BUILT_PRODUCTS_DIR; };
40E347BD29452CF1003A19B9 /* PlusApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlusApp.swift; sourceTree = "<group>"; };
40E347BF29452CF1003A19B9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand All @@ -35,6 +42,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
402A5F32296B835B00A43DB3 /* Tabler in Frameworks */,
40B51E45294549DF0047377A /* GroutUI in Frameworks */,
40E347D329452E4B003A19B9 /* Compactor in Frameworks */,
40EBE1CC29635306004B9189 /* GroutUI in Frameworks */,
Expand Down Expand Up @@ -76,6 +84,9 @@
children = (
40E347BD29452CF1003A19B9 /* PlusApp.swift */,
40E347BF29452CF1003A19B9 /* ContentView.swift */,
402A5F2E296B7F7B00A43DB3 /* HistoryView.swift */,
408FACFD296CABC400D02C9C /* RoutineRunList.swift */,
40245EF5296BE7D4007B5DAB /* ExerciseRunList.swift */,
40E347C129452CF1003A19B9 /* Assets.xcassets */,
40EBCFDE294BFB880082A172 /* Info.plist */,
40E347C329452CF1003A19B9 /* App.entitlements */,
Expand Down Expand Up @@ -113,6 +124,7 @@
40B51E44294549DF0047377A /* GroutUI */,
40CCF3F529454D2B007DDE69 /* GroutLib */,
40EBE1CB29635306004B9189 /* GroutUI */,
402A5F31296B835B00A43DB3 /* Tabler */,
);
productName = "Gym Routine Tracker Plus";
productReference = 40E347BA29452CF1003A19B9 /* Gym Routine Tracker Plus.app */;
Expand Down Expand Up @@ -145,6 +157,7 @@
packageReferences = (
40E347D129452E4B003A19B9 /* XCRemoteSwiftPackageReference "SwiftCompactor" */,
40EBE1CA29635306004B9189 /* XCRemoteSwiftPackageReference "GroutUI" */,
402A5F30296B835B00A43DB3 /* XCRemoteSwiftPackageReference "SwiftTabler" */,
);
productRefGroup = 40E347BB29452CF1003A19B9 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -174,6 +187,9 @@
buildActionMask = 2147483647;
files = (
40E347C029452CF1003A19B9 /* ContentView.swift in Sources */,
408FACFE296CAC9300D02C9C /* RoutineRunList.swift in Sources */,
40245EF6296BE7D4007B5DAB /* ExerciseRunList.swift in Sources */,
402A5F2F296B7FE000A43DB3 /* HistoryView.swift in Sources */,
40E347BE29452CF1003A19B9 /* PlusApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -297,7 +313,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sources/App.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_ASSET_PATHS = "\"Sources/Preview Content\"";
DEVELOPMENT_TEAM = J735QC5U38;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -320,7 +336,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.4;
MARKETING_VERSION = 1.5;
PRODUCT_BUNDLE_IDENTIFIER = org.openalloc.grout.plus;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
Expand All @@ -340,7 +356,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sources/App.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_ASSET_PATHS = "\"Sources/Preview Content\"";
DEVELOPMENT_TEAM = J735QC5U38;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -363,7 +379,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.4;
MARKETING_VERSION = 1.5;
PRODUCT_BUNDLE_IDENTIFIER = org.openalloc.grout.plus;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
Expand Down Expand Up @@ -400,6 +416,14 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
402A5F30296B835B00A43DB3 /* XCRemoteSwiftPackageReference "SwiftTabler" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/openalloc/SwiftTabler.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.9.6;
};
};
40E347D129452E4B003A19B9 /* XCRemoteSwiftPackageReference "SwiftCompactor" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/openalloc/SwiftCompactor.git";
Expand All @@ -419,6 +443,11 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
402A5F31296B835B00A43DB3 /* Tabler */ = {
isa = XCSwiftPackageProductDependency;
package = 402A5F30296B835B00A43DB3 /* XCRemoteSwiftPackageReference "SwiftTabler" */;
productName = Tabler;
};
40B51E44294549DF0047377A /* GroutUI */ = {
isa = XCSwiftPackageProductDependency;
productName = GroutUI;
Expand Down
43 changes: 31 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
# Gym Routine Tracker Plus
# Gym Routine Tracker+

_A minimalist gym workout tracker, for iPhone and iPad_

## Download

Available as a free download in the App Store [HERE](https://apps.apple.com/us/app/gym-routine-tracker/id6444747204).
Available as a FREE download in the App Store [GRT for iPhone/iPad](https://apps.apple.com/us/app/gym-routine-tracker/id1662243916)

## Features

- LARGE text in RUN mode, for those with presbyopia. Leave your cheaters in your locker!
- Prioritizes convenience, quick interactions, and the basic needs of the recreational fitness user.
- Available separately, an independent GRT watchOS app
- _NEW in 1.5_ Logs routine/exercise completions, where history can be reviewed on your iPhone/iPad.

- LARGE text in RUN mode, for the farsighted. Leave your glasses in your locker!
- Simple data model of user-defined routines and their exercises.
- Your data syncs with your private iCloud account when a network connection is available.
- Fully open source where code is licensed with Mozilla Public License 2.0.
- Available separately as an independent app for the Apple Watch.

GRT prioritizes convenience, quick interactions, and the basic needs of the recreational fitness user.

### Quick and easy setup

Expand All @@ -25,12 +31,17 @@ Available as a free download in the App Store [HERE](https://apps.apple.com/us/a
- Convenient skip to the next incomplete exercise, in case a machine isn’t immediately available.
- Control screen showing the time elapsed since starting the routine.

### App features
### History features (NEW)

- Simple data model of user-defined routines and their exercises.
- Your data syncs with CloudKit when a network connection is available.
- Fully open source where code is licensed with Mozilla Public License 2.0.
- App available as a free download in the iOS App Store.
- Completion of routine/exercise is automatically logged to your private iCloud account.
- Logging can be disabled in settings.
- For the watchOS app, recent history will be stored locally for up to 1 year. Periodically run iOS app for long-term storage and review.
- History can be reviewed on the iOS app for the iPhone/iPad.

### iCloud Sync

- Your data automatically syncs with your private iCloud account when a network connection is available.
- That synced data available to the _Gym Routine Tracker_ app running on your other devices.

## Requirements

Expand All @@ -46,12 +57,20 @@ To any Apple product managers who like this app, please consider Sherlocking it!

## See Also

### App Download Links

* [GRT for Apple Watch](https://apps.apple.com/us/app/gym-routine-tracker/id6444747204) - App Store link for FREE download
* [GRT+ for iPhone/iPad](https://apps.apple.com/us/app/gym-routine-tracker/id1662243916) - App Store link for FREE download

### Source Code

* [GRT Website](https://gym-routine-tracker.github.io) - Website for GRT
* [GRT on the App Store](https://apps.apple.com/us/app/gym-routine-tracker/id6444747204) - App Store link for free download of GRT
* [GRT for Apple Watch Source](https://github.com/gym-routine-tracker/Gym-Routine-Tracker-Watch-App) - watchOS implementation
* [GRT+ for iPhone/iPad Source](https://github.com/gym-routine-tracker/Gym-Routine-Tracker-Plus-App) - iOS implementation
* [GroutUI](https://github.com/gym-routine-tracker/GroutUI) - shared UI layer for GRT (watchOS and iOS)
* [GroutLib](https://github.com/gym-routine-tracker/GroutLib) - shared business logic and data layer for GRT

Apps by the same author:
### macOS Apps by the same author

* [FlowAllocator](https://openalloc.github.io/FlowAllocator/index.html) - portfolio rebalancing tool for macOS
* [FlowWorth](https://openalloc.github.io/FlowWorth/index.html) - portfolio valuation and tracking tool for macOS
Expand Down
3 changes: 3 additions & 0 deletions Sources/App.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.org.openalloc.grout</string>
<string>iCloud.org.openalloc.grout.archive</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
Expand Down
41 changes: 35 additions & 6 deletions Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,24 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//

import CoreData
import SwiftUI

import GroutLib
import GroutUI

struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext

enum Tabs: Int {
case routines = 0
case history = 1
case settings = 2
}

@SceneStorage("main-tab") private var selectedTab = 0
@SceneStorage("main-routines-nav") private var routinesNavData: Data?
@SceneStorage("main-history-nav") private var historyNavData: Data?
@SceneStorage("main-settings-nav") private var settingsNavData: Data?

var body: some View {
Expand All @@ -25,9 +35,19 @@ struct ContentView: View {
RoutineList()
}
.tabItem {
Label("Routines", systemImage: "dumbbell.fill")
Label("Routines", systemImage: "dumbbell")
}
.tag(0)
.tag(Tabs.routines.rawValue)

NavStack(name: "history",
navData: $historyNavData,
routineRunDetail: exerciseRunList) {
HistoryView()
}
.tabItem {
Label("History", systemImage: "fossil.shell")
}
.tag(Tabs.history.rawValue)

NavStack(name: "settings",
navData: $settingsNavData) {
Expand All @@ -36,17 +56,26 @@ struct ContentView: View {
.tabItem {
Label("Settings", systemImage: "gear")
}
.tag(1)
.tag(Tabs.settings.rawValue)
}
}

// TODO: history, charts, etc. will be the 'Plus'
// used to inject view into NavStack
@ViewBuilder
private func exerciseRunList(_ routineRunUri: URL) -> some View {
if let zRoutineRun = ZRoutineRun.get(viewContext, forURIRepresentation: routineRunUri),
let archiveStore = PersistenceManager.getArchiveStore(viewContext)
{
ExerciseRunList(zRoutineRun: zRoutineRun, archiveStore: archiveStore)
} else {
Text("Routine Run not available to display detail.")
}
}
}

// TODO: four copies of each routine showing up; should be one!
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let ctx = PersistenceManager.preview.container.viewContext
let ctx = PersistenceManager.getPreviewContainer().viewContext
let routine = Routine.create(ctx, userOrder: 0)
routine.name = "Back & Bicep"
let e1 = Exercise.create(ctx, userOrder: 0)
Expand Down
Loading

0 comments on commit f6591df

Please sign in to comment.