---
# System prepended metadata

title: Workout
tags: [overview, workout-lab]

---

---
title: Workout
tags: workout,overview
---
> [TOC]
## Use cases
 - [ ] Add Terms - https://app.termly.io/
 - [x] Create account
 - [x] Login
 - [x] Logout
 - [ ] Show loading before calendar is ready
 - [ ] Allow reporting duplicate exercise
 - [ ] Bodyparts overview - change "8 days ago" to "more then week ago"
 - [ ] Create public version of workout
 - [ ] Rename workoutlab-3fb75.firebaseapp.com from login screen
 - [ ] Search exercise names in aliases table
 - [x] Add map preview to strava workouts list
 - [ ] Store gpx point encoded in google 
 - [x] Create readonly exercise table
     - [ ] Allow search using aliases
     - [x] Strengthlevel ID
 - [x] Create readonly workout list
     - [ ] Allow filtering
         - [ ] With/Without strava
         - [ ] With/Without sourceFile
 - [ ] Strava 
     - [ ] Strava list
         - [ ] Show matching day/duration/calories/time flags
     - [ ] Show strava workouts which can be mapped to workouts
     - [ ] Show workouts which can be mapped to strava workouts
 - [ ] Google api
 - [ ] add version, buildNumber, buildTime 
     - [ ] to google analytics 
     - [x] to sentry
 - [ ] User detail
     - [ ] Add strava id 
     - [ ] Add runkeeper id
 - [ ] Exercise detail
     - [ ] hide aliases metadata
     - [ ] make category metadata standalone field
     - [ ] Add button "show who practiced this"
     - [ ] Strength level, stats, my stats > move to menu next to hearth
     - [ ] Add workout visibility select
     - [ ] Add workout with multi autocomplete to select users 
 - [ ] Workout detail
     - [ ] Add export workout button
     - [ ] Add share button
     - [ ] 
 - [ ] Exercise record view
     - [ ] change default textarea view height to be equal number of rows
     - [ ] remove record overview on mobiles
 - [ ] Set personal information
     - [x] Birthday
     - [x] Height
     - [x] Weight
     - [x] Gender
     - [ ] TargetWeight
     - [ ] TargetWeightDate
 - [ ] Calculate BMI https://www.calculatorsoup.com/calculators/health/bmi-calculator.php
 - [x] Allow to add file (GPX, Image) as attachment to workout
 - [ ] Allow to create workout from KML format
 - [ ] Create sidenav menu expandable - https://indepth.dev/tutorials/angular/angular-material-nested-menu-dynamic-data
 - [ ] for non dev users
     - [x] hide creation date
 - [ ] GUI Improvements
     - [ ] Create user chip
     - [x] Image preview min-width: min(80vw, 100%);
 - [ ] Created exercises must be approved by approvers
 - [ ] Add color to bodyparts ![](https://i.imgur.com/VuA6fdd.png)
 - [ ] Add functionality from https://www.runloop.com/heavyset
     - [ ] personl records for reps for each exercise
     - [ ] Routines with series and reps withoud weights
 - [ ] Workout overview ![](https://i.imgur.com/qGvbZ0R.png)
 - [ ] Add functionality from https://play.google.com/store/apps/details?id=com.kg.app.sportdiary&hl=en_GB&gl=US
     - [ ] Show received achievemnt after workout's record
     - [ ] Add graph for number of practises for each month for each exercise
     - [ ] Calendar driven workout overview
     - [ ] Rename stats:
         - [ ] Finished exercises/workouts
     - [ ] Max weight and max reps ![](https://i.imgur.com/o59lrf9.png)
 - [ ] show max 1 rep weight graph ![](https://i.imgur.com/Ja4giDV.png)

 - [ ] Create Routine
     - [ ] Set name
     - [ ] Add exercises
     - [ ] Set Reminder
         - [ ] Start date
         - [ ] Until
             - [ ] Number of weeks/days/months
             - [ ] Specific date
             - [ ] X repetations
         - [ ] Send mail notification
 - [x] Create workout
     - [x] Add record to workout
     - [x] Fill properties (start/end date and type, note, place, burned callories)
     - [x] Save workout
 - [ ] Create workout from routine
     - [ ] Choose routine
     - [ ] Fill values for each exercise record
     - [ ] Fill missing properties
     - [ ] Save workout
 - [x] Show exercise records
 - [ ] Clone workout into my workouts
 - [ ] Improve diagrams
     - ![](https://hackmd.io/_uploads/SycYY5tRn.png)
 - [ ] Create routine from workout
 - [ ] Add musscle selector 
   - [x] https://codepen.io/tomaev/pen/dYrEbq 
       - document.querySelectorAll("[class=\"\"]")
   - [ ] https://codepen.io/baublet/pen/PzjmpL
   - [ ] https://codepen.io/MikeLouviere/pen/MyyWNe
 - [ ] Create single record workout creationg page
 - [ ] Create profile card 
 ![](https://hackmd.io/_uploads/r1h8Z6ZAh.png)

 - [ ] Add bite flag for workout about exercises bodyparts
 - [ ] add action row to expandable panel and wrap buttons inside of it
 - [ ] Each workout has either calculated or user defined burned calories
 - [ ] Add visibility option in workoute detail
 - [ ] Handle empty detail actions menu
 - [x] Show my workouts
     - [ ] Export my workouts
 - [x] Edit existing workout
     - [x] Add record to workout
     - [x] Remove record from workout
     - [x] Edit record in workout
     - [x] Edit workout properties
     - [x] Save workout
 - [x] Create exercise record
     - [x] Choose exercise
     - [x] Set attributes (weigth, repetations, note)
     - [x] Save record
 - [x] Exit exercise record
     - [x] Change exercise
     - [x] Edit attributes (weigth, repetations, note)
     - [x] Save record
 - [x] Remove existing workout
 - [ ] Show map for outside activities
 - [ ] Allow to import exercise record from external application
     - [ ] Runkeeper
     - [x] GPX file
     - [ ] Strava
 - [ ] 
 - [ ] Show recommendations
     - [ ] Show which exercies should be practised
 - [ ] Show week/month/year/total stats
     - [x] Number of workouts
     - [ ] Duration
     - [ ] Information for each exercise
         - [ ] Duration, count, percentage
 - [ ] Show stats for exercise
     - [ ] Maximal repetations/weight
     - [ ] List of dates when it was practise
 - [ ] Social
     - [ ] Search users
     - [x] Add/remove  friend
         - [ ] Friends are automatically fallowed
     - [x] Show user detail page


### Create workout
#### online
```plantuml
start

:click on new workout button;
:select start date and time;
:optionally select end date and time;
repeat :click on save button;
    :send request to server;
    :wait for response;
    backward :fix all issues;
    repeat while (Error response) is (true)
-> no;
:show success notification;
:update store;

:redirect to detail of workout;
stop
```
#### offline
```plantuml
start

:click on new workout button;
:select start date and time;
:optionally select end date and time;
repeat :click on save button;
    :validate workout locally;
    backward :fix all issues;
    repeat while (validation failed) is (true)
-> no;
:save request to localstorage;
:show success notification;
:update store and add flag that workout is not saved on server;
:redirect to detail of workout;
stop
```

## Endpoints
### Workout
 - `[GET] /workout`
     - minDate - minimal start date
     - maxDate - maximal end date
     - year - get workouts for specific year
     - month - get workouts for specific month
     - week - get workouts for specific week
     - minDuration - minimal duration
     - maxDuration - maximal duration
     - bodyPart - filter for workout with exercises for specific body parts
     - orderBy - creationDate, startDate, duration, callories
     - orderDirection - asc, desc
 - `[POST] /workout`
     - Create new workout
 - `[GET] workout/:workoutId`
     - Get workout detail
 - `[PUT] workout/:workoutId`
     - Update workout
 - `[DELETE] workout/:workoutId`
     - Delete workout
 - `[GET] workout/:workoutId/exercise_records`
     - Same as as /exercise_record but for specific workout
 - `[POST] workout/:workoutId/exercise_records`
    - Same as as /exercise_record but for specific workout
### Exercises
 - exercise
     - Get
         - Get list of exercises
             - bodyPart - body part or list of body parts
             - key - search by name
             - orderBy - creationDate, name
             - orderDirection - asc, desc
     - Post
         - Create new exercise
 - exercise/{exerciseId}
     - Get 
         - Get exercise detail
     - Put
         - Update exercise
     - Delete
         - Delete exercise
### Exercise records
 - exercise_record/{exertciseRecordId}
     - Get 
         - Get exercise record detail
     - Put
         - Update exercise record
     - Delete
         - Delete exercise record
 - exercise_record
     - Get
         - Get exercise records
     - Post
         - Create exercise record
### User
 - user
     - Get
         - Get list of users
             - key - pattern for user name
             - orderBy - creationDate, name, numberOfWorkouts, followers
             - orderDirection - asc, desc
     - Post
         - Create new user
 - user/{userId}/socials/addFriend/{targetUserId}
     - Post
         - Add friend to user
 - user/{userId}/socials/removeFriend/{targetUserId}
     - Post
         - Remove friend from user
 - user/{userId}/socials/follow/{targetUserId}
     - Post
         - Follow user
 - user/{userId}/socials/unfollow/{targetUserId}
     - Post
         - Unfollow user
 - user/{userId}/profile
     - Get 
         - Get user profile
 - user/{userId}/stats/{weekly,monthly,yearly}
     - Get 
         - Get user weekly,monthly,yearly stats
 - user/{userId}/workout
     - Get 
         - Same as /workout but for specific user
## Models

### Workout

Single workout session. Include multiple exertice records
```plantuml
@startmindmap
* Workout
** ID
** CreationDate
** StartDate
** EndDate
** Comment
** ExerciseRecords
** BurnedCallories
@endmindmap
```
### Exercise

F - Forbitten
R - Required
O - Optional
| Parameter | Create | Update |
| -------- | -------- | -------- |
| ID     | F     | R     |
|Name|R|O|
|type|R|O|
|bodypart|R|O|
|creationDate|F|F|
|description|O|O|
|createdBy|F|F|
|standing|O|O|
|outside|O|O|
|difficulty|O|O|


Exercise definition
```plantuml
@startmindmap
* Exercise
** Id
** Description
** CreatedBy
** CreationDate
** Image
** Visible for (me/friends/all)
** Bodypart string or bodyparts
** Required/Optional properties
*** Duration
*** Distance
*** Repetitions
*** Weight
*** Series
*** Equipment
*** GPX for running
*** Avg Heart Rate in BPM
@endmindmap
```
### App stats
Exercises: all/approved
Bodypart histogram
Category histogram

Workouts total number
Users total number

Graphs
 - number/hours of workouts per months
### Exercise stats

#### BasicExerciseStatistics
| Name | Type | Description |
| -------- | -------- | -------- |
| totalNumberOfExercising     | number     |      |
| maxRepetitions | number     |      |
| maxWeight | number     |      |
| maxLifted | number     |      |
| maxWeightForReps     | `{ [reps in number]: number }`     |      |
| maxRepsForWeight     | `{ [weight in number]: number }`     |      |

#### ExerciseStatistics extends [BasicExerciseStatistics](BasicExerciseStatistics)
| Name | Type | Description |
| -------- | -------- | -------- |
| uniqueUsersExercisingThisExercise     | number     |      |
| id     | ExerciseId     |      |
| updatedTime | string     |      |
| favouriteBy | `{date: string; value: number}`     |      |


### User stats
#### UserExerciseStats extends [BasicExerciseStatistics](BasicExerciseStatistics)
| Name | Type | Description |
| -------- | -------- | -------- |
| exerciseId     | ExerciseId     |      |
| userId     | UserId     |      |
| updatedTime | string     |      |
| yearStats | `{ [year in number]: BasicExerciseStatistics }`     |      |
| monthStats | `{ [month in number]: BasicExerciseStatistics }`     |      |

#### UserWorkoutStats
| Name | Type | Description |
| -------- | -------- | -------- |
| exerciseHistogram     | `[key: string, value: number, exerciseId: ExerciseId][]`     |      |
| bodypartHistogram     | `[key: BodyPart, value: number][]`     |      |
| totalExercises | number     |      |
| iniqueExercises | number | | 
| totalWorkouts | number | | 
| totalWorkoutDuration | number | | 
| maxWorkoutDuration | number | | 
| totalBurnedCalories | number | | 
| maxBurnedCalories | number | | 
### CustomExercise
Exercise created by user
```plantuml
@startmindmap
* CustomExercise
** Extends Exercise
** VerifiedBy
*** UserId
*** DateOfVerification
** Active/Inactive
** CreatedBy: UserId
** Type
*** Weight
**** Repetations
**** Series
**** Weight
*** Duration
**** Duration
*** Run
**** Distance
**** Duration
**** Average speed
*** Body weight
**** Repetations
**** Series
@endmindmap
```

### ExerciseRecord
```plantuml
@startmindmap
* ExerciseRecord
** ID
** Type:Exercise or CustomExercise
** Date
** Properties for Exercise
@endmindmap
```
### Routine
- Template for exercises for one workout
- Contains one or more exercises
- Cant have reminders
## Exercises
```plantuml
@startmindmap
* Exertices
** Pushup
*** Normal
*** Knee pushup
*** Pike pushups
*** One-legged pushup
** Abs
*** Bicycle crunch
*** Hollow hold to jackknife
*** Plank
**** One-leg Plank
**** One-arm Plank
**** Side plank
***** Side plank with hip abduction
** Squat
*** Overhead squat
** Lunge
*** Stationary lunge
*** Walking lunge
*** Jumping lunges
*** Elevated pike pushups
** Plank to Downward Dog
** Bird Dog
*** Advanced Bird Dog
** Dead bug
@endmindmap
```
Knee pushup

## Jobs

### CalculateExerciseStats
 - cons MIN_RECALCULATION_OFFSET ~= 1 day

 - find some exercise when metadata are missing
     - if no one found then find metadat when now() - m.updatedTime > MIN_RECALCULATION_OFFSET

 - find all workouts where creationDate > m.updateTime and has record with r.exerciseId === m.exerciseId
 - generate new ExerciseMetadata from workouts
     - updateDate is now
 - merge previous and new (or set new if previous are missing) ExerciseMetadata


## Relations
### Database

```plantuml
struct WorkoutId 
struct ExerciseId
struct ExerciseRecordId
struct UserId 
class Workout {
    +id: WorkoutId
    +createdBy: UserId
    +ownerId: UserId
    +member: UserId
    +participants?: UserId[]
    +creationDate: DateTime
    +updateDate: DateTime
    +deletionDate?: DateTime
    +sourceFileName?: string
    +startDate: DateTime
    +records: WorkoutRecord[]
    +visibility: PUBLIC | PRIVATE
    +endDate?: DateTime
    +burendCalories: number
    +userDefinedBurnedCalories?: number
    +averageHeartBear: nubmber;
    +note: string
}

enum BodyPart {
    ABDOMINAL
    BACK
    BICEPS
    CHEST
    SHOULDERS
    CALVES
    LEGS
    TRICEPS
}
enum ExerciseType {
    WEIGHT 
    BODY_WEIGHT
    DISTANCE
    DURATION
}
class Exercise {
    +id: ExerciseId
    +description: string
    +bodypars: BodyPart[]
    +secondaryBodypars: BodyPart[]
    +creationDate: DateTime
    +deletionDate?: DateTime
    +image?: "storage"
    +createdBy: UserId
    +standing?: boolean
    +outside?: boolean
    +MET?: number
    +type: ExerciseType
    +image: string
    +variationOf?: ExerciseId
    +similar?: ExerciseId[]
}

class ExerciseRecord {
    +id: ExerciseRecordId
    +workoutId: WorkoutId
    +creationDate: DateTime
    +deletionDate?: DateTime
    +note?: string
    +items: ExerciseRecordItem[]
}
class ExerciseRecordItem {
    +repetitions?: number
    +weight?: number
    +duration?: number
    +series?: number
    +distance?: number
}

ExerciseId <-- ExerciseRecord 
WorkoutId <-- ExerciseRecord 

Workout --> WorkoutId
Workout --> UserId
Workout --> ExerciseId

ExerciseId <-- Exercise
UserId <-- Exercise
Exercise --> ExerciseType
Exercise --> BodyPart
ExerciseRecordItem <-- ExerciseRecord
ExerciseRecordId <-- ExerciseRecord

note left of Workout::participants
    Additional participants 
    (Owner is participant by default)
end note
note left of Exercise::variationOf
    Some exercises could be 
    extendsion for another exercises
end note
hide empty members
```
### Database - sets
```plantuml
enum SetEntryType {
    +BREAK
    +DURATION
    +REPETITIONS
}
interface SetEntry {
    +exerciseId: ExerciseId
    +type: SetEntryType
    +series?: number
    +duration?: number
    +repetitions?: number
}
class Set {
    +id: SetId
    +creationDate: DateTime
    +createdBy: UserId
    +entries: SetEntry[]
}

SetEntryType <-- SetEntry
SetEntry <-- Set

note right of SetEntry::series
  If this is omited then value 1 is used
end note


hide empty members
```
### Database - metadata
```plantuml
interface RepSetEntry {
    reps: number
    sets: number
    count: number
}
interface DateTimeValue {
    date: DateTime
    value: number
}
interface BasicExerciseMetadata {
    mostRepsAndSets?: RepSetEntry[]
    maxRepetitions: number
    maxWeight: number
    maxLifted: number
    maxWeightForReps: Map<number, number>
    recordsForReps: Map<number, number>
}
class ExerciseMetadata implements BasicExerciseMetadata {
    id: ExerciseId
    updateDate: DateTime
    favouriteBy: DateTimeValue[]
}
interface BasicUserExerciseMetadata extends BasicExerciseMetadata {
    maxWeightOverTime: DateTimeValue[]
    maxLiftedOverTime: DateTimeValue[]
}
class UserMetadata {
    id: UserId
    updateDate: DateTime
    longestWorkout: number
    longestDistance: number
    fastestPace: number
    mostBurnedCalories: number
    minAverageHeartBeat: number
    maxAverageHeartBeat: number
    createdExercises: number
    finishedExercise: number
    finishedWorkouts: number
    exerciseRecords: Map<ExerciseId, BasicUserExerciseMetadata>
}

RepSetEntry <-- BasicExerciseMetadata
BasicUserExerciseMetadata <-- UserMetadata

note right of BasicExerciseMetadata::mostRepsAndSets
  Only for exercise of type WEIGHT
end note
note right of BasicExerciseMetadata::maxRepetitions
  Maximal repetitions in one series
end note
note right of BasicExerciseMetadata::maxWeight
  value from recordsForReps[1]
end note
note right of BasicExerciseMetadata::maxLifted
  Series * Reps * Weight
end note
hide empty members
```
### API

```plantuml
interface NamedUserDTO {
    +id: UserId
    +name: string
}
interface UserDTO extends NamedUserDTO {
    +avatar: string
}
interface UserDetailDTO extends UserDTO {
    +properties: any
    +preferences: any
}
interface WorkoutDTO {
    +id: WorkoutId
    +startDate: DateTime
    'Duration in MS
    +endDate: DateTime
    +owner: NamedUserDTO
}
interface WorkoutDetailDTO extends WorkoutDTO{
    +records: ExerciseRecord[]
}
interface ExerciseDTO {
    +id: ExerciseId
    +description: string
    +bodypars: BodyPart[]
    +image: string
}
interface ExerciseDetailDTO extends ExerciseDTO {
    +creationDate: DateTime
}
interface ExerciseRecordDTO {
    +id: ExerciseRecordId
    +exercise: Exercise
    +properties: JsonObject
    +items: WorkoutItemDTO[]
}

interface WorkoutItemDTO {
    +weight?: number
    +repetitions?: number
    +series?: number
    +points?: WorkoutItemPointDTO[]
}

interface WorkoutItemPointDTO {
    +lat: number
    +long: number
    +altitude: number
    +timeOffset: number
}
WorkoutItemDTO *-- WorkoutItemPointDTO
ExerciseRecordDTO *-- WorkoutItemDTO
WorkoutDTO *-- NamedUserDTO
WorkoutDetailDTO *-- ExerciseRecordDTO
ExerciseRecordDTO *-- ExerciseDTO
hide empty members
```
#### API examples
##### Workout detail
###### bench press
```plantuml
@startjson
{
    "id": "0caf6d5b-6b45-452b-ac11-bac6181c9578",
    "startDate": "2023-04-17T07:09:29.780Z",
    "endDate": "2023-04-17T07:58:29.780Z",
    "owner": {
        "id": "fc0a9b94-ef77-46b5-b7aa-31b469608912",
        "name": "Some User "
    },
    "records": [
        {
            "id":"51e31ea1-d453-416b-a580-61327400a150",
            "exercise": {
                "id":"f0d5091b-a7d6-4e58-bc82-134b9b511c22",
                "name": "Bench press",
                "bodyparts": ["CHEST"],
                "image":"https://workout-lab/exercises/f0d5091b-a7d6-4e58-bc82-134b9b511c22/image/320.png"
            },
            "items": [
                {
                    "weight": 80,
                    "series": 2,
                    "repetitions": 12
                },
                {
                    "weight": 80,
                    "series": 2,
                    "repetitions": 10
                }
            ]
        }
    ]
}
@endjson
```
###### Running
```plantuml
@startjson
{
    "id": "0caf6d5b-6b45-452b-ac11-bac6181c9578",
    "startDate": "2023-04-17T07:09:29.780Z",
    "endDate": "2023-04-17T07:58:29.780Z",
    "owner": {
        "id": "fc0a9b94-ef77-46b5-b7aa-31b469608912",
        "name": "Some User "
    },
    "records": [
        {
            "id":"51e31ea1-d453-416b-a580-61327400a150",
            "exercise": {
                "id":"f0d5091b-a7d6-4e58-bc82-134b9b511c22",
                "name": "Running",
                "bodyparts": ["EGS"],
                "image":"https://workout-lab/exercises/f0d5091b-a7d6-4e58-bc82-134b9b511c22/image/320.png"
            },
            "items": [
                {
                    "lat": 80,
                    "long": 2,
                    "altitude": 12,
                    "timeOffset": 0
                },
                {
                    "lat": 80,
                    "long": 2,
                    "altitude": 13,
                    "timeOffset": 2000
                }
            ]
        }
    ]
}
@endjson
```

## Operations
### Create template
```plantuml
interface Template {
    +creationDate: string
}
interface ParsedTemplate {
    +creationDate: string
}
interface WorkoutCreation {
    
}
hide empty members
```

```plantuml
@startuml
box Client
participant User
participant TemplateComponent
participant TemplateService
end box
box Server
participant WorkoutController
participant WorkoutService
participant ExerciseService
end box

User -> TemplateComponent: paste text
TemplateComponent -> TemplateService: parseTemplate(template)
TemplateComponent <- TemplateService: ParsedTemplate
User -> TemplateComponent: submit form
TemplateComponent -> TemplateService: submitTemplate()

TemplateService --> WorkoutController: [POST]


WorkoutController -> WorkoutService: processTemplate(template)
WorkoutService -> ExerciseService: findExercisesByNames(names)
WorkoutService <-- ExerciseService
WorkoutController  <-- WorkoutService

TemplateService <-- WorkoutController: response

==Try to get exercise names== 

TemplateService -> TemplateComponent: showExercisesTable()

opt Some exercises are incorrect
    loop For each incorect exrcise 

        alt Exercise is second options in reasult
            User -> TemplateComponent: click context menu
            User -> TemplateComponent: choose correct exercise
        else Exercise wasn't found or is missing in found exercises
            User -> TemplateComponent: click context menu
            User -> TemplateComponent: click on search button
            TemplateComponent -> TemplateComponent: showExerciseLookupDialog()
            User -> TemplateComponent: search and select correct exercise
        end 
    end
end
User -> TemplateComponent: confirm exercises

TemplateComponent -> TemplateService: WorkoutCreation()
TemplateService --> WorkoutController: [POST]

WorkoutController -> WorkoutService: createWorkoutCreation(parsedTemplate)
WorkoutController <-- WorkoutService

TemplateService <-- WorkoutController
==Show creating workout overview== 
TemplateService -> TemplateComponent: Show overview()

opt Some fields are incorrect
User -> TemplateComponent: update field
end 
User -> TemplateComponent: click create button
TemplateComponent -> TemplateService: createWorkoutFromTemplate(WorkoutCreation, ParsedTemplate)


TemplateService --> WorkoutController: [POST]
WorkoutController --> WorkoutService: createWorkoutFromTemplate(WorkoutCreation, ParsedTemplate)

WorkoutService -> ExerciseService: update searched exercise names and choosen ones inside tabase

@enduml
```

### Import external file
```plantuml
@startuml
Client --> WorkoutController: processFile(File, ProcessFileOptions)
WorkoutController --> WorkoutService: processFile(File, ProcessFileOptions)
WorkoutService --> WorkoutService: validateUserPermission(User, PROCESS)
WorkoutService --> FileImporter: processFile(File, ProcessFileOptions)
FileImporter --> FileImporter: processFileLocaly(File, ProcessFileOptions)
FileImporter --> FileProcessor: processFile(File, ProcessFileOptions)
FileImporter <- FileProcessor: CompactWorkoutCreateDto
FileImporter --> WorkoutBurnedCaloriesCalculator: getCaloriesFor()
FileImporter <- WorkoutBurnedCaloriesCalculator: number
WorkoutService<- FileImporter: CompactWorkoutCreateDto
WorkoutController <- WorkoutService: CompactWorkoutCreateDto
Client <-- WorkoutController: CompactWorkoutCreateDto
@enduml
```
### Get workout detail/list
```plantuml
@startuml
Client --> WorkoutController: getWorkout(WorkoutId)
WorkoutController --> WorkoutService: getWorkout(WorkoutId)
WorkoutService --> WorkoutService: validateUserPermission(USER, READ)
WorkoutService --> WorkoutDatabase: getWorkout(WorkoutId)
WorkoutDatabase --> DB
WorkoutDatabase <- DB: WorkoutModel
WorkoutDatabase -> WorkoutDatabase: WorkoutModelToWorkout(WorkoutModel)
WorkoutService <- WorkoutDatabase: SimpleWorkout
WorkoutService -> WorkoutService: getWorkoutUsers(SimpleWorkout)
WorkoutService -> WorkoutService: getWorkoutExercises(SimpleWorkout)
WorkoutService --> ExerciseService:getExercisesByIds(Array<ExerciseId>)
WorkoutService --> UserService:getUsersByIds(Array<UserId>)
WorkoutService -> WorkoutService: createWorkout(WorkoutModel, Array<Exercise>, Array<User>)
WorkoutController  <- WorkoutService : Workout
Client <- WorkoutController  : Workout
@enduml
```
### Create workout
```plantuml
@startuml
Client --> WorkoutController: createWorkout(WorkoutCreateDto)
WorkoutController --> WorkoutService: createWorkout(WorkoutCreateDto, User)
WorkoutService --> WorkoutService: validateUserPermission(USER, READ)
group is has missing burned calories
WorkoutService -> CaloriesCalculator: calculateCalories(WorkoutCreateDto)
WorkoutService <- CaloriesCalculator: BurnedCalories
WorkoutService -> WorkoutService: setCaloriesToWorkout()
end
WorkoutService --> WorkoutDatabase: createWorkout(WorkoutCreateDto, User)
WorkoutDatabase --> DB
WorkoutDatabase <- DB: WorkoutModel
WorkoutDatabase -> WorkoutDatabase: WorkoutModelToSimpleWorkout()
WorkoutService <- WorkoutDatabase: SimpleWorkout
WorkoutService--> WorkoutService: SimpleWorkoutToWorkout()
WorkoutController  <- WorkoutService : Workout
Client <- WorkoutController  : Workout
@enduml
```
### Calculate exercise statistics

### Calculate exercise user statistics

### Calculate user statistics
## Screens 

### Home screen
{%figma https://www.figma.com/file/SigS4MEFM8u1BUT9j8YZhX/WorkoutLogger?node-id=201%3A4
%}
### List of exercises
{%figma https://www.figma.com/file/SigS4MEFM8u1BUT9j8YZhX/WorkoutLogger?node-id=204%3A90
%}
### Exercise detail
{%figma https://www.figma.com/file/SigS4MEFM8u1BUT9j8YZhX/WorkoutLogger?node-id=203%3A16
%}
### Add exercise
### Add Workout 
#### Empty workout preview

```plantuml
@startsalt
{^"Create workout"
  [Add exercise<&plus>]
  [<color:#9a9a9a>Save] | [Cancel]
}
@endsalt
```

#### Add exercise dialog
```plantuml
@startsalt
{^"Add Exercise record dialog"
  ^Choose exercise record^ 
}
@endsalt
```
```plantuml
@startsalt
{^"Add Exercise record dialog"
  ^Choose Exercise record^^ Normal pushup^^ Knee pushup^
}
@endsalt
```

```plantuml
@startsalt
{^"Add Exercise record dialog"
  ^Normal Pushup^ 
  Repetitions | "12"
  Series | "5"
  Duration | "  "
}
@endsalt
```
{%figma https://www.figma.com/file/SigS4MEFM8u1BUT9j8YZhX/WorkoutLogger?node-id=284%3A667
%}
#### Save workout
```plantuml
@startsalt
{^"Create workout"
  Normal pushups (12 * 5) | ["Remove"<&trash>]
  [Add exercise<&plus>]
  [Save] | [Cancel]
}
@endsalt
```
### Workout detail
### List of workouts
{%figma https://www.figma.com/file/SigS4MEFM8u1BUT9j8YZhX/WorkoutLogger?node-id=204%3A125
%}

## TODO
 - [ ] Optimize user activities logging to bulk update
 - [ ] Add 'create workout' icon to toolbar
 - [ ] Exercise lookup component
 - [ ] Add favourite exercises to the menu
 - [ ] Multi workout overview
 - [ ] Allow to create empty workout
     - [ ] Simple way to add exerciseRecord
 - [x] Hide error notification after logout
 - [x] Add default permissions for new users
 - [ ] Create separate endpoint for update exercise records
 - [ ] Statistics https://codepen.io/marcnewport/pen/xEKWpz
 - [ ] Realtime recording https://codepen.io/echodean/details/EEyGzZ
 - [ ] Add more bodyparts
		- rear_deltoids
		- soleus_muscle
		- triceps
		- traps
		- lats
		- mid_back
		- low_back
		- glutes
		- hamstring
		- calves
		- quads
		- abs
		- forearms
		- biceps
		- chest
		- shoulders
		- neck



## Features

#### Simple overview of your workouts
![](https://hackmd.io/_uploads/rk2ybA6A3.png)
##### Workout statistics
![](https://i.imgur.com/icuMXRl.png)
#### Exercise detail
![](https://i.imgur.com/Y2oKsts.png)
##### Exercise statistics
![](https://hackmd.io/_uploads/SkYr-06A2.png)
##### My exercise statistics 
![](https://hackmd.io/_uploads/SJys-0TC2.png)
#### User profile
##### User properties
![](https://i.imgur.com/rNok6YH.png)
##### Customizable 
![](https://i.imgur.com/hcLFM9D.png)
##### User statistics
![](https://hackmd.io/_uploads/BydR-RaC3.png)
#### Workout detail 
![](https://i.imgur.com/UkMoTkE.png)
##### With simple exercise recods preview
![](https://i.imgur.com/cW7NVML.png)
#### Dark/Light theme 
![](https://i.imgur.com/PPURUxM.png)
#### Workout statistics 
![](https://i.imgur.com/JXbRkzV.png)


## Future features
#### Offline support
#### Advanced workout recommendations
#### Realtime mode for breaks timeout, voice commands
#### File import (GPX, KML)
#### Allow exporting to different formats
#### Add share options (facebook, twitter)
#### Realtime running tracker (Like Runkeeper)
#### Advanced graphs and statistics
#### Integration with external apps (Runkeeper, Strava, Huawei Health, Zepp life)

