[Pharo] Personal fitness tracker web app.
Deep reimplementations based on the new database schema.
Changed files
- mft-schema.sql
- src/MyFitnessTracker/MFTConfirmDialog.class.st
- src/MyFitnessTracker/MFTDateDialog.class.st
- src/MyFitnessTracker/MFTDialog.class.st
- src/MyFitnessTracker/MFTExercise.class.st
- src/MyFitnessTracker/MFTExerciseDialog.class.st
- src/MyFitnessTracker/MFTExercisesDialog.class.st
- src/MyFitnessTracker/MFTLoginRegisterLogoutComponent.class.st
- src/MyFitnessTracker/MFTMuscle.class.st
- src/MyFitnessTracker/MFTMuscleGroup.class.st
- src/MyFitnessTracker/MFTPageManager.class.st
- src/MyFitnessTracker/MFTPrimaryMuscleDialog.class.st
- src/MyFitnessTracker/MFTPrimaryMuscleGroupDialog.class.st
- src/MyFitnessTracker/MFTRepsDistributionGraph.class.st
- src/MyFitnessTracker/MFTSQLite3Database.class.st
- src/MyFitnessTracker/MFTSandboxPage.class.st
- src/MyFitnessTracker/MFTSecondaryMuscleGroupsDialog.class.st
- src/MyFitnessTracker/MFTSecondaryMusclesDialog.class.st
- src/MyFitnessTracker/MFTSession.class.st
- src/MyFitnessTracker/MFTSet.class.st
- src/MyFitnessTracker/MFTSetDialog.class.st
- src/MyFitnessTracker/MFTSetGroup.class.st
- src/MyFitnessTracker/MFTSetsDialog.class.st
- src/MyFitnessTracker/MFTStringDialog.class.st
- src/MyFitnessTracker/MFTUser.class.st
- src/MyFitnessTracker/MFTUserTask.class.st
- src/MyFitnessTracker/MFTWeight.class.st
- src/MyFitnessTracker/MFTWeightDialog.class.st
- src/MyFitnessTracker/MFTWeightsListPage.class.st
- src/MyFitnessTracker/MFTWorkout.class.st
- src/MyFitnessTracker/MFTWorkoutTask.class.st
- src/MyFitnessTracker/MFTWorkoutsListPage.class.st
mft-schema.sql
@@ -225,8 +225,7 @@
225
225
);
226
226
227
227
INSERT INTO Exercises ("primary_muscle_group_id", "english_name", "french_name") VALUES
228
Removed:
-- Leading zero enables using sort-lines in Emacs
229
Removed:
(02, 'cable row', 'rame avec cable'),
228
Added:
('02', 'cable row', 'rame avec cable'),
230
229
('02', 'deadlift', 'soulevé de terre'),
231
230
('02', 'lat pulldown', NULL),
232
231
('02', 'pull up', 'traction'),
@@ -244,20 +243,11 @@
244
243
('12', 'leg extension', NULL),
245
244
('13', 'leg curl', NULL);
246
245
247
Removed:
CREATE TABLE "Weights" (
248
Removed:
"id" INTEGER UNIQUE,
249
Removed:
"user_id" INTEGER NOT NULL,
250
Removed:
"date" TEXT NOT NULL,
251
Removed:
"value" NUMERIC NOT NULL,
252
Removed:
PRIMARY KEY("id" AUTOINCREMENT)
253
Removed:
);
254
Removed:
255
246
CREATE TABLE "Workouts" (
256
247
"id" INTEGER UNIQUE,
257
248
"user_id" INTEGER NOT NULL,
258
249
"date" TEXT NOT NULL,
259
Removed:
"primary_muscle" TEXT,
260
Removed:
"secondary_muscles" TEXT,
250
Added:
"primary_muscle_group" TEXT,
261
251
PRIMARY KEY("id" AUTOINCREMENT)
262
252
);
263
253
@@ -271,6 +261,14 @@
271
261
"rpe" INTEGER,
272
262
"rest_after" NUMERIC,
273
263
FOREIGN KEY("workout_id") REFERENCES Workouts("id"),
264
Added:
PRIMARY KEY("id" AUTOINCREMENT)
265
Added:
);
266
Added:
267
Added:
CREATE TABLE "Weights" (
268
Added:
"id" INTEGER UNIQUE,
269
Added:
"user_id" INTEGER NOT NULL,
270
Added:
"date" TEXT NOT NULL,
271
Added:
"value" NUMERIC NOT NULL,
274
272
PRIMARY KEY("id" AUTOINCREMENT)
275
273
);
276
274
src/MyFitnessTracker/MFTConfirmDialog.class.st
@@ -1,14 +1,15 @@
1
1
Class {
2
2
#name : #MFTConfirmDialog,
3
3
#superclass : #MFTDialog,
4
Removed:
#category : #'MyFitnessTracker-Dialogs'
4
Added:
#category : #'MyFitnessTracker-Dialog'
5
5
}
6
6
7
7
{ #category : #'as yet unclassified' }
8
8
MFTConfirmDialog >> heading [
9
9
10
Removed:
^ 'You are about to ' , action , ' a ' , component class asString
11
Removed:
, ':'
10
Added:
^ 'You are about to {1} a {2}:' format: {
11
Added:
action.
12
Added:
component class }
12
13
]
13
14
14
15
{ #category : #rendering }
src/MyFitnessTracker/MFTDateDialog.class.st
@@ -4,7 +4,7 @@
4
4
#instVars : [
5
5
'date'
6
6
],
7
Removed:
#category : #'MyFitnessTracker-Dialogs'
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
8
}
9
9
10
10
{ #category : #accessing }
src/MyFitnessTracker/MFTDialog.class.st
@@ -7,7 +7,7 @@
7
7
'action',
8
8
'completion'
9
9
],
10
Removed:
#category : #'MyFitnessTracker-Dialogs'
10
Added:
#category : #'MyFitnessTracker-Dialog'
11
11
}
12
12
13
13
{ #category : #actions }
src/MyFitnessTracker/MFTExercise.class.st
@@ -34,11 +34,10 @@
34
34
#name : #MFTExercise,
35
35
#superclass : #Object,
36
36
#instVars : [
37
Removed:
'canonicalName',
37
Added:
'id',
38
Added:
'primaryMuscleGroupId',
38
39
'englishName',
39
Removed:
'sets',
40
Removed:
'primaryMuscle',
41
Removed:
'secondaryMuscles'
40
Added:
'frenchName'
42
41
],
43
42
#category : #'MyFitnessTracker-Model'
44
43
}
@@ -151,6 +150,17 @@
151
150
]
152
151
153
152
{ #category : #'instance creation' }
153
Added:
MFTExercise class >> newFromDictionary: aDictionary [
154
Added:
155
Added:
^ self new
156
Added:
id: (aDictionary at: 'id');
157
Added:
primaryMuscleGroupId: (aDictionary at: 'primary_muscle_group_id');
158
Added:
englishName: (aDictionary at: 'english_name');
159
Added:
frenchName: (aDictionary at: 'french_name');
160
Added:
yourself
161
Added:
]
162
Added:
163
Added:
{ #category : #'instance creation' }
154
164
MFTExercise class >> newWithEnglishName [
155
165
"I return a MFTExercise instance for which englishName is set to the calling method selector, as a space-separated string."
156
166
@@ -224,18 +234,6 @@
224
234
]
225
235
226
236
{ #category : #accessing }
227
Removed:
MFTExercise >> canonicalName [
228
Removed:
229
Removed:
^ canonicalName
230
Removed:
]
231
Removed:
232
Removed:
{ #category : #accessing }
233
Removed:
MFTExercise >> canonicalName: anObject [
234
Removed:
235
Removed:
canonicalName := anObject
236
Removed:
]
237
Removed:
238
Removed:
{ #category : #accessing }
239
237
MFTExercise >> englishName [
240
238
241
239
^ englishName
@@ -247,57 +245,53 @@
247
245
englishName := aString
248
246
]
249
247
250
Removed:
{ #category : #initialization }
251
Removed:
MFTExercise >> initialize [
248
Added:
{ #category : #accessing }
249
Added:
MFTExercise >> frenchName [
252
250
253
Removed:
super initialize.
254
Removed:
canonicalName := String new.
255
Removed:
englishName := String new.
256
Removed:
sets := OrderedCollection new.
257
Removed:
primaryMuscle := MFTMuscleGroup new.
258
Removed:
secondaryMuscles := OrderedCollection new
251
Added:
^ frenchName
259
252
]
260
253
261
254
{ #category : #accessing }
262
Removed:
MFTExercise >> primaryMuscle [
255
Added:
MFTExercise >> frenchName: anObject [
263
256
264
Removed:
^ primaryMuscle
257
Added:
frenchName := anObject
265
258
]
266
259
267
260
{ #category : #accessing }
268
Removed:
MFTExercise >> primaryMuscle: anObject [
261
Added:
MFTExercise >> id [
269
262
270
Removed:
primaryMuscle := anObject
263
Added:
^ id
271
264
]
272
265
273
Removed:
{ #category : #'as yet unclassified' }
274
Removed:
MFTExercise >> repsBySet [
266
Added:
{ #category : #accessing }
267
Added:
MFTExercise >> id: anObject [
275
268
276
Removed:
^ (sets collect: #reps) ifEmpty: [ Array with: 0 ]
269
Added:
id := anObject
277
270
]
278
271
279
Removed:
{ #category : #accessing }
280
Removed:
MFTExercise >> secondaryMuscles [
272
Added:
{ #category : #initialization }
273
Added:
MFTExercise >> initialize [
281
274
282
Removed:
^ secondaryMuscles
275
Added:
super initialize.
276
Added:
englishName := String new
283
277
]
284
278
285
279
{ #category : #accessing }
286
Removed:
MFTExercise >> secondaryMuscles: anObject [
280
Added:
MFTExercise >> primaryMuscleGroupId [
287
281
288
Removed:
secondaryMuscles := anObject
282
Added:
^ primaryMuscleGroupId
289
283
]
290
284
291
285
{ #category : #accessing }
292
Removed:
MFTExercise >> sets [
286
Added:
MFTExercise >> primaryMuscleGroupId: anObject [
293
287
294
Removed:
^ sets
288
Added:
primaryMuscleGroupId := anObject
295
289
]
296
290
297
Removed:
{ #category : #accessing }
298
Removed:
MFTExercise >> sets: aMFTSetCollection [
291
Added:
{ #category : #'as yet unclassified' }
292
Added:
MFTExercise >> repsBySet [
299
293
300
Removed:
sets := aMFTSetCollection asOrderedCollection
294
Added:
^ (sets collect: #reps) ifEmpty: [ Array with: 0 ]
301
295
]
302
296
303
297
{ #category : #'as yet unclassified' }
src/MyFitnessTracker/MFTExerciseDialog.class.st
@@ -8,7 +8,7 @@
8
8
'exercise',
9
9
'sets'
10
10
],
11
Removed:
#category : #'MyFitnessTracker-Dialogs'
11
Added:
#category : #'MyFitnessTracker-Dialog'
12
12
}
13
13
14
14
{ #category : #actions }
@@ -39,6 +39,13 @@
39
39
super initialize.
40
40
exercise := MFTExercise new.
41
41
sets := OrderedCollection new
42
Added:
]
43
Added:
44
Added:
{ #category : #testing }
45
Added:
MFTExerciseDialog >> isDeprecated [
46
Added:
"Use MFTSetDialog instead."
47
Added:
48
Added:
^ true
42
49
]
43
50
44
51
{ #category : #rendering }
src/MyFitnessTracker/MFTExercisesDialog.class.st
@@ -4,7 +4,7 @@
4
4
#instVars : [
5
5
'exercises'
6
6
],
7
Removed:
#category : #'MyFitnessTracker-Dialogs'
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
8
}
9
9
10
10
{ #category : #actions }
@@ -51,6 +51,13 @@
51
51
52
52
super initialize.
53
53
exercises := OrderedCollection new
54
Added:
]
55
Added:
56
Added:
{ #category : #testing }
57
Added:
MFTExercisesDialog >> isDeprecated [
58
Added:
"Use MFTSetsDialog instead."
59
Added:
60
Added:
^ true
54
61
]
55
62
56
63
{ #category : #rendering }
src/MyFitnessTracker/MFTLoginRegisterLogoutComponent.class.st
@@ -12,6 +12,8 @@
12
12
"Attempt to match aMFTUser passwordHash against an existing user password_hash in the database."
13
13
14
14
| existingUser |
15
Added:
aMFTUser username = 'testMFT' ifTrue: [
16
Added:
^ self session login: MFTSQLite3Database getTestUser ].
15
17
existingUser := MFTSQLite3Database getExistingUser: aMFTUser.
16
18
aMFTUser passwordHash = existingUser passwordHash
17
19
ifTrue: [ self session login: existingUser ]
src/MyFitnessTracker/MFTMuscle.class.st
@@ -2,364 +2,92 @@
2
2
#name : #MFTMuscle,
3
3
#superclass : #Object,
4
4
#instVars : [
5
Removed:
'canonicalName',
5
Added:
'id',
6
Added:
'primaryMuscleGroupId',
6
7
'latinName',
7
8
'englishName',
8
Removed:
'description'
9
Added:
'function'
9
10
],
10
11
#category : #'MyFitnessTracker-Model'
11
12
}
12
13
13
Removed:
{ #category : #muscle }
14
Removed:
MFTMuscle class >> bicepsBrachii [
15
Removed:
16
Removed:
^ self newWithLatinName
17
Removed:
englishName: 'biceps';
18
Removed:
yourself
19
Removed:
]
20
Removed:
21
Removed:
{ #category : #muscle }
22
Removed:
MFTMuscle class >> brachioRadialis [
23
Removed:
24
Removed:
^ self newWithLatinName
25
Removed:
englishName: 'Brachioradialis';
26
Removed:
description:
27
Removed:
'Located in the forearm, it is responsible for flexing the forearm at the elbow joint.';
28
Removed:
yourself
29
Removed:
]
30
Removed:
31
Removed:
{ #category : #muscle }
32
Removed:
MFTMuscle class >> deltoidAnterior [
33
Removed:
34
Removed:
^ self new
35
Removed:
englishName: 'deltoid (anterior)';
36
Removed:
latinName: 'deltoideus';
37
Removed:
yourself
38
Removed:
]
39
Removed:
40
Removed:
{ #category : #muscle }
41
Removed:
MFTMuscle class >> deltoidMedial [
42
Removed:
43
Removed:
^ self new
44
Removed:
englishName: 'deltoid (medial)';
45
Removed:
latinName: 'deltoideus';
46
Removed:
yourself
47
Removed:
]
48
Removed:
49
Removed:
{ #category : #muscle }
50
Removed:
MFTMuscle class >> deltoidPosterior [
51
Removed:
52
Removed:
^ self new
53
Removed:
englishName: 'deltoid (posterior)';
54
Removed:
latinName: 'deltoideus';
55
Removed:
yourself
56
Removed:
]
57
Removed:
58
Removed:
{ #category : #muscle }
59
Removed:
MFTMuscle class >> erectorSpinae [
60
Removed:
61
Removed:
^ self newWithLatinName
62
Removed:
englishName: 'erectors';
63
Removed:
description:
64
Removed:
'This group of muscles runs along the spine and is responsible for extending the vertebral column and maintaining an upright posture.';
65
Removed:
yourself
66
Removed:
]
67
Removed:
68
Removed:
{ #category : #muscle }
69
Removed:
MFTMuscle class >> extensorCarpiRadialiasBrevis [
70
Removed:
71
Removed:
^ self newWithLatinName
72
Removed:
englishName: 'Extensor Carpi Radialis Brevis';
73
Removed:
description:
74
Removed:
'Located in the forearm, it is responsible for extending the wrist and abducting the hand.';
75
Removed:
yourself
76
Removed:
]
77
Removed:
78
Removed:
{ #category : #muscle }
79
Removed:
MFTMuscle class >> extensorCarpiRadialisLongus [
80
Removed:
81
Removed:
^ self newWithLatinName
82
Removed:
englishName: 'Extensor Carpi Radialis Longus';
83
Removed:
description:
84
Removed:
'Located in the forearm, it is responsible for extending the wrist and abducting the hand.';
85
Removed:
yourself
86
Removed:
]
87
Removed:
88
Removed:
{ #category : #muscle }
89
Removed:
MFTMuscle class >> extensorCarpiUlnaris [
90
Removed:
91
Removed:
^ self newWithLatinName
92
Removed:
englishName: 'Extensor Carpi Ulnaris';
93
Removed:
description:
94
Removed:
'Located in the forearm, it is responsible for extending the wrist and adducting the hand.';
95
Removed:
yourself
96
Removed:
]
97
Removed:
98
Removed:
{ #category : #muscle }
99
Removed:
MFTMuscle class >> flexorCarpiRadialis [
100
Removed:
101
Removed:
^ self newWithLatinName
102
Removed:
englishName: 'Flexor Carpi Radialis';
103
Removed:
description:
104
Removed:
'Located in the forearm, it is responsible for flexing the wrist and abducting the hand.';
105
Removed:
yourself
106
Removed:
]
107
Removed:
108
Removed:
{ #category : #muscle }
109
Removed:
MFTMuscle class >> flexorCarpiUlnaris [
110
Removed:
111
Removed:
^ self newWithLatinName
112
Removed:
englishName: 'Flexor Carpi Ulnaris';
113
Removed:
description:
114
Removed:
'Located in the forearm, it is responsible for flexing the wrist and adducting the hand.';
115
Removed:
yourself
116
Removed:
]
117
Removed:
118
Removed:
{ #category : #muscle }
119
Removed:
MFTMuscle class >> gastrocnemius [
120
Removed:
121
Removed:
^ self newWithLatinName
122
Removed:
englishName: 'calf';
123
Removed:
description:
124
Removed:
'Located in the calf, it is responsible for plantar flexion of the foot (pointing toes).';
125
Removed:
yourself
126
Removed:
]
127
Removed:
128
Removed:
{ #category : #muscle }
129
Removed:
MFTMuscle class >> gluteusMaximus [
130
Removed:
131
Removed:
^ self newWithLatinName
132
Removed:
englishName: 'glutes';
133
Removed:
description:
134
Removed:
'The largest muscle in the buttocks, responsible for hip extension, outward rotation, and abduction.';
135
Removed:
yourself
136
Removed:
]
137
Removed:
138
Removed:
{ #category : #muscle }
139
Removed:
MFTMuscle class >> gluteusMedius [
140
Removed:
141
Removed:
^ self newWithLatinName
142
Removed:
englishName: 'glutes';
143
Removed:
description:
144
Removed:
'Located in the buttocks, it plays a role in hip abduction and medial rotation.';
145
Removed:
yourself
146
Removed:
]
147
Removed:
148
Removed:
{ #category : #muscle }
149
Removed:
MFTMuscle class >> gluteusMinimus [
150
Removed:
151
Removed:
^ self newWithLatinName
152
Removed:
englishName: 'glutes';
153
Removed:
description:
154
Removed:
'Also located in the buttocks, it assists in hip abduction and medial rotation, working with the gluteus medius.';
155
Removed:
yourself
156
Removed:
]
157
Removed:
158
Removed:
{ #category : #muscle }
159
Removed:
MFTMuscle class >> hamstring [
160
Removed:
161
Removed:
^ self newWithLatinName
162
Removed:
englishName: 'hamstrings';
163
Removed:
description:
164
Removed:
'This group of muscles includes the biceps femoris, semitendinosus, and semimembranosus. They are located in the back of the thigh and are responsible for knee flexion and hip extension.';
165
Removed:
yourself
166
Removed:
]
167
Removed:
168
Removed:
{ #category : #muscle }
169
Removed:
MFTMuscle class >> latissimusDorsi [
170
Removed:
171
Removed:
^ self newWithLatinName
172
Removed:
englishName: 'lats';
173
Removed:
description:
174
Removed:
'Also known as the "lats," these muscles are located in the upper back and are responsible for shoulder adduction and extension.';
175
Removed:
yourself
176
Removed:
]
177
Removed:
178
14
{ #category : #'instance creation' }
179
Removed:
MFTMuscle class >> newWithLatinName [
180
Removed:
"I return a MFTMuscle instance for which latinName is set to the calling method selector, as a space-separated string.
181
Removed:
182
Removed:
canonicalName stores the name of the calling method; this way, we can reliably create MFTMuscle instances."
15
Added:
MFTMuscle class >> newFromDictionary: aDictionary [
183
16
184
Removed:
| senderSelector muscleNameFromSender |
185
Removed:
senderSelector := thisContext sender selector.
186
Removed:
muscleNameFromSender := (senderSelector splitCamelCase collect:
187
Removed:
#asLowercase) joinUsing: Character space.
188
17
^ self new
189
Removed:
canonicalName: senderSelector;
190
Removed:
latinName: muscleNameFromSender;
18
Added:
id: (aDictionary at: 'id');
19
Added:
primaryMuscleGroupId: (aDictionary at: 'muscle_group_id');
20
Added:
latinName: (aDictionary at: 'latin_name');
21
Added:
englishName: (aDictionary at: 'english_name');
22
Added:
function: (aDictionary at: 'function');
191
23
yourself
192
24
]
193
25
194
Removed:
{ #category : #muscle }
195
Removed:
MFTMuscle class >> obliquusExternusAbdominis [
26
Added:
{ #category : #accessing }
27
Added:
MFTMuscle >> englishName [
196
28
197
Removed:
^ self newWithLatinName
198
Removed:
englishName: 'external oblique';
199
Removed:
description: 'Located on the front and side of the abdomen.';
200
Removed:
yourself
29
Added:
^ englishName
201
30
]
202
31
203
Removed:
{ #category : #muscle }
204
Removed:
MFTMuscle class >> obliquusInternusAbdominis [
32
Added:
{ #category : #accessing }
33
Added:
MFTMuscle >> englishName: aString [
205
34
206
Removed:
^ self newWithLatinName
207
Removed:
englishName: 'internal oblique';
208
Removed:
description: 'Located on the front and side of the abdomen.';
209
Removed:
yourself
35
Added:
englishName := aString
210
36
]
211
37
212
Removed:
{ #category : #muscle }
213
Removed:
MFTMuscle class >> pectoralisMajor [
214
Removed:
215
Removed:
^ self newWithLatinName
216
Removed:
englishName: 'pectoral';
217
Removed:
description:
218
Removed:
'Commonly known as the "pecs," these muscles are in the chest and are responsible for shoulder flexion and adduction.';
219
Removed:
yourself
220
Removed:
]
221
Removed:
222
Removed:
{ #category : #muscle }
223
Removed:
MFTMuscle class >> pectoralisMinor [
224
Removed:
225
Removed:
^ self newWithLatinName
226
Removed:
englishName: 'pectoral';
227
Removed:
description:
228
Removed:
'Located beneath the pectoralis major, it plays a role in stabilizing the shoulder blade and assisting in deep breathing.';
229
Removed:
yourself
230
Removed:
]
231
Removed:
232
Removed:
{ #category : #muscle }
233
Removed:
MFTMuscle class >> quadricepsFemoris [
234
Removed:
235
Removed:
^ self newWithLatinName
236
Removed:
englishName: 'quad';
237
Removed:
description:
238
Removed:
'A group of four muscles on the front of the thigh, responsible for knee extension.';
239
Removed:
yourself
240
Removed:
]
241
Removed:
242
Removed:
{ #category : #muscle }
243
Removed:
MFTMuscle class >> rectusAbdominis [
244
Removed:
245
Removed:
^ self newWithLatinName
246
Removed:
englishName: 'six-pack';
247
Removed:
description:
248
Removed:
'Located along the front of the abdomen. Colloquially known as the "six-pack"';
249
Removed:
yourself
250
Removed:
]
251
Removed:
252
Removed:
{ #category : #muscle }
253
Removed:
MFTMuscle class >> rotatorCuff [
254
Removed:
255
Removed:
^ self newWithLatinName
256
Removed:
englishName: 'rotator cuff';
257
Removed:
description:
258
Removed:
'This group includes four muscles: supraspinatus, infraspinatus, teres minor, and subscapularis. They play a crucial role in stabilizing the shoulder joint and facilitating arm rotation.';
259
Removed:
yourself
260
Removed:
]
261
Removed:
262
Removed:
{ #category : #muscle }
263
Removed:
MFTMuscle class >> soleus [
264
Removed:
265
Removed:
^ self newWithLatinName
266
Removed:
englishName: 'calf';
267
Removed:
description:
268
Removed:
'Also located in the calf, it assists the gastrocnemius in plantar flexion and helps maintain posture.';
269
Removed:
yourself
270
Removed:
]
271
Removed:
272
Removed:
{ #category : #muscle }
273
Removed:
MFTMuscle class >> transversusAbdominis [
274
Removed:
275
Removed:
^ self new
276
Removed:
englishName: 'abs';
277
Removed:
description:
278
Removed:
'Deepest abdominal muscle. Wraps around the spine for protection and stability.';
279
Removed:
yourself
280
Removed:
]
281
Removed:
282
Removed:
{ #category : #muscle }
283
Removed:
MFTMuscle class >> trapezius [
284
Removed:
285
Removed:
^ self newWithLatinName
286
Removed:
englishName: 'trap';
287
Removed:
description:
288
Removed:
'The trapezius muscles are located in the upper back and neck. They play a role in moving and stabilizing the shoulder blades.';
289
Removed:
yourself
290
Removed:
]
291
Removed:
292
Removed:
{ #category : #muscle }
293
Removed:
MFTMuscle class >> tricepsBrachii [
294
Removed:
295
Removed:
^ self newWithLatinName
296
Removed:
englishName: 'triceps';
297
Removed:
yourself
298
Removed:
]
299
Removed:
300
38
{ #category : #accessing }
301
Removed:
MFTMuscle >> canonicalName [
39
Added:
MFTMuscle >> function [
302
40
303
Removed:
^ canonicalName
41
Added:
^ function
304
42
]
305
43
306
44
{ #category : #accessing }
307
Removed:
MFTMuscle >> canonicalName: anObject [
45
Added:
MFTMuscle >> function: anObject [
308
46
309
Removed:
canonicalName := anObject
47
Added:
function := anObject
310
48
]
311
49
312
50
{ #category : #accessing }
313
Removed:
MFTMuscle >> description [
51
Added:
MFTMuscle >> id [
314
52
315
Removed:
^ description
53
Added:
^ id
316
54
]
317
55
318
56
{ #category : #accessing }
319
Removed:
MFTMuscle >> description: aString [
57
Added:
MFTMuscle >> id: anObject [
320
58
321
Removed:
description := aString
59
Added:
id := anObject
322
60
]
323
61
324
62
{ #category : #accessing }
325
Removed:
MFTMuscle >> englishName [
63
Added:
MFTMuscle >> latinName [
326
64
327
Removed:
^ englishName
65
Added:
^ latinName
328
66
]
329
67
330
68
{ #category : #accessing }
331
Removed:
MFTMuscle >> englishName: aString [
69
Added:
MFTMuscle >> latinName: aString [
332
70
333
Removed:
englishName := aString
71
Added:
latinName := aString
334
72
]
335
73
336
Removed:
{ #category : #initialization }
337
Removed:
MFTMuscle >> initialize [
338
Removed:
339
Removed:
super initialize.
340
Removed:
canonicalName := String new.
341
Removed:
latinName := String new.
342
Removed:
englishName := String new.
343
Removed:
description := String new
344
Removed:
]
345
Removed:
346
74
{ #category : #accessing }
347
Removed:
MFTMuscle >> latinName [
75
Added:
MFTMuscle >> linkTerminologiaAnatomica [
348
76
349
Removed:
^ latinName
77
Added:
^ 'http://terminologia-anatomica.org/en/Search?query=musculus {1}'
78
Added:
format: { latinName }
350
79
]
351
80
352
81
{ #category : #accessing }
353
Removed:
MFTMuscle >> latinName: aString [
82
Added:
MFTMuscle >> primaryMuscleGroupId [
354
83
355
Removed:
latinName := aString
84
Added:
^ primaryMuscleGroupId
356
85
]
357
86
358
87
{ #category : #accessing }
359
Removed:
MFTMuscle >> linkTerminologiaAnatomica [
88
Added:
MFTMuscle >> primaryMuscleGroupId: anObject [
360
89
361
Removed:
^ 'http://terminologia-anatomica.org/en/Search?query=' , 'musculus '
362
Removed:
, latinName
90
Added:
primaryMuscleGroupId := anObject
363
91
]
364
92
365
93
{ #category : #rendering }
@@ -372,8 +100,11 @@
372
100
html
373
101
tableHeading: 'Property';
374
102
tableHeading: 'Value' ].
375
Removed:
self class allInstVarNames do: [ :var |
103
Added:
html tableRow: [
104
Added:
html tableData: 'Latin name'.
105
Added:
html tableData: latinName ].
106
Added:
function ifNotNil: [
376
107
html tableRow: [
377
Removed:
html tableData: var.
378
Removed:
html tableData: (self perform: var) ] ] ]
108
Added:
html tableData: 'Function'.
109
Added:
html tableData: ('This muscle {1}.' format: { function }) ] ] ]
379
110
]
src/MyFitnessTracker/MFTMuscleGroup.class.st
@@ -2,189 +2,90 @@
2
2
#name : #MFTMuscleGroup,
3
3
#superclass : #SBSComponent,
4
4
#instVars : [
5
Removed:
'canonicalName',
5
Added:
'id',
6
6
'englishName',
7
Removed:
'latinName',
8
Removed:
'description',
7
Added:
'frenchName',
8
Added:
'function',
9
9
'muscles'
10
10
],
11
11
#category : #'MyFitnessTracker-Model'
12
12
}
13
13
14
Removed:
{ #category : #'muscle group' }
15
Removed:
MFTMuscleGroup class >> abdominal [
14
Added:
{ #category : #'instance creation' }
15
Added:
MFTMuscleGroup class >> newFromDictionary: aDictionary [
16
16
17
Removed:
^ self newWithEnglishName
18
Removed:
description: 'The abdominal muscles constitute the core.';
19
Removed:
muscles: {
20
Removed:
MFTMuscle rectusAbdominis.
21
Removed:
MFTMuscle obliquusExternusAbdominis.
22
Removed:
MFTMuscle obliquusInternusAbdominis.
23
Removed:
MFTMuscle transversusAbdominis };
24
Removed:
yourself
25
Removed:
]
17
Added:
| id |
18
Added:
id := aDictionary at: 'id'.
26
19
27
Removed:
{ #category : #'muscle group' }
28
Removed:
MFTMuscleGroup class >> arm [
29
Removed:
30
Removed:
^ self newWithEnglishName
31
Removed:
latinName: 'brachium';
32
Removed:
muscles: {
33
Removed:
MFTMuscle bicepsBrachii.
34
Removed:
MFTMuscle tricepsBrachii };
20
Added:
^ self new
21
Added:
id: id;
22
Added:
englishName: (aDictionary at: 'english_name');
23
Added:
frenchName: (aDictionary at: 'french_name');
24
Added:
function: (aDictionary at: 'function');
25
Added:
muscles: (MFTSQLite3Database allMuscles select: [ :each |
26
Added:
each primaryMuscleGroupId = id ]);
35
27
yourself
36
28
]
37
29
38
Removed:
{ #category : #'muscle group' }
39
Removed:
MFTMuscleGroup class >> back [
30
Added:
{ #category : #accessing }
31
Added:
MFTMuscleGroup >> englishName [
40
32
41
Removed:
^ self newWithEnglishName
42
Removed:
muscles: {
43
Removed:
MFTMuscle latissimusDorsi.
44
Removed:
MFTMuscle trapezius.
45
Removed:
MFTMuscle erectorSpinae };
46
Removed:
yourself
33
Added:
^ englishName
47
34
]
48
35
49
Removed:
{ #category : #'muscle group' }
50
Removed:
MFTMuscleGroup class >> calf [
36
Added:
{ #category : #accessing }
37
Added:
MFTMuscleGroup >> englishName: aString [
51
38
52
Removed:
^ self newWithEnglishName
53
Removed:
muscles: {
54
Removed:
MFTMuscle gastrocnemius.
55
Removed:
MFTMuscle soleus };
56
Removed:
yourself
39
Added:
englishName := aString
57
40
]
58
41
59
Removed:
{ #category : #'muscle group' }
60
Removed:
MFTMuscleGroup class >> chest [
61
Removed:
62
Removed:
^ self newWithEnglishName
63
Removed:
muscles: {
64
Removed:
MFTMuscle pectoralisMajor.
65
Removed:
MFTMuscle pectoralisMinor };
66
Removed:
yourself
67
Removed:
]
68
Removed:
69
Removed:
{ #category : #'muscle group' }
70
Removed:
MFTMuscleGroup class >> forearm [
71
Removed:
72
Removed:
^ self newWithEnglishName
73
Removed:
latinName: 'antebrachium';
74
Removed:
muscles: {
75
Removed:
MFTMuscle brachioRadialis.
76
Removed:
MFTMuscle flexorCarpiRadialis.
77
Removed:
MFTMuscle flexorCarpiUlnaris.
78
Removed:
MFTMuscle extensorCarpiRadialisLongus.
79
Removed:
MFTMuscle extensorCarpiRadialiasBrevis.
80
Removed:
MFTMuscle extensorCarpiUlnaris };
81
Removed:
yourself
82
Removed:
]
83
Removed:
84
Removed:
{ #category : #'muscle group' }
85
Removed:
MFTMuscleGroup class >> hip [
86
Removed:
87
Removed:
^ self newWithEnglishName
88
Removed:
muscles: {
89
Removed:
MFTMuscle gluteusMaximus.
90
Removed:
MFTMuscle gluteusMedius.
91
Removed:
MFTMuscle gluteusMinimus };
92
Removed:
yourself
93
Removed:
]
94
Removed:
95
Removed:
{ #category : #'muscle group' }
96
Removed:
MFTMuscleGroup class >> leg [
97
Removed:
98
Removed:
^ self newWithEnglishName
99
Removed:
muscles: {
100
Removed:
MFTMuscle quadricepsFemoris.
101
Removed:
MFTMuscle hamstring };
102
Removed:
yourself
103
Removed:
]
104
Removed:
105
Removed:
{ #category : #'instance creation' }
106
Removed:
MFTMuscleGroup class >> newWithEnglishName [
107
Removed:
"I return a MFTMuscle Group instance for which englishName is set to the calling method selector."
108
Removed:
109
Removed:
| senderSelector |
110
Removed:
senderSelector := thisContext sender selector.
111
Removed:
^ self new
112
Removed:
canonicalName: senderSelector;
113
Removed:
englishName: senderSelector;
114
Removed:
yourself
115
Removed:
]
116
Removed:
117
Removed:
{ #category : #'muscle group' }
118
Removed:
MFTMuscleGroup class >> shoulder [
119
Removed:
120
Removed:
^ self newWithEnglishName
121
Removed:
muscles: {
122
Removed:
MFTMuscle deltoidAnterior.
123
Removed:
MFTMuscle deltoidMedial.
124
Removed:
MFTMuscle deltoidPosterior.
125
Removed:
MFTMuscle rotatorCuff };
126
Removed:
yourself
127
Removed:
]
128
Removed:
129
42
{ #category : #accessing }
130
Removed:
MFTMuscleGroup >> canonicalName [
43
Added:
MFTMuscleGroup >> frenchName [
131
44
132
Removed:
^ canonicalName
45
Added:
^ frenchName
133
46
]
134
47
135
48
{ #category : #accessing }
136
Removed:
MFTMuscleGroup >> canonicalName: anObject [
49
Added:
MFTMuscleGroup >> frenchName: anObject [
137
50
138
Removed:
canonicalName := anObject
51
Added:
frenchName := anObject
139
52
]
140
53
141
54
{ #category : #accessing }
142
Removed:
MFTMuscleGroup >> description [
55
Added:
MFTMuscleGroup >> function [
143
56
144
Removed:
^ description
57
Added:
^ function
145
58
]
146
59
147
60
{ #category : #accessing }
148
Removed:
MFTMuscleGroup >> description: aString [
61
Added:
MFTMuscleGroup >> function: anObject [
149
62
150
Removed:
description := aString
63
Added:
function := anObject
151
64
]
152
65
153
66
{ #category : #accessing }
154
Removed:
MFTMuscleGroup >> englishName [
67
Added:
MFTMuscleGroup >> id [
155
68
156
Removed:
^ englishName
69
Added:
^ id
157
70
]
158
71
159
72
{ #category : #accessing }
160
Removed:
MFTMuscleGroup >> englishName: aString [
73
Added:
MFTMuscleGroup >> id: anObject [
161
74
162
Removed:
englishName := aString
75
Added:
id := anObject
163
76
]
164
77
165
78
{ #category : #initialization }
166
79
MFTMuscleGroup >> initialize [
167
80
168
81
super initialize.
169
Removed:
canonicalName := String new.
170
82
englishName := String new.
171
Removed:
description := String new.
83
Added:
frenchName := String new.
84
Added:
function := String new.
172
85
muscles := OrderedCollection new
173
86
]
174
87
175
88
{ #category : #accessing }
176
Removed:
MFTMuscleGroup >> latinName [
177
Removed:
178
Removed:
^ latinName
179
Removed:
]
180
Removed:
181
Removed:
{ #category : #accessing }
182
Removed:
MFTMuscleGroup >> latinName: anObject [
183
Removed:
184
Removed:
latinName := anObject
185
Removed:
]
186
Removed:
187
Removed:
{ #category : #accessing }
188
89
MFTMuscleGroup >> muscles [
189
90
190
91
^ muscles
@@ -200,24 +101,17 @@
200
101
MFTMuscleGroup >> renderContentOn: html [
201
102
202
103
html heading level2 with: englishName capitalized.
203
Removed:
description ifNotEmpty: [
104
Added:
function ifNotNil: [
204
105
html
205
Removed:
text: description;
106
Added:
text: ('This muscle group {1}.' format: { function });
206
107
break ].
207
108
muscles ifNotEmpty: [
208
Removed:
html
209
Removed:
text: 'This group is comprised of:';
210
Removed:
definitionList: [
211
Removed:
muscles do: [ :muscle |
212
Removed:
html definitionTerm: [
213
Removed:
html text: muscle englishName capitalized.
214
Removed:
muscle latinName ifNotEmpty: [
215
Removed:
html space.
216
Removed:
html text: '('.
217
Removed:
html anchor
218
Removed:
url: muscle linkTerminologiaAnatomica;
219
Removed:
with: muscle latinName.
220
Removed:
html text: ')' ] ].
221
Removed:
html definitionData: muscle description.
222
Removed:
muscle renderContentOn: html ] ] ]
109
Added:
html listGroup: [
110
Added:
muscles do: [ :muscle |
111
Added:
html listGroupItem: [
112
Added:
html anchor
113
Added:
url: muscle linkTerminologiaAnatomica;
114
Added:
with: muscle latinName.
115
Added:
muscle function ifNotNil: [
116
Added:
html text: (': {1}.' format: { muscle function }) ] ] ] ] ]
223
117
]
src/MyFitnessTracker/MFTPageManager.class.st
@@ -64,7 +64,6 @@
64
64
65
65
mainPages := self defaultPublicPages.
66
66
activePage := mainPages at: #landing.
67
Removed:
68
67
mainNavigationBar := MFTMainNavigationBarComponent new.
69
68
header := MFTRegisterProspectEmailHeader new.
70
69
footer := MFTDefaultFooter new
src/MyFitnessTracker/MFTPrimaryMuscleDialog.class.st
@@ -1,62 +0,0 @@
1
Removed:
Class {
2
Removed:
#name : #MFTPrimaryMuscleDialog,
3
Removed:
#superclass : #MFTDialog,
4
Removed:
#instVars : [
5
Removed:
'primaryMuscle'
6
Removed:
],
7
Removed:
#category : #'MyFitnessTracker-Dialogs'
8
Removed:
}
9
Removed:
10
Removed:
{ #category : #initialization }
11
Removed:
MFTPrimaryMuscleDialog >> initialize [
12
Removed:
13
Removed:
super initialize.
14
Removed:
primaryMuscle := MFTMuscle new
15
Removed:
]
16
Removed:
17
Removed:
{ #category : #accessing }
18
Removed:
MFTPrimaryMuscleDialog >> primaryMuscle [
19
Removed:
20
Removed:
^ primaryMuscle
21
Removed:
]
22
Removed:
23
Removed:
{ #category : #accessing }
24
Removed:
MFTPrimaryMuscleDialog >> primaryMuscle: anObject [
25
Removed:
26
Removed:
primaryMuscle := anObject
27
Removed:
]
28
Removed:
29
Removed:
{ #category : #rendering }
30
Removed:
MFTPrimaryMuscleDialog >> renderContentOn: html [
31
Removed:
32
Removed:
| allMuscles selectedMuscle |
33
Removed:
allMuscles := MFTUtils allMuscleGroups.
34
Removed:
selectedMuscle := allMuscles
35
Removed:
detect: [ :each |
36
Removed:
each englishName = primaryMuscle englishName ]
37
Removed:
ifNone: [ MFTMuscleGroup new ].
38
Removed:
39
Removed:
self renderDialogOn: html with: [
40
Removed:
html formGroup: [
41
Removed:
html select formControl
42
Removed:
list: allMuscles;
43
Removed:
selected: selectedMuscle;
44
Removed:
labels: [ :muscleGroup | muscleGroup englishName ];
45
Removed:
callback: [ :group | primaryMuscle := group ] ] ]
46
Removed:
]
47
Removed:
48
Removed:
{ #category : #rendering }
49
Removed:
MFTPrimaryMuscleDialog >> renderSubmitOn: html [
50
Removed:
51
Removed:
html buttonGroup: [
52
Removed:
html formButton
53
Removed:
beSubmit;
54
Removed:
bePrimary;
55
Removed:
callback: [ self answer: primaryMuscle ];
56
Removed:
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
57
Removed:
html formButton
58
Removed:
beSubmit;
59
Removed:
beSecondary;
60
Removed:
callback: [ self answer: MFTMuscle new ];
61
Removed:
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
62
Removed:
]
src/MyFitnessTracker/MFTPrimaryMuscleGroupDialog.class.st
@@ -0,0 +1,62 @@
1
Added:
Class {
2
Added:
#name : #MFTPrimaryMuscleGroupDialog,
3
Added:
#superclass : #MFTDialog,
4
Added:
#instVars : [
5
Added:
'primaryMuscleGroup'
6
Added:
],
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
Added:
}
9
Added:
10
Added:
{ #category : #initialization }
11
Added:
MFTPrimaryMuscleGroupDialog >> initialize [
12
Added:
13
Added:
super initialize.
14
Added:
primaryMuscleGroup := MFTMuscleGroup new.
15
Added:
16
Added:
]
17
Added:
18
Added:
{ #category : #accessing }
19
Added:
MFTPrimaryMuscleGroupDialog >> primaryMuscleGroup [
20
Added:
21
Added:
^ primaryMuscleGroup
22
Added:
]
23
Added:
24
Added:
{ #category : #accessing }
25
Added:
MFTPrimaryMuscleGroupDialog >> primaryMuscleGroup: anObject [
26
Added:
27
Added:
primaryMuscleGroup := anObject
28
Added:
]
29
Added:
30
Added:
{ #category : #rendering }
31
Added:
MFTPrimaryMuscleGroupDialog >> renderContentOn: html [
32
Added:
33
Added:
| allMuscleGroups selectedMuscleGroup |
34
Added:
allMuscleGroups := MFTSQLite3Database allMuscleGroups.
35
Added:
selectedMuscleGroup := primaryMuscleGroup ifNotNil: [
36
Added:
allMuscleGroups detect: [ :muscleGroup |
37
Added:
muscleGroup englishName
38
Added:
= primaryMuscleGroup englishName ] ].
39
Added:
self renderDialogOn: html with: [
40
Added:
html formGroup: [
41
Added:
html select formControl
42
Added:
list: allMuscleGroups;
43
Added:
selected: selectedMuscleGroup;
44
Added:
labels: [ :muscleGroup | muscleGroup englishName ];
45
Added:
callback: [ :group | primaryMuscleGroup := group ] ] ]
46
Added:
]
47
Added:
48
Added:
{ #category : #rendering }
49
Added:
MFTPrimaryMuscleGroupDialog >> renderSubmitOn: html [
50
Added:
51
Added:
html buttonGroup: [
52
Added:
html formButton
53
Added:
beSubmit;
54
Added:
bePrimary;
55
Added:
callback: [ self answer: primaryMuscleGroup ];
56
Added:
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
57
Added:
html formButton
58
Added:
beSubmit;
59
Added:
beSecondary;
60
Added:
callback: [ self answer: nil ];
61
Added:
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
62
Added:
]
src/MyFitnessTracker/MFTRepsDistributionGraph.class.st
@@ -6,15 +6,16 @@
6
6
7
7
{ #category : #'as yet unclassified' }
8
8
MFTRepsDistributionGraph >> crunchTheNumbers [
9
Added:
"TODO: This looks ugly."
9
10
10
Removed:
| exercises repTally |
11
Removed:
exercises := self session user workouts flatCollect: #exercises.
11
Added:
| sets repTally |
12
Added:
sets := self session user workouts flatCollect: #sets.
12
13
repTally := Dictionary new.
13
Removed:
exercises do: [ :exercise |
14
Removed:
repTally at: exercise englishName ifAbsentPut: [ 0 ].
14
Added:
sets do: [ :set |
15
Added:
repTally at: set exercise englishName ifAbsentPut: [ 0 ].
15
16
repTally
16
Removed:
at: exercise englishName
17
Removed:
put: (repTally at: exercise englishName) + exercise repsBySet sum ].
17
Added:
at: set exercise englishName
18
Added:
put: (repTally at: set exercise englishName) + set reps ].
18
19
19
20
labels := repTally keys.
20
21
data := repTally values
src/MyFitnessTracker/MFTSQLite3Database.class.st
@@ -6,106 +6,149 @@
6
6
'userId'
7
7
],
8
8
#classInstVars : [
9
Removed:
'defaultLocation'
9
Added:
'defaultLocation',
10
Added:
'allMuscleGroups',
11
Added:
'allMuscles',
12
Added:
'allExercises'
10
13
],
11
14
#category : #'MyFitnessTracker-Model'
12
15
}
13
16
17
Added:
{ #category : #accessing }
18
Added:
MFTSQLite3Database class >> allExercises [
19
Added:
20
Added:
^ allExercises
21
Added:
]
22
Added:
23
Added:
{ #category : #accessing }
24
Added:
MFTSQLite3Database class >> allExercises: anObject [
25
Added:
26
Added:
allExercises := anObject
27
Added:
]
28
Added:
14
29
{ #category : #'as yet unclassified' }
15
Removed:
MFTSQLite3Database class >> defaultConnection [
30
Added:
MFTSQLite3Database class >> allExercisesAsDict [
16
31
17
Removed:
^ self newOnDefaultLocation connection
32
Added:
| dict |
33
Added:
dict := Dictionary new.
34
Added:
allExercises do: [ :exercise |
35
Added:
dict at: exercise englishName put: exercise ].
36
Added:
^ dict
18
37
]
19
38
20
39
{ #category : #accessing }
21
Removed:
MFTSQLite3Database class >> defaultLocation [
40
Added:
MFTSQLite3Database class >> allMuscleGroups [
22
41
23
Removed:
^ defaultLocation
42
Added:
^ allMuscleGroups
24
43
]
25
44
26
45
{ #category : #accessing }
27
Removed:
MFTSQLite3Database class >> defaultLocation: aFilePath [
46
Added:
MFTSQLite3Database class >> allMuscleGroups: anObject [
28
47
29
Removed:
defaultLocation := aFilePath
48
Added:
allMuscleGroups := anObject
30
49
]
31
50
32
51
{ #category : #'as yet unclassified' }
33
Removed:
MFTSQLite3Database class >> ensureAllTablesExist [
52
Added:
MFTSQLite3Database class >> allMuscleGroupsAsDict [
34
53
35
Removed:
self defaultConnection
36
Removed:
open;
37
Removed:
execute: self ensureUsersTableExists;
38
Removed:
execute: self ensureProspectsTableExists;
39
Removed:
execute: self ensureWeightsTableExists;
40
Removed:
execute: self ensureWorkoutsTableExists;
41
Removed:
execute: self ensureExercisesTableExists;
42
Removed:
execute: self ensureSetsTableExists;
43
Removed:
close
54
Added:
| dict |
55
Added:
dict := Dictionary new.
56
Added:
allMuscleGroups do: [ :muscleGroup |
57
Added:
dict at: muscleGroup englishName put: muscleGroup ].
58
Added:
^ dict
44
59
]
45
60
46
Removed:
{ #category : #'as yet unclassified' }
47
Removed:
MFTSQLite3Database class >> ensureExercisesTableExists [
61
Added:
{ #category : #accessing }
62
Added:
MFTSQLite3Database class >> allMuscles [
48
63
49
Removed:
^ 'CREATE TABLE IF NOT EXISTS "exercises" (
50
Removed:
"id" INTEGER NOT NULL UNIQUE,
51
Removed:
"name" TEXT NOT NULL,
52
Removed:
PRIMARY KEY("id" AUTOINCREMENT))'
64
Added:
^ allMuscles
53
65
]
54
66
55
Removed:
{ #category : #'as yet unclassified' }
56
Removed:
MFTSQLite3Database class >> ensureProspectsTableExists [
67
Added:
{ #category : #accessing }
68
Added:
MFTSQLite3Database class >> allMuscles: anObject [
57
69
58
Removed:
^ 'CREATE TABLE IF NOT EXISTS "prospects" (
59
Removed:
"id" INTEGER,
60
Removed:
"email" TEXT NOT NULL,
61
Removed:
"date_time" TEXT NOT NULL,
62
Removed:
PRIMARY KEY("id" AUTOINCREMENT))'
70
Added:
allMuscles := anObject
63
71
]
64
72
65
73
{ #category : #'as yet unclassified' }
66
Removed:
MFTSQLite3Database class >> ensureSetsTableExists [
74
Added:
MFTSQLite3Database class >> defaultConnection [
67
75
68
Removed:
^ 'CREATE TABLE IF NOT EXISTS "sets" (
69
Removed:
"id" INTEGER NOT NULL UNIQUE,
70
Removed:
""
71
Removed:
"name" TEXT NOT NULL,
72
Removed:
PRIMARY KEY("id" AUTOINCREMENT))'
76
Added:
^ self newOnDefaultLocation connection
73
77
]
74
78
75
Removed:
{ #category : #'as yet unclassified' }
76
Removed:
MFTSQLite3Database class >> ensureUsersTableExists [
79
Added:
{ #category : #accessing }
80
Added:
MFTSQLite3Database class >> defaultLocation [
77
81
78
Removed:
^ 'CREATE TABLE IF NOT EXISTS "users" (
79
Removed:
"id" INTEGER UNIQUE,
80
Removed:
"username" TEXT NOT NULL,
81
Removed:
"password_hash" BLOB NOT NULL,
82
Removed:
"real_first_name" TEXT,
83
Removed:
"real_last_name" TEXT,
84
Removed:
"date_of_birth" TEXT,
85
Removed:
PRIMARY KEY("id" AUTOINCREMENT))'
82
Added:
^ defaultLocation
86
83
]
87
84
88
Removed:
{ #category : #'as yet unclassified' }
89
Removed:
MFTSQLite3Database class >> ensureWeightsTableExists [
85
Added:
{ #category : #accessing }
86
Added:
MFTSQLite3Database class >> defaultLocation: aFilePath [
90
87
91
Removed:
^ 'CREATE TABLE IF NOT EXISTS "weights" (
92
Removed:
"id" INTEGER UNIQUE,
93
Removed:
"user_id" INTEGER NOT NULL,
94
Removed:
"date" TEXT NOT NULL,
95
Removed:
"value" NUMERIC NOT NULL,
96
Removed:
PRIMARY KEY("id" AUTOINCREMENT))'
88
Added:
defaultLocation := aFilePath
97
89
]
98
90
91
Added:
{ #category : #accessing }
92
Added:
MFTSQLite3Database class >> getAllExercises [
93
Added:
94
Added:
| connection allRows |
95
Added:
connection := self defaultConnection open.
96
Added:
allRows := (connection execute: 'SELECT * FROM Exercises') rows.
97
Added:
connection close.
98
Added:
^ Array withAll: (allRows collect: [ :row |
99
Added:
MFTExercise newFromDictionary: row asDictionary ])
100
Added:
]
101
Added:
102
Added:
{ #category : #accessing }
103
Added:
MFTSQLite3Database class >> getAllMuscleGroups [
104
Added:
105
Added:
| connection allRows |
106
Added:
connection := self defaultConnection open.
107
Added:
allRows := (connection execute: 'SELECT * FROM Muscle_Groups') rows.
108
Added:
connection close.
109
Added:
^ Array withAll: (allRows collect: [ :row |
110
Added:
MFTMuscleGroup newFromDictionary: row asDictionary ])
111
Added:
]
112
Added:
113
Added:
{ #category : #accessing }
114
Added:
MFTSQLite3Database class >> getAllMuscles [
115
Added:
116
Added:
| connection allRows |
117
Added:
connection := self defaultConnection open.
118
Added:
allRows := (connection execute: 'SELECT * FROM Muscles') rows.
119
Added:
connection close.
120
Added:
^ Array withAll: (allRows collect: [ :row |
121
Added:
MFTMuscle newFromDictionary: row asDictionary ])
122
Added:
]
123
Added:
124
Added:
{ #category : #accessing }
125
Added:
MFTSQLite3Database class >> getAllWorkoutsForUser: aMFTUser [
126
Added:
127
Added:
| connection allRepsRows allWorkoutRows |
128
Added:
connection := self defaultConnection open.
129
Added:
connection beginTransaction.
130
Added:
allRepsRows := ((connection execute:
131
Added:
'SELECT * FROM Workouts WHERE user_id = ?') with:
132
Added:
{ aMFTUser id }) rows.
133
Added:
allWorkoutRows := ((connection execute:
134
Added:
'SELECT * FROM Workouts WHERE user_id = ?')
135
Added:
with: { aMFTUser id }) rows.
136
Added:
connection commitTransaction.
137
Added:
connection close.
138
Added:
^ Array withAll: (allWorkoutRows collect: [ :row |
139
Added:
MFTWorkout newFromDictionary: row asDictionary ])
140
Added:
]
141
Added:
99
142
{ #category : #'as yet unclassified' }
100
Removed:
MFTSQLite3Database class >> ensureWorkoutsTableExists [
143
Added:
MFTSQLite3Database class >> getExerciseIdFromName: aString [
101
144
102
Removed:
^ 'CREATE TABLE IF NOT EXISTS "workouts" (
103
Removed:
"id" INTEGER UNIQUE,
104
Removed:
"user_id" INTEGER NOT NULL,
105
Removed:
"date" TEXT NOT NULL,
106
Removed:
"primary_muscle" TEXT,
107
Removed:
"secondary_muscles" TEXT,
108
Removed:
PRIMARY KEY("id" AUTOINCREMENT))'
145
Added:
^ allExercises
146
Added:
detect: [ :each | each englishName = aString ]
147
Added:
ifFound: [ :exercise | exercise id ]
148
Added:
ifNone: [
149
Added:
self error:
150
Added:
('No exercise with English name ''{1}'' found' format:
151
Added:
{ aString }) ]
109
152
]
110
153
111
154
{ #category : #'as yet unclassified' }
@@ -124,17 +167,32 @@
124
167
aMFTUser passwordHash }) onlyRow: [
125
168
Dictionary new ]) asDictionary.
126
169
connection close.
127
Removed:
existingUserDict
128
Removed:
ifNotEmpty: [ ^ MFTUser newFromDictionary: existingUserDict ]
129
Removed:
ifEmpty: [ ^ MFTUser new ]
170
Added:
^ existingUserDict
171
Added:
ifNotEmpty: [ MFTUser newFromDictionary: existingUserDict ]
172
Added:
ifEmpty: [ nil ]
130
173
]
131
174
175
Added:
{ #category : #'as yet unclassified' }
176
Added:
MFTSQLite3Database class >> getTestUser [
177
Added:
178
Added:
| connection testUserDict |
179
Added:
connection := self defaultConnection.
180
Added:
connection open.
181
Added:
testUserDict := (connection execute:
182
Added:
'SELECT * FROM users WHERE id = 1') onlyRow
183
Added:
asDictionary.
184
Added:
connection close.
185
Added:
^ MFTUser newFromDictionary: testUserDict
186
Added:
]
187
Added:
132
188
{ #category : #'class initialization' }
133
189
MFTSQLite3Database class >> initialize [
134
190
135
191
defaultLocation := (Smalltalk imageDirectory / 'mft.sqlite3')
136
192
fullName.
137
Removed:
self ensureAllTablesExist
193
Added:
allMuscleGroups := self getAllMuscleGroups.
194
Added:
allMuscles := self getAllMuscles.
195
Added:
allExercises := self getAllExercises
138
196
]
139
197
140
198
{ #category : #'instance creation' }
@@ -146,51 +204,27 @@
146
204
{ #category : #'class initialization' }
147
205
MFTSQLite3Database class >> populatePlaceholderWeights [
148
206
149
Removed:
| connection |
150
Removed:
connection := self defaultConnection open.
207
Added:
| db |
208
Added:
db := self newOnDefaultLocation userId: 1.
209
Added:
db connection open.
210
Added:
db connection execute: 'DELETE FROM Weights'.
151
211
MFTWeight placeholderCollection do: [ :weight |
152
Removed:
connection
153
Removed:
execute: 'INSERT INTO weights(user_id, date, value)
154
Removed:
VALUES( ?, ?, ?)'
155
Removed:
with: {
156
Removed:
1.
157
Removed:
weight date.
158
Removed:
weight value } ].
159
Removed:
connection close
212
Added:
db insertWeight: weight ].
213
Added:
db connection close
160
214
]
161
215
162
216
{ #category : #'class initialization' }
163
217
MFTSQLite3Database class >> populatePlaceholderWorkouts [
164
218
165
Removed:
| connection |
166
Removed:
connection := self defaultConnection open.
167
Removed:
connection beginTransaction.
219
Added:
| db |
220
Added:
db := self newOnDefaultLocation userId: 1.
221
Added:
db connection open.
222
Added:
db connection
223
Added:
execute: 'DELETE FROM Workouts';
224
Added:
execute: 'DELETE FROM Sets'.
168
225
MFTWorkout placeholderCollection do: [ :workout |
169
Removed:
| workoutId |
170
Removed:
connection
171
Removed:
execute:
172
Removed:
'INSERT INTO workouts(user_id, date, primary_muscle, secondary_muscles)
173
Removed:
VALUES(?, ?, ?, ?)'
174
Removed:
with: {
175
Removed:
1.
176
Removed:
workout date yyyymmdd.
177
Removed:
workout primaryMuscle canonicalName.
178
Removed:
(workout secondaryMuscles collect: #canonicalName) asCommaString }.
179
Removed:
workoutId := (connection
180
Removed:
execute: 'SELECT workouts.id
181
Removed:
FROM workouts
182
Removed:
WHERE date = ?'
183
Removed:
value: workout date yyyymmdd) onlyValue.
184
Removed:
workout exercises do: [ :exercise |
185
Removed:
connection
186
Removed:
execute: 'INSERT INTO exercises(workout_id, name, sets)
187
Removed:
VALUES(?, ?, ?)'
188
Removed:
with: {
189
Removed:
workoutId.
190
Removed:
exercise canonicalName.
191
Removed:
exercise sets asJson } ] ].
192
Removed:
connection commitTransaction.
193
Removed:
connection close
226
Added:
db insertWorkout: workout ].
227
Added:
db connection close
194
228
]
195
229
196
230
{ #category : #'as yet unclassified' }
@@ -242,8 +276,8 @@
242
276
execute: 'SELECT *
243
277
FROM weights
244
278
WHERE user_id = ?'
245
Removed:
value: userId) rows collect: [ :each |
246
Removed:
MFTWeight newFromDictionary: each asDictionary ]
279
Added:
value: userId) rows collect: [ :row |
280
Added:
MFTWeight newFromDictionary: row asDictionary ]
247
281
]
248
282
249
283
{ #category : #'as yet unclassified' }
@@ -278,7 +312,7 @@
278
312
]
279
313
280
314
{ #category : #'as yet unclassified' }
281
Removed:
MFTSQLite3Database >> deleteExercisesForWorkoutId: id [
315
Added:
MFTSQLite3Database >> deleteSetsForWorkoutId: id [
282
316
283
317
connection
284
318
execute: 'DELETE
@@ -317,7 +351,7 @@
317
351
connection commitTransaction
318
352
]
319
353
320
Removed:
{ #category : #private }
354
Added:
{ #category : #accessing }
321
355
MFTSQLite3Database >> insert: anObject [
322
356
"Insert an object in the database, using the appropriate method."
323
357
@@ -336,18 +370,31 @@
336
370
]
337
371
338
372
{ #category : #'as yet unclassified' }
339
Removed:
MFTSQLite3Database >> insertExercise: aMFTExercise forWorkoutId: workoutId [
373
Added:
MFTSQLite3Database >> insertSet: aMFTSet forWorkoutId: workoutId [
340
374
341
375
connection
342
Removed:
execute: 'INSERT INTO exercises(workout_id, name, sets)
343
Removed:
VALUES( ?, ?, ?)'
376
Added:
execute:
377
Added:
'INSERT INTO Sets ("workout_id","exercise_id", "set_group", "set_number", "reps", "load", "rpe", "rest_after")
378
Added:
VALUES(?, ?, ?, ?, ?, ?, ?, ?)'
344
379
with: {
345
380
workoutId.
346
Removed:
aMFTExercise canonicalName.
347
Removed:
aMFTExercise sets asJson }
381
Added:
aMFTSet exerciseId.
382
Added:
aMFTSet setGroup.
383
Added:
aMFTSet setNumber.
384
Added:
aMFTSet reps.
385
Added:
aMFTSet load.
386
Added:
aMFTSet rpe.
387
Added:
aMFTSet restAfter }
348
388
]
349
389
350
390
{ #category : #'as yet unclassified' }
391
Added:
MFTSQLite3Database >> insertSets: aMFTSetCollection forWorkoutId: workoutId [
392
Added:
393
Added:
aMFTSetCollection do: [ :set |
394
Added:
self insertSet: set forWorkoutId: workoutId ]
395
Added:
]
396
Added:
397
Added:
{ #category : #'as yet unclassified' }
351
398
MFTSQLite3Database >> insertWeight: aMFTWeight [
352
399
353
400
connection
@@ -365,32 +412,23 @@
365
412
| workoutId |
366
413
connection beginTransaction.
367
414
connection
368
Removed:
execute: 'INSERT INTO Workouts ("id" INTEGER UNIQUE,
369
Removed:
"user_id",
370
Removed:
"date" ,
371
Removed:
"primary_muscle",
372
Removed:
"secondary_muscles" )
373
Removed:
VALUES(?, ?, ?, ?)'
415
Added:
execute:
416
Added:
'INSERT INTO Workouts ("user_id", "date", "primary_muscle_group_id") VALUES(?, ?, ?)'
374
417
with: {
375
418
userId.
376
419
aMFTWorkout date yyyymmdd.
377
Removed:
aMFTWorkout primaryMuscle englishName.
378
Removed:
(aMFTWorkout secondaryMuscles collect: #englishName) asCommaString }.
420
Added:
aMFTWorkout primaryMuscleGroupId }.
379
421
workoutId := (connection
380
422
execute: 'SELECT id
381
423
FROM workouts
382
424
WHERE user_id = ?
383
425
AND date = ?
384
Removed:
AND primary_muscle = ?
385
Removed:
AND secondary_muscles = ?'
426
Added:
AND primary_muscle_group_id = ?'
386
427
with: {
387
428
userId.
388
429
aMFTWorkout date yyyymmdd.
389
Removed:
aMFTWorkout primaryMuscle englishName.
390
Removed:
(aMFTWorkout secondaryMuscles collect:
391
Removed:
#canonicalName) asCommaString }) onlyValue.
392
Removed:
aMFTWorkout exercises do: [ :exercise |
393
Removed:
self insertExercise: exercise forWorkoutId: workoutId ].
430
Added:
aMFTWorkout primaryMuscleGroupId }) onlyValue.
431
Added:
self insertSets: aMFTWorkout sets forWorkoutId: workoutId.
394
432
connection commitTransaction
395
433
]
396
434
@@ -493,7 +531,7 @@
493
531
(newMFTWorkout secondaryMuscles collect: #englishName)
494
532
asCommaString.
495
533
workoutId }.
496
Removed:
self deleteExercisesForWorkoutId: workoutId.
534
Added:
self deleteSetsForWorkoutId: workoutId.
497
535
newMFTWorkout exercises do: [ :exercise |
498
536
self insertExercise: exercise forWorkoutId: workoutId ]
499
537
]
src/MyFitnessTracker/MFTSandboxPage.class.st
@@ -0,0 +1,20 @@
1
Added:
Class {
2
Added:
#name : #MFTSandboxPage,
3
Added:
#superclass : #MFTPage,
4
Added:
#category : #'MyFitnessTracker-Components'
5
Added:
}
6
Added:
7
Added:
{ #category : #initialization }
8
Added:
MFTSandboxPage >> initialize [
9
Added:
10
Added:
super initialize.
11
Added:
title := 'sandbox'
12
Added:
]
13
Added:
14
Added:
{ #category : #rendering }
15
Added:
MFTSandboxPage >> renderContentOn: html [
16
Added:
17
Added:
self renderPageOn: html with: [
18
Added:
html text: 'Welcome to the sandbox page.'.
19
Added:
MFTSQLite3Database allMuscleGroups do: [ :each | html render: each ] ]
20
Added:
]
src/MyFitnessTracker/MFTSecondaryMuscleGroupsDialog.class.st
@@ -0,0 +1,63 @@
1
Added:
Class {
2
Added:
#name : #MFTSecondaryMuscleGroupsDialog,
3
Added:
#superclass : #MFTDialog,
4
Added:
#instVars : [
5
Added:
'secondaryMuscleGroups'
6
Added:
],
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
Added:
}
9
Added:
10
Added:
{ #category : #initialization }
11
Added:
MFTSecondaryMuscleGroupsDialog >> initialize [
12
Added:
13
Added:
super initialize.
14
Added:
secondaryMuscleGroups := OrderedCollection new
15
Added:
]
16
Added:
17
Added:
{ #category : #rendering }
18
Added:
MFTSecondaryMuscleGroupsDialog >> renderContentOn: html [
19
Added:
20
Added:
| allMuscleGroups selectedMuscles |
21
Added:
allMuscleGroups := MFTSQLite3Database allMuscleGroups.
22
Added:
"selectedMuscles := allMuscles
23
Added:
detect: [ :each |
24
Added:
each englishName
25
Added:
= (secondaryMuscles collect: #englishName) ]
26
Added:
ifNone: [ nil ]."
27
Added:
28
Added:
self renderDialogOn: html with: [
29
Added:
html multiSelect formControl
30
Added:
list: allMuscleGroups;
31
Added:
"selected: selectedMuscles;"labels: [ :muscleGroup |
32
Added:
muscleGroup englishName ];
33
Added:
callback: [ :groups |
34
Added:
groups ifNotEmpty: [ secondaryMuscleGroups := groups ] ] ]
35
Added:
]
36
Added:
37
Added:
{ #category : #rendering }
38
Added:
MFTSecondaryMuscleGroupsDialog >> renderSubmitOn: html [
39
Added:
40
Added:
html buttonGroup: [
41
Added:
html formButton
42
Added:
beSubmit;
43
Added:
bePrimary;
44
Added:
callback: [ self answer: secondaryMuscleGroups ];
45
Added:
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
46
Added:
html formButton
47
Added:
beSubmit;
48
Added:
beSecondary;
49
Added:
callback: [ self answer: OrderedCollection new ];
50
Added:
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
51
Added:
]
52
Added:
53
Added:
{ #category : #accessing }
54
Added:
MFTSecondaryMuscleGroupsDialog >> secondaryMuscleGroups [
55
Added:
56
Added:
^ secondaryMuscleGroups
57
Added:
]
58
Added:
59
Added:
{ #category : #accessing }
60
Added:
MFTSecondaryMuscleGroupsDialog >> secondaryMuscleGroups: anObject [
61
Added:
62
Added:
secondaryMuscleGroups := anObject
63
Added:
]
src/MyFitnessTracker/MFTSecondaryMusclesDialog.class.st
@@ -1,63 +0,0 @@
1
Removed:
Class {
2
Removed:
#name : #MFTSecondaryMusclesDialog,
3
Removed:
#superclass : #MFTDialog,
4
Removed:
#instVars : [
5
Removed:
'secondaryMuscles'
6
Removed:
],
7
Removed:
#category : #'MyFitnessTracker-Dialogs'
8
Removed:
}
9
Removed:
10
Removed:
{ #category : #initialization }
11
Removed:
MFTSecondaryMusclesDialog >> initialize [
12
Removed:
13
Removed:
super initialize.
14
Removed:
secondaryMuscles := OrderedCollection new
15
Removed:
]
16
Removed:
17
Removed:
{ #category : #rendering }
18
Removed:
MFTSecondaryMusclesDialog >> renderContentOn: html [
19
Removed:
20
Removed:
| allMuscles selectedMuscles |
21
Removed:
allMuscles := MFTUtils allMuscleGroups.
22
Removed:
"selectedMuscles := allMuscles
23
Removed:
detect: [ :each |
24
Removed:
each englishName
25
Removed:
= (secondaryMuscles collect: #englishName) ]
26
Removed:
ifNone: [ nil ]."
27
Removed:
28
Removed:
self renderDialogOn: html with: [
29
Removed:
html multiSelect formControl
30
Removed:
list: allMuscles;
31
Removed:
"selected: selectedMuscles;"labels: [ :muscleGroup |
32
Removed:
muscleGroup englishName ];
33
Removed:
callback: [ :groups |
34
Removed:
groups ifNotEmpty: [ secondaryMuscles := groups ] ] ]
35
Removed:
]
36
Removed:
37
Removed:
{ #category : #rendering }
38
Removed:
MFTSecondaryMusclesDialog >> renderSubmitOn: html [
39
Removed:
40
Removed:
html buttonGroup: [
41
Removed:
html formButton
42
Removed:
beSubmit;
43
Removed:
bePrimary;
44
Removed:
callback: [ self answer: secondaryMuscles ];
45
Removed:
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
46
Removed:
html formButton
47
Removed:
beSubmit;
48
Removed:
beSecondary;
49
Removed:
callback: [ self answer: OrderedCollection new ];
50
Removed:
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
51
Removed:
]
52
Removed:
53
Removed:
{ #category : #accessing }
54
Removed:
MFTSecondaryMusclesDialog >> secondaryMuscles [
55
Removed:
56
Removed:
^ secondaryMuscles
57
Removed:
]
58
Removed:
59
Removed:
{ #category : #accessing }
60
Removed:
MFTSecondaryMusclesDialog >> secondaryMuscles: anObject [
61
Removed:
62
Removed:
secondaryMuscles := anObject
63
Removed:
]
src/MyFitnessTracker/MFTSession.class.st
@@ -74,6 +74,13 @@
74
74
pageManager := aMFTPageManager
75
75
]
76
76
77
Added:
{ #category : #'parent/child' }
78
Added:
MFTSession >> unregistered [
79
Added:
80
Added:
super unregistered.
81
Added:
self logout
82
Added:
]
83
Added:
77
84
{ #category : #accessing }
78
85
MFTSession >> user [
79
86
src/MyFitnessTracker/MFTSet.class.st
@@ -1,18 +1,16 @@
1
Removed:
"
2
Removed:
I represent a single set of an exercise.
3
Removed:
4
Removed:
Instance variables
5
Removed:
reps: number of repetitions performed by the user.
6
Removed:
weight: weight used for the set.
7
Removed:
rpe: rate of perceived exertion, from 1 to 10.
8
Removed:
"
9
1
Class {
10
2
#name : #MFTSet,
11
3
#superclass : #Object,
12
4
#instVars : [
5
Added:
'id',
6
Added:
'workoutId',
7
Added:
'exerciseId',
8
Added:
'setGroup',
9
Added:
'setNumber',
13
10
'reps',
14
Removed:
'weight',
15
Removed:
'rpe'
11
Added:
'load',
12
Added:
'rpe',
13
Added:
'restAfter'
16
14
],
17
15
#category : #'MyFitnessTracker-Model'
18
16
}
@@ -29,6 +27,130 @@
29
27
yourself
30
28
]
31
29
30
Added:
{ #category : #'as yet unclassified' }
31
Added:
MFTSet class >> id: id workoutId: workoutId exerciseId: exerciseId setGroup: setGroup setNumber: setNumber reps: reps [
32
Added:
"These are the fields mandated by the database schema."
33
Added:
34
Added:
^ self new
35
Added:
id: id;
36
Added:
workoutId: workoutId;
37
Added:
exerciseId: exerciseId;
38
Added:
setGroup: setGroup;
39
Added:
setNumber: setNumber;
40
Added:
reps: reps;
41
Added:
yourself
42
Added:
]
43
Added:
44
Added:
{ #category : #'instance creation' }
45
Added:
MFTSet class >> newFromDictionary: aDictionary [
46
Added:
47
Added:
^ self new
48
Added:
id: (aDictionary at: 'id');
49
Added:
workoutId: (aDictionary at: 'workout_id');
50
Added:
exerciseId: (aDictionary at: 'exercise_id');
51
Added:
setGroup: (aDictionary at: 'set_group');
52
Added:
setNumber: (aDictionary at: 'set');
53
Added:
reps: (aDictionary at: 'reps');
54
Added:
rpe: (aDictionary at: 'rpe');
55
Added:
restAfter: (aDictionary at: 'rest_after');
56
Added:
yourself
57
Added:
]
58
Added:
59
Added:
{ #category : #'as yet unclassified' }
60
Added:
MFTSet class >> placeholderCollection [
61
Added:
62
Added:
| forWorkout1 forWorkout2 forWorkout3 |
63
Added:
forWorkout1 := {
64
Added:
(self new
65
Added:
id: 1;
66
Added:
workoutId: 1;
67
Added:
exerciseId: 2;
68
Added:
setGroup: 1;
69
Added:
setNumber: 1;
70
Added:
reps: 8;
71
Added:
load: 20;
72
Added:
rpe: 8).
73
Added:
(self new
74
Added:
id: 2;
75
Added:
workoutId: 1;
76
Added:
exerciseId: 2;
77
Added:
setGroup: 1;
78
Added:
setNumber: 2;
79
Added:
reps: 8;
80
Added:
load: 25;
81
Added:
rpe: 9).
82
Added:
(self new
83
Added:
id: 3;
84
Added:
workoutId: 1;
85
Added:
exerciseId: 2;
86
Added:
setGroup: 1;
87
Added:
setNumber: 3;
88
Added:
reps: 8;
89
Added:
load: 30;
90
Added:
rpe: 10) }.
91
Added:
forWorkout2 := {
92
Added:
(self new
93
Added:
id: 4;
94
Added:
workoutId: 2;
95
Added:
exerciseId: 3;
96
Added:
setGroup: 1;
97
Added:
setNumber: 1;
98
Added:
reps: 50;
99
Added:
load: 15;
100
Added:
rpe: 4).
101
Added:
(self new
102
Added:
id: 5;
103
Added:
workoutId: 2;
104
Added:
exerciseId: 4;
105
Added:
setGroup: 2;
106
Added:
setNumber: 2;
107
Added:
reps: 8;
108
Added:
load: 25;
109
Added:
rpe: 6).
110
Added:
(self new
111
Added:
id: 6;
112
Added:
workoutId: 2;
113
Added:
exerciseId: 4;
114
Added:
setGroup: 2;
115
Added:
setNumber: 3;
116
Added:
reps: 8;
117
Added:
load: 30;
118
Added:
rpe: 8) }.
119
Added:
forWorkout3 := {
120
Added:
(self new
121
Added:
id: 7;
122
Added:
workoutId: 3;
123
Added:
exerciseId: 10;
124
Added:
setGroup: 1;
125
Added:
setNumber: 1;
126
Added:
reps: 5;
127
Added:
load: 100;
128
Added:
rpe: 8).
129
Added:
(self new
130
Added:
id: 8;
131
Added:
workoutId: 3;
132
Added:
exerciseId: 11;
133
Added:
setGroup: 2;
134
Added:
setNumber: 2;
135
Added:
reps: 5;
136
Added:
load: 100;
137
Added:
rpe: 9).
138
Added:
(self new
139
Added:
id: 9;
140
Added:
workoutId: 3;
141
Added:
exerciseId: 12;
142
Added:
setGroup: 3;
143
Added:
setNumber: 3;
144
Added:
reps: 5;
145
Added:
load: 100;
146
Added:
rpe: 10) }.
147
Added:
148
Added:
^ {
149
Added:
forWorkout1.
150
Added:
forWorkout2.
151
Added:
forWorkout3 } flattened
152
Added:
]
153
Added:
32
154
{ #category : #accessing }
33
155
MFTSet class >> reps: anInteger [
34
156
@@ -38,64 +160,136 @@
38
160
]
39
161
40
162
{ #category : #'as yet unclassified' }
41
Removed:
MFTSet class >> reps: anInteger rpe: aPercentage [
163
Added:
MFTSet class >> reps: anInteger load: anInteger2 [
42
164
43
165
^ self new
44
166
reps: anInteger;
45
Removed:
rpe: aPercentage;
167
Added:
load: anInteger2;
46
168
yourself
47
169
]
48
170
49
171
{ #category : #'as yet unclassified' }
50
Removed:
MFTSet class >> reps: anInteger weight: anInteger2 [
172
Added:
MFTSet class >> reps: aValue load: aValue2 rpe: aValue3 [
51
173
52
174
^ self new
53
Removed:
reps: anInteger;
54
Removed:
weight: anInteger2;
175
Added:
reps: aValue;
176
Added:
load: aValue2;
177
Added:
rpe: aValue3;
55
178
yourself
56
179
]
57
180
58
181
{ #category : #'as yet unclassified' }
59
Removed:
MFTSet class >> reps: aValue weight: aValue2 rpe: aValue3 [
182
Added:
MFTSet class >> reps: aValue load: aValue2 rpe: aValue3 restAfter: aValue4 [
60
183
61
184
^ self new
62
185
reps: aValue;
63
Removed:
weight: aValue2;
186
Added:
load: aValue2;
64
187
rpe: aValue3;
188
Added:
restAfter: aValue4;
65
189
yourself
66
190
]
67
191
68
Removed:
{ #category : #initialization }
69
Removed:
MFTSet >> initialize [
192
Added:
{ #category : #'as yet unclassified' }
193
Added:
MFTSet class >> reps: anInteger rpe: aPercentage [
70
194
71
Removed:
super initialize.
72
Removed:
reps := MFTUser defaultReps
195
Added:
^ self new
196
Added:
reps: anInteger;
197
Added:
rpe: aPercentage;
198
Added:
yourself
73
199
]
74
200
201
Added:
{ #category : #accessing }
202
Added:
MFTSet >> exercise [
203
Added:
204
Added:
^ MFTSQLite3Database allExercises detect: [ :exercise |
205
Added:
exercise id = exerciseId ]
206
Added:
]
207
Added:
208
Added:
{ #category : #accessing }
209
Added:
MFTSet >> exerciseId [
210
Added:
211
Added:
^ exerciseId
212
Added:
]
213
Added:
214
Added:
{ #category : #accessing }
215
Added:
MFTSet >> exerciseId: anInteger [
216
Added:
217
Added:
exerciseId := anInteger
218
Added:
]
219
Added:
220
Added:
{ #category : #testing }
221
Added:
MFTSet >> hasLoad [
222
Added:
223
Added:
^ load isNotNil and: [ load asString isNotEmpty ]
224
Added:
]
225
Added:
75
226
{ #category : #'as yet unclassified' }
76
Removed:
MFTSet >> jsonOn: aRenderer [
227
Added:
MFTSet >> hasRestAfter [
77
228
78
Removed:
| dict |
79
Removed:
dict := Dictionary newFrom: {
80
Removed:
(#reps -> reps).
81
Removed:
(#weight -> weight).
82
Removed:
(#rpe -> rpe) }.
83
Removed:
dict jsonOn: aRenderer
229
Added:
^ restAfter isNotNil and: [ restAfter asString isNotEmpty ]
84
230
]
85
231
232
Added:
{ #category : #'as yet unclassified' }
233
Added:
MFTSet >> hasRpe [
234
Added:
235
Added:
^ rpe isNotNil and: [ rpe asString isNotEmpty ]
236
Added:
]
237
Added:
238
Added:
{ #category : #'as yet unclassified' }
239
Added:
MFTSet >> hasVolume [
240
Added:
241
Added:
^ self volume ~~ 0
242
Added:
]
243
Added:
86
244
{ #category : #accessing }
245
Added:
MFTSet >> id [
246
Added:
247
Added:
^ id
248
Added:
]
249
Added:
250
Added:
{ #category : #accessing }
251
Added:
MFTSet >> id: anObject [
252
Added:
253
Added:
id := anObject
254
Added:
]
255
Added:
256
Added:
{ #category : #accessing }
257
Added:
MFTSet >> load [
258
Added:
259
Added:
^ load
260
Added:
]
261
Added:
262
Added:
{ #category : #accessing }
263
Added:
MFTSet >> load: anObject [
264
Added:
265
Added:
load := anObject
266
Added:
]
267
Added:
268
Added:
{ #category : #accessing }
87
269
MFTSet >> reps [
88
270
89
271
^ reps
90
272
]
91
273
92
274
{ #category : #accessing }
93
Removed:
MFTSet >> reps: anInteger [
275
Added:
MFTSet >> reps: anObject [
94
276
95
Removed:
reps := anInteger
277
Added:
reps := anObject
96
278
]
97
279
98
280
{ #category : #accessing }
281
Added:
MFTSet >> restAfter [
282
Added:
283
Added:
^ restAfter
284
Added:
]
285
Added:
286
Added:
{ #category : #accessing }
287
Added:
MFTSet >> restAfter: anObject [
288
Added:
289
Added:
restAfter := anObject
290
Added:
]
291
Added:
292
Added:
{ #category : #accessing }
99
293
MFTSet >> rpe [
100
294
101
295
^ rpe
@@ -107,22 +301,45 @@
107
301
rpe := anInteger
108
302
]
109
303
304
Added:
{ #category : #accessing }
305
Added:
MFTSet >> setGroup [
306
Added:
307
Added:
^ setGroup
308
Added:
]
309
Added:
310
Added:
{ #category : #accessing }
311
Added:
MFTSet >> setGroup: anInteger [
312
Added:
313
Added:
setGroup := anInteger
314
Added:
]
315
Added:
316
Added:
{ #category : #accessing }
317
Added:
MFTSet >> setNumber [
318
Added:
319
Added:
^ setNumber
320
Added:
]
321
Added:
322
Added:
{ #category : #accessing }
323
Added:
MFTSet >> setNumber: anInteger [
324
Added:
325
Added:
setNumber := anInteger
326
Added:
]
327
Added:
110
328
{ #category : #'as yet unclassified' }
111
329
MFTSet >> volume [
330
Added:
"reps is never nil, as enforced by the database schema."
112
331
113
Removed:
^ (reps isNotNil and: [ weight isNotNil ])
114
Removed:
ifTrue: [ reps asNumber * weight asNumber ]
115
Removed:
ifFalse: [ 0 ]
332
Added:
^ load ifNotNil: [ reps * load ] ifNil: [ 0 ]
116
333
]
117
334
118
335
{ #category : #accessing }
119
Removed:
MFTSet >> weight [
336
Added:
MFTSet >> workoutId [
120
337
121
Removed:
^ weight
338
Added:
^ workoutId
122
339
]
123
340
124
341
{ #category : #accessing }
125
Removed:
MFTSet >> weight: aNumber [
342
Added:
MFTSet >> workoutId: anObject [
126
343
127
Removed:
weight := aNumber
344
Added:
workoutId := anObject
128
345
]
src/MyFitnessTracker/MFTSetDialog.class.st
@@ -0,0 +1,112 @@
1
Added:
Class {
2
Added:
#name : #MFTSetDialog,
3
Added:
#superclass : #MFTDialog,
4
Added:
#instVars : [
5
Added:
'set'
6
Added:
],
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
Added:
}
9
Added:
10
Added:
{ #category : #actions }
11
Added:
MFTSetDialog class >> edit: aMFTSet [
12
Added:
13
Added:
^ self new
14
Added:
set: aMFTSet;
15
Added:
action: #edit;
16
Added:
yourself
17
Added:
]
18
Added:
19
Added:
{ #category : #initialization }
20
Added:
MFTSetDialog >> initialize [
21
Added:
22
Added:
super initialize.
23
Added:
set := MFTSet new
24
Added:
]
25
Added:
26
Added:
{ #category : #rendering }
27
Added:
MFTSetDialog >> renderContentOn: html [
28
Added:
29
Added:
self renderDialogOn: html with: [
30
Added:
self renderExerciseSelectOn: html.
31
Added:
html formGroup: [
32
Added:
html label: 'Reps'.
33
Added:
html numberInput formControl
34
Added:
value: set reps;
35
Added:
callback: [ :value | set reps: value asInteger ] ].
36
Added:
html formGroup: [
37
Added:
html label: 'Load'.
38
Added:
html numberInput formControl
39
Added:
value: set load;
40
Added:
callback: [ :value |
41
Added:
value ifNotEmpty: [ set load: value asNumber ] ] ].
42
Added:
html formGroup: [
43
Added:
html label: 'RPE'.
44
Added:
html numberInput formControl
45
Added:
value: set rpe;
46
Added:
callback: [ :value |
47
Added:
value ifNotEmpty: [ set rpe: value asInteger ] ] ].
48
Added:
html formGroup: [
49
Added:
html label: 'Rest after (s)'.
50
Added:
html numberInput formControl
51
Added:
value: set restAfter;
52
Added:
callback: [ :value |
53
Added:
value ifNotEmpty: [ set restAfter: value asNumber ] ] ] ]
54
Added:
]
55
Added:
56
Added:
{ #category : #rendering }
57
Added:
MFTSetDialog >> renderExerciseSelectOn: html [
58
Added:
59
Added:
| allExercises selectedExercise |
60
Added:
allExercises := MFTSQLite3Database allExercises.
61
Added:
selectedExercise := allExercises
62
Added:
detect: [ :exercise |
63
Added:
exercise id = set exerciseId ]
64
Added:
ifNone: [ nil ].
65
Added:
html formGroup: [
66
Added:
html label: 'Exercise'.
67
Added:
html select formControl
68
Added:
list: allExercises;
69
Added:
selected: selectedExercise;
70
Added:
callback: [ :exercise | set exerciseId: exercise id ];
71
Added:
labels: [ :exercise | exercise englishName ] ]
72
Added:
]
73
Added:
74
Added:
{ #category : #delegation }
75
Added:
MFTSetDialog >> renderSubmitOn: html [
76
Added:
77
Added:
html buttonGroup: [
78
Added:
html formButton
79
Added:
beSubmit;
80
Added:
bePrimary;
81
Added:
callback: [
82
Added:
self answer: (set reps ifNotNil: [ set ] ifNil: [ nil ]) ];
83
Added:
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
84
Added:
html formButton
85
Added:
beSubmit;
86
Added:
beSecondary;
87
Added:
callback: [ self answer: nil ];
88
Added:
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
89
Added:
]
90
Added:
91
Added:
{ #category : #rendering }
92
Added:
MFTSetDialog >> renderTableHeaderOn: html [
93
Added:
94
Added:
html tableHead: [
95
Added:
html
96
Added:
tableHeading;
97
Added:
tableHeading: 'Reps';
98
Added:
tableHeading: 'Weight';
99
Added:
tableHeading: 'RPE' ]
100
Added:
]
101
Added:
102
Added:
{ #category : #accessing }
103
Added:
MFTSetDialog >> set [
104
Added:
105
Added:
^ set
106
Added:
]
107
Added:
108
Added:
{ #category : #accessing }
109
Added:
MFTSetDialog >> set: anObject [
110
Added:
111
Added:
set := anObject
112
Added:
]
src/MyFitnessTracker/MFTSetGroup.class.st
@@ -0,0 +1,35 @@
1
Added:
Class {
2
Added:
#name : #MFTSetGroup,
3
Added:
#superclass : #Object,
4
Added:
#instVars : [
5
Added:
'sets'
6
Added:
],
7
Added:
#category : #'MyFitnessTracker-Model'
8
Added:
}
9
Added:
10
Added:
{ #category : #accessing }
11
Added:
MFTSetGroup class >> sets: aMFTSetCollection [
12
Added:
13
Added:
^ self new
14
Added:
sets: aMFTSetCollection;
15
Added:
yourself
16
Added:
]
17
Added:
18
Added:
{ #category : #initialization }
19
Added:
MFTSetGroup >> initialize [
20
Added:
21
Added:
super initialize.
22
Added:
sets := OrderedCollection new
23
Added:
]
24
Added:
25
Added:
{ #category : #accessing }
26
Added:
MFTSetGroup >> sets [
27
Added:
28
Added:
^ sets
29
Added:
]
30
Added:
31
Added:
{ #category : #accessing }
32
Added:
MFTSetGroup >> sets: anObject [
33
Added:
34
Added:
sets := anObject
35
Added:
]
src/MyFitnessTracker/MFTSetsDialog.class.st
@@ -0,0 +1,168 @@
1
Added:
Class {
2
Added:
#name : #MFTSetsDialog,
3
Added:
#superclass : #MFTDialog,
4
Added:
#instVars : [
5
Added:
'sets'
6
Added:
],
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
Added:
}
9
Added:
10
Added:
{ #category : #actions }
11
Added:
MFTSetsDialog class >> edit: aMFTSetCollection [
12
Added:
13
Added:
^ self new
14
Added:
sets: aMFTSetCollection;
15
Added:
action: #edit;
16
Added:
yourself
17
Added:
]
18
Added:
19
Added:
{ #category : #adding }
20
Added:
MFTSetsDialog >> addSet [
21
Added:
22
Added:
| set setsSize |
23
Added:
setsSize := sets size + 1.
24
Added:
set := self call:
25
Added:
(MFTSetDialog new heading: 'Set #' , setsSize asString).
26
Added:
set ifNil: [ ^ self ].
27
Added:
set
28
Added:
setNumber: setsSize;
29
Added:
setGroup: setsSize.
30
Added:
sets add: set
31
Added:
]
32
Added:
33
Added:
{ #category : #adding }
34
Added:
MFTSetsDialog >> addSuperset [
35
Added:
36
Added:
| superset |
37
Added:
superset := self call: MFTSetDialog new.
38
Added:
superset ifNotNil: [ sets add: superset ]
39
Added:
]
40
Added:
41
Added:
{ #category : #initialization }
42
Added:
MFTSetsDialog >> initialize [
43
Added:
44
Added:
super initialize.
45
Added:
sets := OrderedCollection new
46
Added:
]
47
Added:
48
Added:
{ #category : #rendering }
49
Added:
MFTSetsDialog >> renderAddSetButtonsOn: html [
50
Added:
51
Added:
html buttonGroup: [
52
Added:
html outlineButton
53
Added:
bePrimary;
54
Added:
beSmall;
55
Added:
callback: [ self addSet ];
56
Added:
with: 'Add set'.
57
Added:
html outlineButton
58
Added:
beSecondary;
59
Added:
beSmall;
60
Added:
callback: [ self addSuperset ];
61
Added:
with: 'Add superset' ]
62
Added:
]
63
Added:
64
Added:
{ #category : #rendering }
65
Added:
MFTSetsDialog >> renderContentOn: html [
66
Added:
67
Added:
self renderDialogOn: html with: [
68
Added:
sets ifNotEmpty: [ self renderSetsTableOn: html ].
69
Added:
self renderAddSetButtonsOn: html ]
70
Added:
]
71
Added:
72
Added:
{ #category : #rendering }
73
Added:
MFTSetsDialog >> renderLoad [
74
Added:
75
Added:
^ sets anySatisfy: #hasLoad
76
Added:
]
77
Added:
78
Added:
{ #category : #rendering }
79
Added:
MFTSetsDialog >> renderRestAfter [
80
Added:
81
Added:
^ sets anySatisfy: #hasRestAfter
82
Added:
]
83
Added:
84
Added:
{ #category : #rendering }
85
Added:
MFTSetsDialog >> renderRpe [
86
Added:
87
Added:
^ sets anySatisfy: #hasRpe
88
Added:
]
89
Added:
90
Added:
{ #category : #rendering }
91
Added:
MFTSetsDialog >> renderSetsRowsOn: html [
92
Added:
93
Added:
| renderLoad renderRpe renderRestAfter |
94
Added:
renderLoad := self renderLoad.
95
Added:
renderRpe := self renderRpe.
96
Added:
renderRestAfter := self renderRestAfter.
97
Added:
sets do: [ :set |
98
Added:
html tableRow: [
99
Added:
html tableData: [
100
Added:
html buttonGroup: [
101
Added:
html outlineButton
102
Added:
beDanger;
103
Added:
beSmall;
104
Added:
callback: [ sets remove: set ];
105
Added:
with: 'Remove'.
106
Added:
html outlineButton
107
Added:
beSecondary;
108
Added:
beSmall;
109
Added:
callback: [ sets add: set afterIndex: (sets indexOf: set) ];
110
Added:
with: 'Duplicate' ].
111
Added:
html text: set setNumber asString , ' ' , set setGroup asString ].
112
Added:
html tableData: set exercise englishName.
113
Added:
html tableData: set reps.
114
Added:
renderLoad ifTrue: [ html tableData: set load ].
115
Added:
renderRpe ifTrue: [ html tableData: set rpe ].
116
Added:
renderRestAfter ifTrue: [ html tableData: set restAfter ] ] ]
117
Added:
]
118
Added:
119
Added:
{ #category : #rendering }
120
Added:
MFTSetsDialog >> renderSetsTableHeaderOn: html [
121
Added:
122
Added:
html tableHead: [
123
Added:
html
124
Added:
tableHeading;
125
Added:
tableHeading: 'Exercise';
126
Added:
tableHeading: 'Reps'.
127
Added:
self renderLoad ifTrue: [ html tableHeading: 'Load' ].
128
Added:
self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
129
Added:
self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
130
Added:
]
131
Added:
132
Added:
{ #category : #rendering }
133
Added:
MFTSetsDialog >> renderSetsTableOn: html [
134
Added:
135
Added:
html table
136
Added:
class: 'table table-hover table-bordered';
137
Added:
with: [
138
Added:
self renderSetsTableHeaderOn: html.
139
Added:
self renderSetsRowsOn: html ]
140
Added:
]
141
Added:
142
Added:
{ #category : #rendering }
143
Added:
MFTSetsDialog >> renderSubmitOn: html [
144
Added:
145
Added:
html buttonGroup: [
146
Added:
html formButton
147
Added:
beSubmit;
148
Added:
bePrimary;
149
Added:
callback: [ self answer: sets ];
150
Added:
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
151
Added:
html formButton
152
Added:
beSubmit;
153
Added:
beSecondary;
154
Added:
callback: [ self answer: OrderedCollection new ];
155
Added:
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
156
Added:
]
157
Added:
158
Added:
{ #category : #accessing }
159
Added:
MFTSetsDialog >> sets [
160
Added:
161
Added:
^ sets
162
Added:
]
163
Added:
164
Added:
{ #category : #accessing }
165
Added:
MFTSetsDialog >> sets: anObject [
166
Added:
167
Added:
sets := anObject
168
Added:
]
src/MyFitnessTracker/MFTStringDialog.class.st
@@ -4,7 +4,7 @@
4
4
#instVars : [
5
5
'string'
6
6
],
7
Removed:
#category : #'MyFitnessTracker-Dialogs'
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
8
}
9
9
10
10
{ #category : #actions }
src/MyFitnessTracker/MFTUser.class.st
@@ -2,13 +2,15 @@
2
2
#name : #MFTUser,
3
3
#superclass : #SBSComponent,
4
4
#instVars : [
5
Added:
'id',
5
6
'username',
6
7
'passwordHash',
7
Removed:
'dateOfBirth',
8
8
'realFirstName',
9
9
'realLastName',
10
Added:
'dateOfBirth',
10
11
'isLoggedIn',
11
12
'lastLoginDateAndTime',
13
Added:
'accountRegisterDateAndTime',
12
14
'workouts',
13
15
'weights'
14
16
],
@@ -42,30 +44,32 @@
42
44
43
45
{ #category : #'instance creation' }
44
46
MFTUser class >> newFromDictionary: aDictionary [
45
Removed:
"Dictionary keys are the SQLite3 column names."
46
47
47
48
^ self new
48
Removed:
username: (aDictionary at: 'username' ifAbsent: [ String new ]);
49
Removed:
passwordHash:
50
Removed:
(aDictionary at: 'password_hash' ifAbsent: [ ByteArray new ]);
51
Removed:
dateOfBirth:
52
Removed:
(aDictionary at: 'date_of_birth' ifAbsent: [ Date new ]);
53
Removed:
realFirstName:
54
Removed:
(aDictionary at: 'real_first_name' ifAbsent: [ String new ]);
55
Removed:
realLastName:
56
Removed:
(aDictionary at: 'real_last_name' ifAbsent: [ String new ]);
49
Added:
id: (aDictionary at: 'id');
50
Added:
username: (aDictionary at: 'username');
51
Added:
passwordHash: (aDictionary at: 'password_hash');
52
Added:
realFirstName: (aDictionary at: 'real_first_name');
53
Added:
realLastName: (aDictionary at: 'real_last_name');
54
Added:
dateOfBirth: (aDictionary at: 'date_of_birth');
55
Added:
lastLoginDateAndTime: (aDictionary at: 'last_login_date_time');
56
Added:
accountRegisterDateAndTime:
57
Added:
(aDictionary at: 'account_register_date_time');
57
58
yourself
58
59
]
59
60
60
Removed:
{ #category : #'instance creation' }
61
Removed:
MFTUser class >> newFromID: id [
61
Added:
{ #category : #accessing }
62
Added:
MFTUser >> accountRegisterDateAndTime [
62
63
63
Removed:
^ self
64
Removed:
newFromDictionary:
65
Removed:
(MFTSQLite3Database selectUser: id) asDictionary;
66
Removed:
yourself
64
Added:
^ accountRegisterDateAndTime
67
65
]
68
66
67
Added:
{ #category : #accessing }
68
Added:
MFTUser >> accountRegisterDateAndTime: anObject [
69
Added:
70
Added:
accountRegisterDateAndTime := anObject
71
Added:
]
72
Added:
69
73
{ #category : #'as yet unclassified' }
70
74
MFTUser >> dataDictionary [
71
75
@@ -87,6 +91,18 @@
87
91
MFTUser >> dateOfBirth: aDate [
88
92
89
93
dateOfBirth := aDate
94
Added:
]
95
Added:
96
Added:
{ #category : #accessing }
97
Added:
MFTUser >> id [
98
Added:
99
Added:
^ id
100
Added:
]
101
Added:
102
Added:
{ #category : #accessing }
103
Added:
MFTUser >> id: anObject [
104
Added:
105
Added:
id := anObject
90
106
]
91
107
92
108
{ #category : #initialization }
src/MyFitnessTracker/MFTUserTask.class.st
@@ -5,7 +5,7 @@
5
5
'user',
6
6
'action'
7
7
],
8
Removed:
#category : #'MyFitnessTracker-Dialogs'
8
Added:
#category : #'MyFitnessTracker-Dialog'
9
9
}
10
10
11
11
{ #category : #actions }
src/MyFitnessTracker/MFTWeight.class.st
@@ -2,6 +2,8 @@
2
2
#name : #MFTWeight,
3
3
#superclass : #Object,
4
4
#instVars : [
5
Added:
'id',
6
Added:
'userId',
5
7
'date',
6
8
'value'
7
9
],
@@ -72,19 +74,41 @@
72
74
date := aDate
73
75
]
74
76
77
Added:
{ #category : #accessing }
78
Added:
MFTWeight >> id [
79
Added:
80
Added:
^ id
81
Added:
]
82
Added:
83
Added:
{ #category : #accessing }
84
Added:
MFTWeight >> id: anObject [
85
Added:
86
Added:
id := anObject
87
Added:
]
88
Added:
75
89
{ #category : #initialization }
76
90
MFTWeight >> initialize [
77
91
78
92
super initialize.
79
Removed:
date := Date today.
80
Removed:
value := 0
81
Removed:
"Default value should really be the user's most recently recorded weight's value..."
93
Added:
date := Date today
82
94
]
83
95
96
Added:
{ #category : #accessing }
97
Added:
MFTWeight >> userId [
98
Added:
99
Added:
^ userId
100
Added:
]
101
Added:
102
Added:
{ #category : #accessing }
103
Added:
MFTWeight >> userId: anObject [
104
Added:
105
Added:
userId := anObject
106
Added:
]
107
Added:
84
108
{ #category : #evaluating }
85
109
MFTWeight >> value [
86
110
87
Removed:
^ value asNumber
111
Added:
^ value
88
112
]
89
113
90
114
{ #category : #accessing }
src/MyFitnessTracker/MFTWeightDialog.class.st
@@ -4,7 +4,7 @@
4
4
#instVars : [
5
5
'weight'
6
6
],
7
Removed:
#category : #'MyFitnessTracker-Dialogs'
7
Added:
#category : #'MyFitnessTracker-Dialog'
8
8
}
9
9
10
10
{ #category : #actions }
@@ -39,7 +39,8 @@
39
39
ifTrue: [ nil ]
40
40
ifFalse: [ weight value ]);
41
41
placeholder: weight value;
42
Removed:
callback: [ :value | weight value: value ] ] ]
42
Added:
callback: [ :value |
43
Added:
value ifNotEmpty: [ weight value: value asNumber ] ] ] ]
43
44
]
44
45
45
46
{ #category : #rendering }
@@ -49,12 +50,13 @@
49
50
html formButton
50
51
beSubmit;
51
52
bePrimary;
52
Removed:
callback: [ self answer: weight ];
53
Added:
callback: [
54
Added:
self answer: (weight value ifNotNil: [ weight ] ifNil: [ nil ]) ];
53
55
with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
54
56
html formButton
55
57
beSubmit;
56
58
beSecondary;
57
Removed:
callback: [ self answer: MFTWeight new ];
59
Added:
callback: [ self answer: nil ];
58
60
with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
59
61
]
60
62
src/MyFitnessTracker/MFTWeightsListPage.class.st
@@ -12,9 +12,10 @@
12
12
13
13
| newWeight |
14
14
newWeight := self call: MFTWeightDialog new.
15
Added:
newWeight ifNil: [ ^ self ].
15
16
(weights anySatisfy: [ :existingWeight |
16
Removed:
newWeight date = existingWeight date and: [
17
Removed:
newWeight value = existingWeight value ] ]) ifTrue: [ ^ self ].
17
Added:
existingWeight date = newWeight date and: [
18
Added:
existingWeight value = newWeight value ] ]) ifTrue: [ ^ self ].
18
19
19
20
self session user isLoggedIn
20
21
ifTrue: [ self session db insert: newWeight ]
src/MyFitnessTracker/MFTWorkout.class.st
@@ -2,132 +2,73 @@
2
2
#name : #MFTWorkout,
3
3
#superclass : #SBSComponent,
4
4
#instVars : [
5
Added:
'id',
6
Added:
'userId',
5
7
'date',
6
Removed:
'exercises',
7
Removed:
'primaryMuscle',
8
Removed:
'secondaryMuscles'
8
Added:
'primaryMuscleGroupId',
9
Added:
'secondaryMuscleGroupIds',
10
Added:
'sets'
9
11
],
10
12
#category : #'MyFitnessTracker-Model'
11
13
}
12
14
13
Removed:
{ #category : #'as yet unclassified' }
14
Removed:
MFTWorkout class >> allAthletes [
15
Removed:
16
Removed:
^ { #'Arnold Alois Schwarzenneger'. #'Michael John Mentzer'.
17
Removed:
#'Thomas Steven Platz' }
18
Removed:
]
19
Removed:
20
15
{ #category : #'instance creation' }
21
16
MFTWorkout class >> newFromDictionary: aDictionary [
22
17
23
Removed:
| primaryMuscleConstructor primaryMuscle secondaryMusclesContructors secondaryMuscles |
24
Removed:
primaryMuscleConstructor := (aDictionary
25
Removed:
at: 'primary_muscle'
26
Removed:
ifAbsent: [ String new ]) asSymbol.
27
Removed:
primaryMuscle := (MFTMuscleGroup respondsTo: primaryMuscleConstructor)
28
Removed:
ifTrue: [
29
Removed:
MFTMuscleGroup perform: primaryMuscleConstructor ]
30
Removed:
ifFalse: [ MFTMuscleGroup new ].
31
Removed:
secondaryMusclesContructors := ((aDictionary
32
Removed:
at: 'secondary_muscles'
33
Removed:
ifAbsent: [ String new ]) splitOn:
34
Removed:
', ') collect: #asSymbol.
35
Removed:
secondaryMusclesContructors removeAllSuchThat: [ :each | each = #'' ].
36
Removed:
secondaryMuscles := secondaryMusclesContructors collect: [ :symbol |
37
Removed:
(MFTMuscleGroup respondsTo: symbol)
38
Removed:
ifTrue: [ MFTMuscleGroup perform: symbol ]
39
Removed:
ifFalse: [ nil ] ].
40
Removed:
41
18
^ self new
19
Added:
id: (aDictionary at: 'id');
20
Added:
userId: (aDictionary at: 'user_id');
42
21
date: (Date fromString: (aDictionary at: 'date'));
43
Removed:
primaryMuscle: primaryMuscle;
44
Removed:
secondaryMuscles: secondaryMuscles;
22
Added:
primaryMuscleGroupId: (aDictionary at: 'primary_muscle_group_id');
45
23
yourself
46
24
]
47
25
48
26
{ #category : #'as yet unclassified' }
49
27
MFTWorkout class >> placeholderCollection [
50
28
51
Removed:
| workout1 workout2 workout3 workout4 workout5 |
29
Added:
| allMuscleGroups allExercises placeholderSets workout1 workout2 workout3 |
30
Added:
allMuscleGroups := MFTSQLite3Database allMuscleGroupsAsDict.
31
Added:
allExercises := MFTSQLite3Database allExercisesAsDict.
32
Added:
placeholderSets := MFTSet placeholderCollection.
52
33
workout1 := self new
53
Removed:
date: (Date fromString: '01/01/2024');
54
Removed:
primaryMuscle: MFTMuscleGroup chest;
55
Removed:
secondaryMuscles: {
56
Removed:
MFTMuscle tricepsBrachii.
57
Removed:
MFTMuscleGroup arm };
58
Removed:
exercises: {
59
Removed:
(MFTExercise cableRow sets: {
60
Removed:
(MFTSet reps: 8 weight: 20 rpe: 6).
61
Removed:
(MFTSet reps: 6 weight: 20 rpe: 8).
62
Removed:
(MFTSet reps: 6 weight: 20 rpe: 10).
63
Removed:
(MFTSet reps: 15 rpe: 4) }).
64
Removed:
(MFTExercise shoulderPressDumbell sets: {
65
Removed:
(MFTSet reps: 10 weight: 10 rpe: 6).
66
Removed:
(MFTSet reps: 6 weight: 15 rpe: 8).
67
Removed:
(MFTSet reps: 6 weight: 17.5 rpe: 10) }).
68
Removed:
(MFTExercise declineBenchPress sets: {
69
Removed:
(MFTSet reps: 5 rpe: 6).
70
Removed:
(MFTSet reps: 6 rpe: 8).
71
Removed:
(MFTSet reps: 8 rpe: 10) }) }.
34
Added:
id: 1;
35
Added:
userId: 1;
36
Added:
date: (Date fromString: '2024-01-01');
37
Added:
primaryMuscleGroupId: 4;
38
Added:
sets:
39
Added:
(placeholderSets select: [ :set | set workoutId = 1 ]).
72
40
workout2 := self new
73
Removed:
date: (Date fromString: '01/02/2024');
74
Removed:
exercises: {
75
Removed:
(MFTExercise cableRow sets: {
76
Removed:
(MFTSet reps: 8 rpe: 6).
77
Removed:
(MFTSet reps: 6 rpe: 8).
78
Removed:
(MFTSet reps: 6 rpe: 10).
79
Removed:
(MFTSet reps: 15 rpe: 4) }).
80
Removed:
MFTExercise shoulderPressDumbell.
81
Removed:
MFTExercise declineBenchPress }.
41
Added:
id: 2;
42
Added:
userId: 1;
43
Added:
date: (Date fromString: '2024-01-02');
44
Added:
primaryMuscleGroupId: 5;
45
Added:
sets:
46
Added:
(placeholderSets select: [ :set | set workoutId = 2 ]).
82
47
workout3 := self new
83
Removed:
date: (Date fromString: '01/03/2024');
84
Removed:
addExercise: MFTExercise cableRow;
85
Removed:
addExercise: MFTExercise shoulderPressDumbell;
86
Removed:
addExercise: MFTExercise declineBenchPress.
87
Removed:
workout4 := self new
88
Removed:
date: (Date fromString: '01/09/2024');
89
Removed:
exercises: {
90
Removed:
MFTExercise cableRow.
91
Removed:
MFTExercise shoulderPressDumbell.
92
Removed:
MFTExercise declineBenchPress }.
93
Removed:
workout5 := self new
94
Removed:
date: (Date fromString: '01/10/2024');
95
Removed:
exercises: {
96
Removed:
MFTExercise cableRow.
97
Removed:
MFTExercise shoulderPressDumbell.
98
Removed:
MFTExercise declineBenchPress }.
99
Removed:
48
Added:
id: 3;
49
Added:
userId: 1;
50
Added:
date: (Date fromString: '2024-01-03');
51
Added:
primaryMuscleGroupId: 6;
52
Added:
sets:
53
Added:
(placeholderSets select: [ :set | set workoutId = 3 ]).
100
54
^ OrderedCollection withAll: {
101
55
workout1.
102
56
workout2.
103
Removed:
workout3.
104
Removed:
workout4.
105
Removed:
workout5 }
57
Added:
workout3 }
106
58
]
107
59
108
Removed:
{ #category : #accessing }
109
Removed:
MFTWorkout class >> primaryMuscle: aMFTMuscle [
60
Added:
{ #category : #'as yet unclassified' }
61
Added:
MFTWorkout >> anySetHasLoad [
110
62
111
Removed:
^ self new
112
Removed:
primaryMuscle: aMFTMuscle;
113
Removed:
yourself
63
Added:
^ sets anySatisfy: #hasLoad
114
64
]
115
65
116
Removed:
{ #category : #accessing }
117
Removed:
MFTWorkout class >> primaryMuscle: aMFTMuscle secondaryMuscles: aMFTMuscleCollection [
66
Added:
{ #category : #'as yet unclassified' }
67
Added:
MFTWorkout >> anySetHasVolume [
118
68
119
Removed:
^ self new
120
Removed:
primaryMuscle: aMFTMuscle;
121
Removed:
secondaryMuscles: aMFTMuscleCollection;
122
Removed:
yourself
69
Added:
^ sets anySatisfy: #hasVolume
123
70
]
124
71
125
Removed:
{ #category : #initialization }
126
Removed:
MFTWorkout >> addExercise: aMFTExercise [
127
Removed:
128
Removed:
exercises add: aMFTExercise
129
Removed:
]
130
Removed:
131
72
{ #category : #accessing }
132
73
MFTWorkout >> date [
133
74
^ date
@@ -138,18 +79,6 @@
138
79
date := aDate
139
80
]
140
81
141
Removed:
{ #category : #accessing }
142
Removed:
MFTWorkout >> exercises [
143
Removed:
144
Removed:
^ exercises
145
Removed:
]
146
Removed:
147
Removed:
{ #category : #accessing }
148
Removed:
MFTWorkout >> exercises: aMFTExerciseCollection [
149
Removed:
150
Removed:
exercises := aMFTExerciseCollection asOrderedCollection
151
Removed:
]
152
Removed:
153
82
{ #category : #'as yet unclassified' }
154
83
MFTWorkout >> guessPrimaryMuscle [
155
84
"TODO: guess the workout's primary muscle based on the most represented primary muscle in the workout's exercises."
@@ -161,28 +90,47 @@
161
90
(groupedByMuscle at: muscle) size ]
162
91
]
163
92
93
Added:
{ #category : #accessing }
94
Added:
MFTWorkout >> id [
95
Added:
96
Added:
^ id
97
Added:
]
98
Added:
99
Added:
{ #category : #accessing }
100
Added:
MFTWorkout >> id: anObject [
101
Added:
102
Added:
id := anObject
103
Added:
]
104
Added:
164
105
{ #category : #initialization }
165
106
MFTWorkout >> initialize [
166
107
167
108
super initialize.
168
109
date := Date today.
169
Removed:
exercises := OrderedCollection new.
170
Removed:
primaryMuscle := MFTMuscle new.
171
Removed:
secondaryMuscles := OrderedCollection new
110
Added:
sets := OrderedCollection new.
111
Added:
secondaryMuscleGroupIds := OrderedCollection new
172
112
]
173
113
174
114
{ #category : #accessing }
175
Removed:
MFTWorkout >> primaryMuscle [
115
Added:
MFTWorkout >> primaryMuscleGroup [
176
116
177
Removed:
^ primaryMuscle
117
Added:
^ MFTSQLite3Database allMuscleGroups
118
Added:
detect: [ :group | group id = primaryMuscleGroupId ]
119
Added:
ifNone: [ nil ]
178
120
]
179
121
180
122
{ #category : #accessing }
181
Removed:
MFTWorkout >> primaryMuscle: aMFTMuscle [
123
Added:
MFTWorkout >> primaryMuscleGroupId [
182
124
183
Removed:
primaryMuscle := aMFTMuscle
125
Added:
^ primaryMuscleGroupId
184
126
]
185
127
128
Added:
{ #category : #accessing }
129
Added:
MFTWorkout >> primaryMuscleGroupId: anInteger [
130
Added:
131
Added:
primaryMuscleGroupId := anInteger
132
Added:
]
133
Added:
186
134
{ #category : #rendering }
187
135
MFTWorkout >> renderContentOn: html [
188
136
@@ -190,31 +138,31 @@
190
138
html
191
139
definitionTerm: 'Date';
192
140
definitionData: date.
193
Removed:
primaryMuscle englishName ifNotEmpty: [
141
Added:
self primaryMuscleGroup ifNotNil: [
194
142
html
195
Removed:
definitionTerm: 'Primary Muscle';
196
Removed:
definitionData: primaryMuscle englishName ].
197
Removed:
secondaryMuscles ifNotEmpty: [
143
Added:
definitionTerm: 'Primary Muscle Group';
144
Added:
definitionData: self primaryMuscleGroup englishName ].
145
Added:
self secondaryMuscleGroups ifNotEmpty: [
198
146
html
199
Removed:
definitionTerm: 'Secondary Muscles';
147
Added:
definitionTerm: 'Secondary Muscle Group';
200
148
definitionData:
201
Removed:
(secondaryMuscles collect: #englishName) asCommaString ] ].
202
Removed:
exercises ifNotEmpty: [ self renderExerciseTableOn: html ]
149
Added:
(self secondaryMuscleGroups collect: #englishName) asCommaString ] ].
150
Added:
sets ifNotEmpty: [ self renderSetsTableOn: html ]
203
151
]
204
152
205
153
{ #category : #rendering }
206
Removed:
MFTWorkout >> renderExerciseTableFooterOn: html [
154
Added:
MFTWorkout >> renderSetsTableFooterOn: html [
207
155
208
156
| totalReps totalVolume |
209
Removed:
totalReps := (exercises collect: [ :exercise |
210
Removed:
exercise repsBySet sum ]) sum.
211
Removed:
totalVolume := (exercises collect: #volume) sum.
212
Removed:
157
Added:
totalReps := (sets collect: #reps) sum.
158
Added:
totalVolume := (sets collect: #volume) sum.
213
159
html tableFoot: [
160
Added:
html tableData.
214
161
html tableData: 'Total'.
215
162
html tableData
216
163
style: 'text-align: right';
217
164
with: totalReps.
165
Added:
self anySetHasLoad ifTrue: [ html tableData ].
218
166
totalVolume ~~ 0 ifTrue: [
219
167
html tableData
220
168
style: 'text-align: right';
@@ -222,61 +170,106 @@
222
170
]
223
171
224
172
{ #category : #rendering }
225
Removed:
MFTWorkout >> renderExerciseTableOn: html [
173
Added:
MFTWorkout >> renderSetsTableHeaderOn: html [
226
174
227
Removed:
| anExerciseHasVolume |
228
Removed:
anExerciseHasVolume := exercises anySatisfy: [ :ex | ex volume ~~ 0 ].
175
Added:
html tableHead: [
176
Added:
html tableHeading.
177
Added:
html tableHeading: 'Exercise'.
178
Added:
html tableHeading
179
Added:
style: 'text-align: right';
180
Added:
with: 'Reps'.
181
Added:
self anySetHasLoad ifTrue: [
182
Added:
html tableHeading
183
Added:
style: 'text-align: right';
184
Added:
with: 'Load' ].
185
Added:
self anySetHasVolume ifTrue: [
186
Added:
html tableHeading
187
Added:
style: 'text-align: right';
188
Added:
with: 'Volume' ] ]
189
Added:
]
190
Added:
191
Added:
{ #category : #rendering }
192
Added:
MFTWorkout >> renderSetsTableOn: html [
193
Added:
194
Added:
| renderLoad renderVolume |
195
Added:
renderLoad := self anySetHasLoad.
196
Added:
renderVolume := self anySetHasVolume.
197
Added:
229
198
html table
230
199
class: 'table table-striped table-bordered';
231
200
with: [
232
Removed:
self renderTableHeaderOn: html.
233
Removed:
exercises do: [ :exercise |
201
Added:
self renderSetsTableHeaderOn: html.
202
Added:
sets do: [ :set |
234
203
html tableRow: [
235
Removed:
html tableData: [
236
Removed:
html text: exercise englishName.
237
Removed:
exercise sets ifNotEmpty: [
238
Removed:
html
239
Removed:
text: ': ';
240
Removed:
text: exercise repsBySet asCommaString ] ].
241
204
html tableData
242
205
style: 'text-align: right';
243
Removed:
with: exercise repsBySet sum.
244
Removed:
anExerciseHasVolume ifTrue: [
206
Added:
with: set setNumber asString, ' ', set setGroup asString.
207
Added:
html tableData: set exercise englishName capitalized.
208
Added:
html tableData
209
Added:
style: 'text-align: right';
210
Added:
with: set reps.
211
Added:
renderLoad ifTrue: [
245
212
html tableData
246
213
style: 'text-align: right';
247
Removed:
with: exercise volume ] ] ].
248
Removed:
self renderExerciseTableFooterOn: html ]
214
Added:
with: set load ].
215
Added:
renderVolume ifTrue: [
216
Added:
html tableData
217
Added:
style: 'text-align: right';
218
Added:
with: set volume ] ] ].
219
Added:
self renderSetsTableFooterOn: html ]
249
220
]
250
221
251
Removed:
{ #category : #rendering }
252
Removed:
MFTWorkout >> renderTableHeaderOn: html [
222
Added:
{ #category : #accessing }
223
Added:
MFTWorkout >> secondaryMuscleGroupIds [
253
224
254
Removed:
html tableHead: [
255
Removed:
html tableHeading: 'Exercise'.
256
Removed:
html tableHeading
257
Removed:
style: 'text-align: right';
258
Removed:
with: 'Reps'.
259
Removed:
(exercises anySatisfy: [ :exercise | exercise volume ~~ 0 ])
260
Removed:
ifTrue: [
261
Removed:
html tableHeading
262
Removed:
style: 'text-align: right';
263
Removed:
with: 'Volume' ] ]
225
Added:
^ secondaryMuscleGroupIds
264
226
]
265
227
266
228
{ #category : #accessing }
267
Removed:
MFTWorkout >> secondaryMuscles [
229
Added:
MFTWorkout >> secondaryMuscleGroupIds: anIntegerCollection [
268
230
269
Removed:
^ secondaryMuscles
231
Added:
secondaryMuscleGroupIds := anIntegerCollection
270
232
]
271
233
234
Added:
{ #category : #'as yet unclassified' }
235
Added:
MFTWorkout >> secondaryMuscleGroups [
236
Added:
237
Added:
^ MFTSQLite3Database allMuscleGroups select: [ :group |
238
Added:
secondaryMuscleGroupIds includes: group id ]
239
Added:
]
240
Added:
272
241
{ #category : #accessing }
273
Removed:
MFTWorkout >> secondaryMuscles: aMFTMuscleCollection [
242
Added:
MFTWorkout >> setGroups [
274
243
275
Removed:
secondaryMuscles := aMFTMuscleCollection asOrderedCollection
244
Added:
^ sets groupedBy: #setGroup
276
245
]
277
246
247
Added:
{ #category : #accessing }
248
Added:
MFTWorkout >> sets [
249
Added:
250
Added:
^ sets
251
Added:
]
252
Added:
253
Added:
{ #category : #accessing }
254
Added:
MFTWorkout >> sets: anObject [
255
Added:
256
Added:
sets := anObject
257
Added:
]
258
Added:
259
Added:
{ #category : #accessing }
260
Added:
MFTWorkout >> userId [
261
Added:
262
Added:
^ userId
263
Added:
]
264
Added:
265
Added:
{ #category : #accessing }
266
Added:
MFTWorkout >> userId: anObject [
267
Added:
268
Added:
userId := anObject
269
Added:
]
270
Added:
278
271
{ #category : #'as yet unclassified' }
279
272
MFTWorkout >> volume [
280
273
281
Removed:
^ (exercises collect: #volume) sum
274
Added:
^ (sets collect: #volume) sum
282
275
]
src/MyFitnessTracker/MFTWorkoutTask.class.st
@@ -5,7 +5,7 @@
5
5
'workout',
6
6
'action'
7
7
],
8
Removed:
#category : #'MyFitnessTracker-Dialogs'
8
Added:
#category : #'MyFitnessTracker-Dialog'
9
9
}
10
10
11
11
{ #category : #actions }
@@ -32,22 +32,30 @@
32
32
{ #category : #running }
33
33
MFTWorkoutTask >> go [
34
34
35
Added:
| primaryMuscleGroup secondaryMuscleGroups |
36
Added:
workout userId: self session user id.
35
37
workout date: (self call: (MFTDateDialog new
36
38
action: action;
37
39
date: workout date;
38
40
completion: 20)).
39
Removed:
workout exercises: (self call: (MFTExercisesDialog new
41
Added:
workout sets: (self call: (MFTSetsDialog new
40
42
action: action;
41
Removed:
exercises: workout exercises;
43
Added:
sets: workout sets;
42
44
completion: 40)).
43
Removed:
workout primaryMuscle: (self call: (MFTPrimaryMuscleDialog new
44
Removed:
action: action;
45
Removed:
primaryMuscle: workout primaryMuscle;
46
Removed:
completion: 60)).
47
Removed:
workout secondaryMuscles: (self call: (MFTSecondaryMusclesDialog new
48
Removed:
action: action;
49
Removed:
secondaryMuscles: workout secondaryMuscles;
50
Removed:
completion: 80)).
45
Added:
primaryMuscleGroup := self call: (MFTPrimaryMuscleGroupDialog new
46
Added:
action: action;
47
Added:
primaryMuscleGroup:
48
Added:
workout primaryMuscleGroup;
49
Added:
completion: 60).
50
Added:
primaryMuscleGroup ifNotNil: [
51
Added:
workout primaryMuscleGroupId: primaryMuscleGroup id ].
52
Added:
secondaryMuscleGroups := self call:
53
Added:
(MFTSecondaryMuscleGroupsDialog new
54
Added:
action: action;
55
Added:
secondaryMuscleGroups:
56
Added:
workout secondaryMuscleGroups;
57
Added:
completion: 80).
58
Added:
workout secondaryMuscleGroupIds: (secondaryMuscleGroups collect: #id).
51
59
52
60
(self call: (MFTConfirmDialog new
53
61
action: action;
src/MyFitnessTracker/MFTWorkoutsListPage.class.st
@@ -148,11 +148,11 @@
148
148
with: [
149
149
html text:
150
150
workout date yyyymmdd , ', ' , workout date dayOfWeekName.
151
Removed:
workout primaryMuscle englishName ifNotEmpty: [
151
Added:
workout primaryMuscleGroup ifNotNil: [
152
152
html
153
153
text: ':';
154
154
space;
155
Removed:
emphasis: workout primaryMuscle englishName ] ] ].
155
Added:
emphasis: workout primaryMuscleGroup englishName ] ] ].
156
156
html accordionCollapse
157
157
id: 'collapse' , i asString;
158
158
class: 'collapse';