Skip to content

Commit f6591df

Browse files
authored
History Log Feature (open-trackers#2)
Lots of changes for this feature.
1 parent 067e2db commit f6591df

8 files changed

Lines changed: 648 additions & 23 deletions

File tree

Gym Routine Tracker Plus.xcodeproj/project.pbxproj

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
/* Begin PBXBuildFile section */
1010
4011EECD2961C9B000A36D87 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 4011EECC2961C9B000A36D87 /* LICENSE */; };
11+
40245EF6296BE7D4007B5DAB /* ExerciseRunList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40245EF5296BE7D4007B5DAB /* ExerciseRunList.swift */; };
12+
402A5F2F296B7FE000A43DB3 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 402A5F2E296B7F7B00A43DB3 /* HistoryView.swift */; };
13+
402A5F32296B835B00A43DB3 /* Tabler in Frameworks */ = {isa = PBXBuildFile; productRef = 402A5F31296B835B00A43DB3 /* Tabler */; };
14+
408FACFE296CAC9300D02C9C /* RoutineRunList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 408FACFD296CABC400D02C9C /* RoutineRunList.swift */; };
1115
40B51E45294549DF0047377A /* GroutUI in Frameworks */ = {isa = PBXBuildFile; productRef = 40B51E44294549DF0047377A /* GroutUI */; };
1216
40CCF3F629454D2B007DDE69 /* GroutLib in Frameworks */ = {isa = PBXBuildFile; productRef = 40CCF3F529454D2B007DDE69 /* GroutLib */; };
1317
40E347BE29452CF1003A19B9 /* PlusApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40E347BD29452CF1003A19B9 /* PlusApp.swift */; };
@@ -21,6 +25,9 @@
2125
/* Begin PBXFileReference section */
2226
4011EECC2961C9B000A36D87 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
2327
4011EECE2961C9BC00A36D87 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
28+
40245EF5296BE7D4007B5DAB /* ExerciseRunList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseRunList.swift; sourceTree = "<group>"; };
29+
402A5F2E296B7F7B00A43DB3 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = "<group>"; };
30+
408FACFD296CABC400D02C9C /* RoutineRunList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutineRunList.swift; sourceTree = "<group>"; };
2431
40E347BA29452CF1003A19B9 /* Gym Routine Tracker Plus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Gym Routine Tracker Plus.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2532
40E347BD29452CF1003A19B9 /* PlusApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlusApp.swift; sourceTree = "<group>"; };
2633
40E347BF29452CF1003A19B9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -35,6 +42,7 @@
3542
isa = PBXFrameworksBuildPhase;
3643
buildActionMask = 2147483647;
3744
files = (
45+
402A5F32296B835B00A43DB3 /* Tabler in Frameworks */,
3846
40B51E45294549DF0047377A /* GroutUI in Frameworks */,
3947
40E347D329452E4B003A19B9 /* Compactor in Frameworks */,
4048
40EBE1CC29635306004B9189 /* GroutUI in Frameworks */,
@@ -76,6 +84,9 @@
7684
children = (
7785
40E347BD29452CF1003A19B9 /* PlusApp.swift */,
7886
40E347BF29452CF1003A19B9 /* ContentView.swift */,
87+
402A5F2E296B7F7B00A43DB3 /* HistoryView.swift */,
88+
408FACFD296CABC400D02C9C /* RoutineRunList.swift */,
89+
40245EF5296BE7D4007B5DAB /* ExerciseRunList.swift */,
7990
40E347C129452CF1003A19B9 /* Assets.xcassets */,
8091
40EBCFDE294BFB880082A172 /* Info.plist */,
8192
40E347C329452CF1003A19B9 /* App.entitlements */,
@@ -113,6 +124,7 @@
113124
40B51E44294549DF0047377A /* GroutUI */,
114125
40CCF3F529454D2B007DDE69 /* GroutLib */,
115126
40EBE1CB29635306004B9189 /* GroutUI */,
127+
402A5F31296B835B00A43DB3 /* Tabler */,
116128
);
117129
productName = "Gym Routine Tracker Plus";
118130
productReference = 40E347BA29452CF1003A19B9 /* Gym Routine Tracker Plus.app */;
@@ -145,6 +157,7 @@
145157
packageReferences = (
146158
40E347D129452E4B003A19B9 /* XCRemoteSwiftPackageReference "SwiftCompactor" */,
147159
40EBE1CA29635306004B9189 /* XCRemoteSwiftPackageReference "GroutUI" */,
160+
402A5F30296B835B00A43DB3 /* XCRemoteSwiftPackageReference "SwiftTabler" */,
148161
);
149162
productRefGroup = 40E347BB29452CF1003A19B9 /* Products */;
150163
projectDirPath = "";
@@ -174,6 +187,9 @@
174187
buildActionMask = 2147483647;
175188
files = (
176189
40E347C029452CF1003A19B9 /* ContentView.swift in Sources */,
190+
408FACFE296CAC9300D02C9C /* RoutineRunList.swift in Sources */,
191+
40245EF6296BE7D4007B5DAB /* ExerciseRunList.swift in Sources */,
192+
402A5F2F296B7FE000A43DB3 /* HistoryView.swift in Sources */,
177193
40E347BE29452CF1003A19B9 /* PlusApp.swift in Sources */,
178194
);
179195
runOnlyForDeploymentPostprocessing = 0;
@@ -297,7 +313,7 @@
297313
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
298314
CODE_SIGN_ENTITLEMENTS = Sources/App.entitlements;
299315
CODE_SIGN_STYLE = Automatic;
300-
CURRENT_PROJECT_VERSION = 5;
316+
CURRENT_PROJECT_VERSION = 7;
301317
DEVELOPMENT_ASSET_PATHS = "\"Sources/Preview Content\"";
302318
DEVELOPMENT_TEAM = J735QC5U38;
303319
ENABLE_HARDENED_RUNTIME = YES;
@@ -320,7 +336,7 @@
320336
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
321337
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
322338
MACOSX_DEPLOYMENT_TARGET = 13.0;
323-
MARKETING_VERSION = 1.4;
339+
MARKETING_VERSION = 1.5;
324340
PRODUCT_BUNDLE_IDENTIFIER = org.openalloc.grout.plus;
325341
PRODUCT_NAME = "$(TARGET_NAME)";
326342
SDKROOT = auto;
@@ -340,7 +356,7 @@
340356
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
341357
CODE_SIGN_ENTITLEMENTS = Sources/App.entitlements;
342358
CODE_SIGN_STYLE = Automatic;
343-
CURRENT_PROJECT_VERSION = 5;
359+
CURRENT_PROJECT_VERSION = 7;
344360
DEVELOPMENT_ASSET_PATHS = "\"Sources/Preview Content\"";
345361
DEVELOPMENT_TEAM = J735QC5U38;
346362
ENABLE_HARDENED_RUNTIME = YES;
@@ -363,7 +379,7 @@
363379
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
364380
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
365381
MACOSX_DEPLOYMENT_TARGET = 13.0;
366-
MARKETING_VERSION = 1.4;
382+
MARKETING_VERSION = 1.5;
367383
PRODUCT_BUNDLE_IDENTIFIER = org.openalloc.grout.plus;
368384
PRODUCT_NAME = "$(TARGET_NAME)";
369385
SDKROOT = auto;
@@ -400,6 +416,14 @@
400416
/* End XCConfigurationList section */
401417

