Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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