[Pharo] Personal fitness tracker web app.
Dialog components for adding a workout and its exercises.
Changed files
src/MyFitnessTracker/MFTExerciseDialog.class.st
@@ -0,0 +1,159 @@
1
Added:
Class {
2
Added:
#name : #MFTExerciseDialog,
3
Added:
#superclass : #SBSComponent,
4
Added:
#instVars : [
5
Added:
'exercise',
6
Added:
'sets',
7
Added:
'addOrEdit'
8
Added:
],
9
Added:
#classInstVars : [
10
Added:
'exercise'
11
Added:
],
12
Added:
#category : #'MyFitnessTracker-Dialogs'
13
Added:
}
14
Added:
15
Added:
{ #category : #accessing }
16
Added:
MFTExerciseDialog >> addOrEdit [
17
Added:
18
Added:
^ addOrEdit
19
Added:
]
20
Added:
21
Added:
{ #category : #accessing }
22
Added:
MFTExerciseDialog >> addOrEdit: aRole [
23
Added:
24
Added:
addOrEdit := aRole
25
Added:
]
26
Added:
27
Added:
{ #category : #accessing }
28
Added:
MFTExerciseDialog >> exercise [
29
Added:
30
Added:
^ exercise
31
Added:
]
32
Added:
33
Added:
{ #category : #accessing }
34
Added:
MFTExerciseDialog >> exercise: aMFTExercise [
35
Added:
36
Added:
exercise := aMFTExercise
37
Added:
]
38
Added:
39
Added:
{ #category : #initialization }
40
Added:
MFTExerciseDialog >> initialize [
41
Added:
42
Added:
super initialize.
43
Added:
exercise := MFTExercise new.
44
Added:
sets := OrderedCollection new.
45
Added:
addOrEdit := #add
46
Added:
]
47
Added:
48
Added:
{ #category : #rendering }
49
Added:
MFTExerciseDialog >> renderAddSetRowOn: html [
50
Added:
51
Added:
html tableRow: [
52
Added:
html tableData: [
53
Added:
html outlineButton
54
Added:
bePrimary;
55
Added:
beSmall;
56
Added:
callback: [ sets add: MFTSet new ];
57
Added:
with: 'Add' ].
58
Added:
html
59
Added:
tableData;
60
Added:
tableData ]
61
Added:
]
62
Added:
63
Added:
{ #category : #rendering }
64
Added:
MFTExerciseDialog >> renderContentOn: html [
65
Added:
66
Added:
html container: [
67
Added:
html heading: addOrEdit capitalized , ' exercise'.
68
Added:
html form: [
69
Added:
self renderExerciseSelectOn: html.
70
Added:
self renderSetsTableOn: html.
71
Added:
self renderSubmitExerciseOn: html ] ]
72
Added:
]
73
Added:
74
Added:
{ #category : #rendering }
75
Added:
MFTExerciseDialog >> renderExerciseSelectOn: html [
76
Added:
77
Added:
html formGroup: [
78
Added:
html label: 'Exercise'.
79
Added:
html select formControl
80
Added:
list: MFTUtils allExercises;
81
Added:
selected: exercise;
82
Added:
labels: [ :each | each name ];
83
Added:
callback: [ :value | exercise := value ] ]
84
Added:
]
85
Added:
86
Added:
{ #category : #rendering }
87
Added:
MFTExerciseDialog >> renderSetsRowsOn: html [
88
Added:
"TODO: something fishy is going on here. Why are reps and rpe instantiated as nil, but become the empty string after adding additional empty sets?"
89
Added:
90
Added:
sets doWithIndex: [ :set :i |
91
Added:
html tableRow: [
92
Added:
html tableData: [
93
Added:
html buttonGroup: [
94
Added:
html outlineButton
95
Added:
beSecondary;
96
Added:
beSmall;
97
Added:
callback: [ sets removeAt: i ];
98
Added:
with: 'Remove'.
99
Added:
html outlineButton
100
Added:
beSecondary;
101
Added:
beSmall;
102
Added:
callback: [ sets add: set afterIndex: i ];
103
Added:
with: 'Duplicate' ] ].
104
Added:
html tableData: [
105
Added:
html numberInput
106
Added:
placeholder: 10;
107
Added:
value: set reps;
108
Added:
callback: [ :value | value ifNotNil: [ set reps: value ] ] ].
109
Added:
html tableData: [
110
Added:
html numberInput
111
Added:
placeholder: 80;
112
Added:
value: set rpe;
113
Added:
callback: [ :value | value ifNotNil: [ set rpe: value ] ] ] ] ]
114
Added:
]
115
Added:
116
Added:
{ #category : #rendering }
117
Added:
MFTExerciseDialog >> renderSetsTableOn: html [
118
Added:
119
Added:
html formGroup: [
120
Added:
html label: 'Sets'.
121
Added:
html table
122
Added:
class: 'table table-hover';
123
Added:
with: [
124
Added:
sets ifNotEmpty: [ self renderTableHeaderOn: html ].
125
Added:
self renderSetsRowsOn: html.
126
Added:
self renderAddSetRowOn: html ] ]
127
Added:
]
128
Added:
129
Added:
{ #category : #rendering }
130
Added:
MFTExerciseDialog >> renderSubmitExerciseOn: html [
131
Added:
132
Added:
html formGroup: [
133
Added:
"html text: (sets collect: #reps).
134
Added:
html break.
135
Added:
html text: (sets collect: #rpe)."
136
Added:
html buttonGroup: [
137
Added:
html formButton
138
Added:
bePrimary;
139
Added:
beSubmit;
140
Added:
callback: [
141
Added:
sets removeAllSuchThat: [ :each |
142
Added:
each reps isNil or: [ each reps = '' ] ].
143
Added:
self answer: (exercise sets: sets) ];
144
Added:
with: 'Submit'.
145
Added:
html formButton
146
Added:
beSecondary;
147
Added:
callback: [ self answer: nil ];
148
Added:
with: 'Cancel' ] ]
149
Added:
]
150
Added:
151
Added:
{ #category : #rendering }
152
Added:
MFTExerciseDialog >> renderTableHeaderOn: html [
153
Added:
154
Added:
html tableHead: [
155
Added:
html
156
Added:
tableHeading;
157
Added:
tableHeading: 'Reps';
158
Added:
tableHeading: 'RPE' ]
159
Added:
]
src/MyFitnessTracker/MFTWorkoutDialog.class.st
@@ -0,0 +1,195 @@
1
Added:
Class {
2
Added:
#name : #MFTWorkoutDialog,
3
Added:
#superclass : #SBSComponent,
4
Added:
#instVars : [
5
Added:
'workout',
6
Added:
'addOrEdit'
7
Added:
],
8
Added:
#category : #'MyFitnessTracker-Dialogs'
9
Added:
}
10
Added:
11
Added:
{ #category : #adding }
12
Added:
MFTWorkoutDialog >> addExercise [
13
Added:
14
Added:
| exercise |
15
Added:
exercise := self call: MFTExerciseDialog new.
16
Added:
exercise ifNotNil: [ workout exercises add: exercise ]
17
Added:
]
18
Added:
19
Added:
{ #category : #accessing }
20
Added:
MFTWorkoutDialog >> addOrEdit [
21
Added:
22
Added:
^ addOrEdit
23
Added:
]
24
Added:
25
Added:
{ #category : #accessing }
26
Added:
MFTWorkoutDialog >> addOrEdit: aRole [
27
Added:
28
Added:
addOrEdit := aRole
29
Added:
]
30
Added:
31
Added:
{ #category : #'as yet unclassified' }
32
Added:
MFTWorkoutDialog >> editExercise: i [
33
Added:
34
Added:
| oldExercise newExercise |
35
Added:
oldExercise := workout exercises at: i.
36
Added:
newExercise := self call: (MFTExerciseDialog edit: oldExercise).
37
Added:
newExercise ifNotNil: [ workout exercises at: i put: newExercise ]
38
Added:
]
39
Added:
40
Added:
{ #category : #initialization }
41
Added:
MFTWorkoutDialog >> initialize [
42
Added:
43
Added:
super initialize.
44
Added:
workout := MFTWorkout new.
45
Added:
addOrEdit := #add
46
Added:
]
47
Added:
48
Added:
{ #category : #rendering }
49
Added:
MFTWorkoutDialog >> renderAddExerciseButtonOn: html [
50
Added:
51
Added:
html outlineButton
52
Added:
bePrimary;
53
Added:
beSmall;
54
Added:
callback: [ self addExercise ];
55
Added:
with: 'Add'
56
Added:
]
57
Added:
58
Added:
{ #category : #rendering }
59
Added:
MFTWorkoutDialog >> renderAddExerciseRowOn: html [
60
Added:
61
Added:
html tableRow: [
62
Added:
html tableData: [ self renderAddExerciseButtonOn: html ].
63
Added:
1 to: 3 do: [ :each | html tableData ] ]
64
Added:
]
65
Added:
66
Added:
{ #category : #rendering }
67
Added:
MFTWorkoutDialog >> renderContentOn: html [
68
Added:
69
Added:
html container: [
70
Added:
html heading: 'Add workout'.
71
Added:
html form: [
72
Added:
self renderDateInputOn: html.
73
Added:
self renderExercisesTableOn: html.
74
Added:
self renderPrimaryMuscleSelectOn: html.
75
Added:
"TODO: use the workout guessPrimaryMuscle."
76
Added:
self renderSecondaryMusclesSelectOn: html.
77
Added:
self renderSubmitWorkoutOn: html ] ]
78
Added:
]
79
Added:
80
Added:
{ #category : #rendering }
81
Added:
MFTWorkoutDialog >> renderDateInputOn: html [
82
Added:
83
Added:
html formGroup: [
84
Added:
html label: 'Date'.
85
Added:
html dateInput5 formControl
86
Added:
value: workout date yyyymmdd;
87
Added:
callback: [ :date | workout date: (Date fromString: date) ] ]
88
Added:
]
89
Added:
90
Added:
{ #category : #rendering }
91
Added:
MFTWorkoutDialog >> renderExerciseActionsButtonGroupOn: html at: i [
92
Added:
93
Added:
html buttonGroup: [
94
Added:
html outlineButton
95
Added:
beSecondary;
96
Added:
beSmall;
97
Added:
callback: [ workout exercises removeAt: i ];
98
Added:
with: 'Delete'.
99
Added:
html outlineButton
100
Added:
beSecondary;
101
Added:
beSmall;
102
Added:
callback: [ self editExercise: i ];
103
Added:
with: 'Edit' ]
104
Added:
]
105
Added:
106
Added:
{ #category : #rendering }
107
Added:
MFTWorkoutDialog >> renderExercisesRowsOn: html [
108
Added:
109
Added:
workout exercises doWithIndex: [ :exercise :i |
110
Added:
html tableRow: [
111
Added:
html tableData: [
112
Added:
self renderExerciseActionsButtonGroupOn: html at: i ].
113
Added:
html tableData: exercise name.
114
Added:
html tableData: exercise primaryMuscle name.
115
Added:
html tableData: exercise repsBySet asCommaString ] ]
116
Added:
]
117
Added:
118
Added:
{ #category : #rendering }
119
Added:
MFTWorkoutDialog >> renderExercisesTableOn: html [
120
Added:
121
Added:
html formGroup: [
122
Added:
html label: 'Exercises'.
123
Added:
html table
124
Added:
class: 'table table-hover';
125
Added:
with: [
126
Added:
workout exercises isNotEmpty ifTrue: [
127
Added:
self renderTableHeaderOn: html ].
128
Added:
self renderExercisesRowsOn: html.
129
Added:
self renderAddExerciseRowOn: html ] ]
130
Added:
]
131
Added:
132
Added:
{ #category : #rendering }
133
Added:
MFTWorkoutDialog >> renderPrimaryMuscleSelectOn: html [
134
Added:
"TODO: use the workout guessPrimaryMuscle."
135
Added:
136
Added:
html formGroup: [
137
Added:
html label: 'Primary muscle'.
138
Added:
html select formControl
139
Added:
list: MFTUtils allMuscleGroups;
140
Added:
selected: workout primaryMuscle;
141
Added:
labels: [ :muscleGroup | muscleGroup name ];
142
Added:
callback: [ :group | workout primaryMuscle: group ] ]
143
Added:
]
144
Added:
145
Added:
{ #category : #rendering }
146
Added:
MFTWorkoutDialog >> renderSecondaryMusclesSelectOn: html [
147
Added:
148
Added:
html formGroup: [
149
Added:
html label: 'Secondary muscles'.
150
Added:
html multiSelect formControl
151
Added:
list: MFTUtils allMuscleGroups;
152
Added:
selected: workout secondaryMuscles;
153
Added:
labels: [ :muscleGroup | muscleGroup name ];
154
Added:
callback: [ :groups | workout secondaryMuscles: groups ] ]
155
Added:
]
156
Added:
157
Added:
{ #category : #rendering }
158
Added:
MFTWorkoutDialog >> renderSubmitWorkoutOn: html [
159
Added:
160
Added:
html formGroup: [
161
Added:
html buttonGroup: [
162
Added:
html formButton
163
Added:
bePrimary;
164
Added:
beSubmit;
165
Added:
callback: [ self answer: workout ];
166
Added:
with: 'Submit'.
167
Added:
html formButton
168
Added:
beSecondary;
169
Added:
callback: [ self answer: nil ];
170
Added:
with: 'Cancel' ] ]
171
Added:
]
172
Added:
173
Added:
{ #category : #rendering }
174
Added:
MFTWorkoutDialog >> renderTableHeaderOn: html [
175
Added:
176
Added:
html tableHead: [
177
Added:
html
178
Added:
tableHeading;
179
Added:
tableHeading: 'Name';
180
Added:
tableHeading: 'Muscles'.
181
Added:
((workout exercises collect: #sets) anySatisfy: #isNotEmpty)
182
Added:
ifTrue: [ html tableHeading: 'Sets' ] ]
183
Added:
]
184
Added:
185
Added:
{ #category : #accessing }
186
Added:
MFTWorkoutDialog >> workout [
187
Added:
188
Added:
^ workout
189
Added:
]
190
Added:
191
Added:
{ #category : #accessing }
192
Added:
MFTWorkoutDialog >> workout: aMFTWorkout [
193
Added:
194
Added:
workout := aMFTWorkout
195
Added:
]