402418
/* Begin XCRemoteSwiftPackageReference section */
419+
402A5F30296B835B00A43DB3 /* XCRemoteSwiftPackageReference "SwiftTabler" */ = {
420+
isa = XCRemoteSwiftPackageReference;
421+
repositoryURL = "https://github.com/openalloc/SwiftTabler.git";
422+
requirement = {
423+
kind = upToNextMajorVersion;
424+
minimumVersion = 0.9.6;
425+
};
426+
};
403427
40E347D129452E4B003A19B9 /* XCRemoteSwiftPackageReference "SwiftCompactor" */ = {
404428
isa = XCRemoteSwiftPackageReference;
405429
repositoryURL = "https://github.com/openalloc/SwiftCompactor.git";
@@ -419,6 +443,11 @@
419443
/* End XCRemoteSwiftPackageReference section */
420444

421445
/* Begin XCSwiftPackageProductDependency section */
446+
402A5F31296B835B00A43DB3 /* Tabler */ = {
447+
isa = XCSwiftPackageProductDependency;
448+
package = 402A5F30296B835B00A43DB3 /* XCRemoteSwiftPackageReference "SwiftTabler" */;
449+
productName = Tabler;
450+
};
422451
40B51E44294549DF0047377A /* GroutUI */ = {
423452
isa = XCSwiftPackageProductDependency;
424453
productName = GroutUI;

README.md

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1-
# Gym Routine Tracker Plus
1+
# Gym Routine Tracker+
22

33
_A minimalist gym workout tracker, for iPhone and iPad_
44

55
## Download
66

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

99
## Features
1010

11-
- LARGE text in RUN mode, for those with presbyopia. Leave your cheaters in your locker!
12-
- Prioritizes convenience, quick interactions, and the basic needs of the recreational fitness user.
13-
- Available separately, an independent GRT watchOS app
11+
- _NEW in 1.5_ Logs routine/exercise completions, where history can be reviewed on your iPhone/iPad.
12+
13+
- LARGE text in RUN mode, for the farsighted. Leave your glasses in your locker!
14+
- Simple data model of user-defined routines and their exercises.
15+
- Your data syncs with your private iCloud account when a network connection is available.
16+
- Fully open source where code is licensed with Mozilla Public License 2.0.
17+
- Available separately as an independent app for the Apple Watch.
18+
19+
GRT prioritizes convenience, quick interactions, and the basic needs of the recreational fitness user.
1420

1521
### Quick and easy setup
1622

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

28-
### App features
34+
### History features (NEW)
2935

30-
- Simple data model of user-defined routines and their exercises.
31-
- Your data syncs with CloudKit when a network connection is available.
32-
- Fully open source where code is licensed with Mozilla Public License 2.0.
33-
- App available as a free download in the iOS App Store.
36+
- Completion of routine/exercise is automatically logged to your private iCloud account.
37+
- Logging can be disabled in settings.
38+
- 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.
39+
- History can be reviewed on the iOS app for the iPhone/iPad.
40+
41+
### iCloud Sync
42+
43+
- Your data automatically syncs with your private iCloud account when a network connection is available.
44+
- That synced data available to the _Gym Routine Tracker_ app running on your other devices.
3445

3546
## Requirements
3647

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

4758
## See Also
4859

60+
### App Download Links
61+
62+
* [GRT for Apple Watch](https://apps.apple.com/us/app/gym-routine-tracker/id6444747204) - App Store link for FREE download
63+
* [GRT+ for iPhone/iPad](https://apps.apple.com/us/app/gym-routine-tracker/id1662243916) - App Store link for FREE download
64+
65+
### Source Code
66+
4967
* [GRT Website](https://gym-routine-tracker.github.io) - Website for GRT
50-
* [GRT on the App Store](https://apps.apple.com/us/app/gym-routine-tracker/id6444747204) - App Store link for free download of GRT
68+
* [GRT for Apple Watch Source](https://github.com/gym-routine-tracker/Gym-Routine-Tracker-Watch-App) - watchOS implementation
69+
* [GRT+ for iPhone/iPad Source](https://github.com/gym-routine-tracker/Gym-Routine-Tracker-Plus-App) - iOS implementation
5170
* [GroutUI](https://github.com/gym-routine-tracker/GroutUI) - shared UI layer for GRT (watchOS and iOS)
5271
* [GroutLib](https://github.com/gym-routine-tracker/GroutLib) - shared business logic and data layer for GRT
5372

54-
Apps by the same author:
73+
### macOS Apps by the same author
5574

5675
* [FlowAllocator](https://openalloc.github.io/FlowAllocator/index.html) - portfolio rebalancing tool for macOS
5776
* [FlowWorth](https://openalloc.github.io/FlowWorth/index.html) - portfolio valuation and tracking tool for macOS

Sources/App.entitlements

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5+
<key>aps-environment</key>
6+
<string>development</string>
57
<key>com.apple.developer.icloud-container-identifiers</key>
68
<array>
79
<string>iCloud.org.openalloc.grout</string>
10+
<string>iCloud.org.openalloc.grout.archive</string>
811
</array>
912
<key>com.apple.developer.icloud-services</key>
1013
<array>

Sources/ContentView.swift

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,24 @@
88
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
99
//
1010

11+
import CoreData
1112
import SwiftUI
1213

1314
import GroutLib
1415
import GroutUI
1516

1617
struct ContentView: View {
18+
@Environment(\.managedObjectContext) private var viewContext
19+
20+
enum Tabs: Int {
21+
case routines = 0
22+
case history = 1
23+
case settings = 2
24+
}
25+
1726
@SceneStorage("main-tab") private var selectedTab = 0
1827
@SceneStorage("main-routines-nav") private var routinesNavData: Data?
28+
@SceneStorage("main-history-nav") private var historyNavData: Data?
1929
@SceneStorage("main-settings-nav") private var settingsNavData: Data?
2030

2131
var body: some View {
@@ -25,9 +35,19 @@ struct ContentView: View {
2535
RoutineList()
2636
}
2737
.tabItem {
28-
Label("Routines", systemImage: "dumbbell.fill")
38+
Label("Routines", systemImage: "dumbbell")
2939
}
30-
.tag(0)
40+
.tag(Tabs.routines.rawValue)
41+
42+
NavStack(name: "history",
43+
navData: $historyNavData,
44+
routineRunDetail: exerciseRunList) {
45+
HistoryView()
46+
}
47+
.tabItem {
48+
Label("History", systemImage: "fossil.shell")
49+
}
50+
.tag(Tabs.history.rawValue)
3151

3252
NavStack(name: "settings",
3353
navData: $settingsNavData) {
@@ -36,17 +56,26 @@ struct ContentView: View {
3656
.tabItem {
3757
Label("Settings", systemImage: "gear")
3858
}
39-
.tag(1)
59+
.tag(Tabs.settings.rawValue)
60+
}
61+
}
4062

41-
// TODO: history, charts, etc. will be the 'Plus'
63+
// used to inject view into NavStack
64+
@ViewBuilder
65+
private func exerciseRunList(_ routineRunUri: URL) -> some View {
66+
if let zRoutineRun = ZRoutineRun.get(viewContext, forURIRepresentation: routineRunUri),
67+
let archiveStore = PersistenceManager.getArchiveStore(viewContext)
68+
{
69+
ExerciseRunList(zRoutineRun: zRoutineRun, archiveStore: archiveStore)
70+
} else {
71+
Text("Routine Run not available to display detail.")
4272
}
4373
}
4474
}
4575

46-
// TODO: four copies of each routine showing up; should be one!
4776
struct ContentView_Previews: PreviewProvider {
4877
static var previews: some View {
49-
let ctx = PersistenceManager.preview.container.viewContext
78+
let ctx = PersistenceManager.getPreviewContainer().viewContext
5079
let routine = Routine.create(ctx, userOrder: 0)
5180
routine.name = "Back & Bicep"
5281
let e1 = Exercise.create(ctx, userOrder: 0)

0 commit comments

Comments
 (0)