|
|
@@ -20,6 +20,8 @@ struct GymLogDbParsedEntry { |
|
|
|
string name; |
|
|
|
}; |
|
|
|
|
|
|
|
typedef GymLogDbEntry Exercise; |
|
|
|
|
|
|
|
struct GymLogDbParsed { |
|
|
|
GymLogDbHeader header; |
|
|
|
list<GymLogDbParsedEntry> entries; |
|
|
@@ -38,6 +40,11 @@ struct GymLogEntry { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
struct WorkSummary { |
|
|
|
real32 totalWork; |
|
|
|
uint32 restTime; |
|
|
|
}; |
|
|
|
|
|
|
|
GymLogDbParsed *parseDb(Arena *arena, string database) { |
|
|
|
GymLogDbParsed *dbParsed = PushStruct(arena, GymLogDbParsed); |
|
|
|
|
|
|
@@ -73,27 +80,24 @@ list<GymLogEntry> loadEntryLog(Arena *arena, string fileLocation) { |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
struct WorkSummary { |
|
|
|
real32 totalWork; |
|
|
|
uint32 restTime; |
|
|
|
}; |
|
|
|
|
|
|
|
WorkSummary workSummaryForExercise(list<GymLogEntry> entries) { |
|
|
|
WorkSummary workSummaryForExercise(list<GymLogEntry> entries, Exercise exercise) { |
|
|
|
WorkSummary result = {0}; |
|
|
|
UnixTimestamp lastTimestamp = 0; |
|
|
|
for (EachInReversed(entries, i)) { |
|
|
|
GymLogEntry logEntry = entries.data[i]; |
|
|
|
result.totalWork += logEntry.weightRepsInfo.weight * logEntry.weightRepsInfo.reps; |
|
|
|
if (lastTimestamp > 0) { |
|
|
|
result.restTime += (uint32)(lastTimestamp - logEntry.timestamp); |
|
|
|
if (entries.data[i].exerciseId == exercise.id) { |
|
|
|
GymLogEntry logEntry = entries.data[i]; |
|
|
|
result.totalWork += logEntry.weightRepsInfo.weight * logEntry.weightRepsInfo.reps; |
|
|
|
if (lastTimestamp > 0) { |
|
|
|
result.restTime += (uint32)(lastTimestamp - logEntry.timestamp); |
|
|
|
} |
|
|
|
lastTimestamp = logEntry.timestamp; |
|
|
|
} |
|
|
|
lastTimestamp = logEntry.timestamp; |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
int gymTrackerWorkToday(Arena *arena, uint32 exerciseId, string exerciseName) { |
|
|
|
int gymTrackerLogWorkToday(Arena *arena, Exercise exercise) { |
|
|
|
int statusCode = 0; |
|
|
|
string logfile = os_readEntireFile(arena, LOG_FILE_LOCATION); |
|
|
|
|
|
|
@@ -119,8 +123,8 @@ int gymTrackerWorkToday(Arena *arena, uint32 exerciseId, string exerciseName) { |
|
|
|
|
|
|
|
if (todaysEntries.data) { |
|
|
|
todaysEntries.length = todaysEntries.head; |
|
|
|
WorkSummary summary = workSummaryForExercise(todaysEntries); |
|
|
|
log("Total work today for %S:\n%.2fkg in ~%.2fmin.\n", exerciseName, summary.totalWork, (real32)summary.restTime / 60.0f); |
|
|
|
WorkSummary summary = workSummaryForExercise(todaysEntries, exercise); |
|
|
|
log("Total work today for %S:\n%.2fkg in ~%.2fmin.\n", exercise.name, summary.totalWork, (real32)summary.restTime / 60.0f); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
@@ -284,12 +288,13 @@ int gymTrackerDeleteEntries(Arena *arena, list<string> args) { |
|
|
|
// Syntax: do <exercise-name> weightKg reps |
|
|
|
int gymTrackerDo(Arena *arena, list<string> args) { |
|
|
|
int statusCode = 0; |
|
|
|
string exerciseName = {0}; |
|
|
|
Exercise exercise = {}; |
|
|
|
|
|
|
|
if (args.length < 3 || args.data[0].length == 0) { |
|
|
|
log("Invalid exercise name and/or number of arguments.\n"); |
|
|
|
statusCode = 1; |
|
|
|
} else { |
|
|
|
exerciseName = args.data[0]; |
|
|
|
exercise.name = args.data[0]; |
|
|
|
} |
|
|
|
|
|
|
|
GymLogDbParsedEntry *existingEntry = 0; |
|
|
@@ -298,23 +303,23 @@ int gymTrackerDo(Arena *arena, list<string> args) { |
|
|
|
GymLogDbParsed *db = parseDb(arena, os_readEntireFile(arena, DB_FILE_LOCATION)); |
|
|
|
for (EachIn(db->entries, i)) { |
|
|
|
GymLogDbParsedEntry entry = db->entries.data[i]; |
|
|
|
if (strStartsWith(entry.name, exerciseName)) { |
|
|
|
if (strStartsWith(entry.name, exercise.name)) { |
|
|
|
existingEntry = &entry; |
|
|
|
if (entry.name.length != exerciseName.length) { |
|
|
|
exerciseName = entry.name; |
|
|
|
if (entry.name.length != exercise.name.length) { |
|
|
|
exercise.name = entry.name; |
|
|
|
log("Assuming exercise \"%S\".\n\n", entry.name); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!existingEntry) { |
|
|
|
log("The exercise \"%S\" hasn't been registered.", exerciseName); |
|
|
|
log("The exercise \"%S\" hasn't been registered.", exercise.name); |
|
|
|
statusCode = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (statusCode == 0) { |
|
|
|
uint32 exerciseId = existingEntry->id; |
|
|
|
exercise.id = existingEntry->id; |
|
|
|
size_t parsedCount = 0; |
|
|
|
real32 kg = parsePositiveReal32(args.data[1], &parsedCount); |
|
|
|
uint8 reps = parsePositiveInt(args.data[2], &parsedCount); |
|
|
@@ -324,13 +329,13 @@ int gymTrackerDo(Arena *arena, list<string> args) { |
|
|
|
} else { |
|
|
|
GymLogEntry entry = { |
|
|
|
getSystemUnixTime(), |
|
|
|
exerciseId, |
|
|
|
exercise.id, |
|
|
|
reps, |
|
|
|
kg, |
|
|
|
}; |
|
|
|
|
|
|
|
os_fileAppend(arena, LOG_FILE_LOCATION, (byte *)&entry, sizeof(entry)); |
|
|
|
statusCode = gymTrackerWorkToday(arena, exerciseId, exerciseName); |
|
|
|
statusCode = gymTrackerLogWorkToday(arena, exercise); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|