Promote components to package.

Commit
615f717da8fa5689e019058878bad2644d19b4e2
Author
Marius Peter <marius.peter@tutanota.com>
Author date
Committer
Marius Peter <marius.peter@tutanota.com>
Committer date
Changed files
src/MyFitnessTracker-Components/MFTAboutPage.class.st
index 00000000..95172b24 000000..100644
@@ -0,0 +1,87 @@
1 Added: Class {
2 Added: #name : 'MFTAboutPage',
3 Added: #superclass : 'MFTPage',
4 Added: #category : 'MyFitnessTracker-Components-Pages',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Pages'
7 Added: }
8 Added:
9 Added: { #category : 'initialization' }
10 Added: MFTAboutPage >> initialize [
11 Added:
12 Added: super initialize.
13 Added: title := 'about'
14 Added: ]
15 Added:
16 Added: { #category : 'rendering' }
17 Added: MFTAboutPage >> renderBackgroundOn: html [
18 Added:
19 Added: html heading level1 with: 'Background'.
20 Added: html heading level2 with: 'Why I built this web app'.
21 Added: html
22 Added: paragraph:
23 Added: 'I wanted a convenient way to record, perform data analysis, and create visualizations for my workouts.';
24 Added: paragraph:
25 Added: 'The following features were, and still are, essential for me:';
26 Added: unorderedList: [
27 Added: html
28 Added: listItem: 'Free access to all app features,';
29 Added: listItem: 'Easy import and export of my training data,';
30 Added: listItem:
31 Added: 'An extensible interface to suit a wide range of training routines.' ];
32 Added: paragraph:
33 Added: 'What better way than to build my own Personal Fitness Tracker?!'.
34 Added: html heading level2 with: 'Who I am'.
35 Added: html paragraph:
36 Added: 'I am an engineer working in Europe, with a deep passion for health and fitness. Publishing My Fitness Tracker is a way for me to give thanks to everyone who has inspired me throughtout my fitness journey.'
37 Added: ]
38 Added:
39 Added: { #category : 'rendering' }
40 Added: MFTAboutPage >> renderCatchOn: html [
41 Added:
42 Added: html heading level1 dangerText with: 'The catch'.
43 Added: html
44 Added: paragraph:
45 Added: 'I''ve made some debatable compromises when it comes to My Fitness Tracker:';
46 Added: unorderedList: [
47 Added: html
48 Added: listItem: 'No external advertisement,';
49 Added: listItem:
50 Added: 'No cookies or personally identifying information stored,';
51 Added: listItem:
52 Added: 'No paid feature, except for the storage of your training data beyond ten workouts.' ];
53 Added: paragraph:
54 Added: 'I know these design choices might frustrate and maybe even anger certain users; '
55 Added: ,
56 Added: 'thankfully, all previously existing fitness tracking services do not abide by these design principles.';
57 Added: paragraph:
58 Added: 'I am developing My Fitness Tracker for my own personal use case, first and foremost; '
59 Added: ,
60 Added: 'secondly, for the benefit of as many other fitness enthusiasts as possible; '
61 Added: ,
62 Added: 'thirdly, for the enjoyment that developing this web application brings me. '
63 Added: ,
64 Added: 'The paid feature enables me to increase the amount of fitness enthusiasts I can cater to.'
65 Added: ]
66 Added:
67 Added: { #category : 'rendering' }
68 Added: MFTAboutPage >> renderContentOn: html [
69 Added:
70 Added: self renderPageOn: html with: [
71 Added: self renderVisionOn: html.
72 Added: self renderBackgroundOn: html.
73 Added: self renderCatchOn: html ]
74 Added: ]
75 Added:
76 Added: { #category : 'rendering' }
77 Added: MFTAboutPage >> renderVisionOn: html [
78 Added:
79 Added: html heading level1 with: 'The Vision'.
80 Added: html paragraph: [
81 Added: html text: 'Free, and eventually '.
82 Added: html anchor
83 Added: url: 'https://fsfe.org/index.en.html';
84 Added: with: 'libre'.
85 Added: html text:
86 Added: ' fitness tracking for all to enjoy. No user data tracking and reselling; no features blocked for any reason.' ]
87 Added: ]
src/MyFitnessTracker-Components/MFTActionsCard.class.st
index 00000000..55b4e816 000000..100644
@@ -0,0 +1,18 @@
1 Added: Class {
2 Added: #name : 'MFTActionsCard',
3 Added: #superclass : 'MFTCard',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'rendering' }
10 Added: MFTActionsCard >> renderContentOn: html [
11 Added:
12 Added: self renderCardOn: html with: [
13 Added: html form: [
14 Added: html formButton
15 Added: formControl;
16 Added: callback: [ MFTWorkoutTask new ];
17 Added: with: 'Log Workout' ] ]
18 Added: ]
src/MyFitnessTracker-Components/MFTAnalyticsPage.class.st
index 00000000..e444af04 000000..100644
@@ -0,0 +1,70 @@
1 Added: Class {
2 Added: #name : 'MFTAnalyticsPage',
3 Added: #superclass : 'MFTPage',
4 Added: #instVars : [
5 Added: 'type'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Pages',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Pages'
10 Added: }
11 Added:
12 Added: { #category : 'instance creation' }
13 Added: MFTAnalyticsPage class >> for: aSymbol [
14 Added:
15 Added: ^ self new
16 Added: type: aSymbol;
17 Added: yourself
18 Added: ]
19 Added:
20 Added: { #category : 'accessing' }
21 Added: MFTAnalyticsPage >> analytics [
22 Added:
23 Added: ^ Dictionary newFrom: {
24 Added: (#workouts -> {
25 Added: MFTRepsDistributionGraph new.
26 Added: MFTWorkoutVolumeVsTimeGraph new
27 Added: "MFTWorkoutVolumePerWeekGraph new" }).
28 Added: (#weights -> { MFTWeightVsTimeGraph new }) }
29 Added: ]
30 Added:
31 Added: { #category : 'rendering' }
32 Added: MFTAnalyticsPage >> renderActionsButtonGroupOn: html [
33 Added:
34 Added: html form class: 'my-3'; with: [
35 Added: html buttonGroup: [
36 Added: html formButton
37 Added: bePrimary;
38 Added: callback: [ self answer ];
39 Added: with: 'Return' ] ]
40 Added: ]
41 Added:
42 Added: { #category : 'rendering' }
43 Added: MFTAnalyticsPage >> renderContentOn: html [
44 Added:
45 Added: | components |
46 Added: components := self analytics at: type.
47 Added:
48 Added: self renderPageOn: html with: [
49 Added: self renderActionsButtonGroupOn: html.
50 Added: html div
51 Added: style:
52 Added: 'display: flex; flex-wrap: wrap; justify-content: space-around; gap: 1em';
53 Added: with: [
54 Added: components do: [ :each |
55 Added: html card: [
56 Added: html cardHeader: each title.
57 Added: html render: each ] ] ] ]
58 Added: ]
59 Added:
60 Added: { #category : 'accessing' }
61 Added: MFTAnalyticsPage >> type [
62 Added:
63 Added: ^ type
64 Added: ]
65 Added:
66 Added: { #category : 'accessing' }
67 Added: MFTAnalyticsPage >> type: anObject [
68 Added:
69 Added: type := anObject
70 Added: ]
src/MyFitnessTracker-Components/MFTArticle.class.st
index 00000000..30882210 000000..100644
@@ -0,0 +1,28 @@
1 Added: Class {
2 Added: #name : 'MFTArticle',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'title'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'rendering' }
12 Added: MFTArticle >> renderArticleOn: html with: aBlock [
13 Added:
14 Added: html heading: title capitalized.
15 Added: html render: aBlock
16 Added: ]
17 Added:
18 Added: { #category : 'accessing' }
19 Added: MFTArticle >> title [
20 Added:
21 Added: ^ title
22 Added: ]
23 Added:
24 Added: { #category : 'accessing' }
25 Added: MFTArticle >> title: aString [
26 Added:
27 Added: title := aString
28 Added: ]
src/MyFitnessTracker-Components/MFTAthletesArticle.class.st
index 00000000..1d8f17ce 000000..100644
@@ -0,0 +1,25 @@
1 Added: Class {
2 Added: #name : 'MFTAthletesArticle',
3 Added: #superclass : 'MFTArticle',
4 Added: #instVars : [
5 Added: 'athletes'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'initialization' }
12 Added: MFTAthletesArticle >> initialize [
13 Added:
14 Added: super initialize.
15 Added: title := 'athletes'.
16 Added: athletes := { MFTMikeMentzer new }
17 Added: ]
18 Added:
19 Added: { #category : 'rendering' }
20 Added: MFTAthletesArticle >> renderContentOn: html [
21 Added:
22 Added: self
23 Added: renderArticleOn: html
24 Added: with: [ athletes do: [ :athlete | athlete renderContentOn: html ] ]
25 Added: ]
src/MyFitnessTracker-Components/MFTCard.class.st
index 00000000..a79b171c 000000..100644
@@ -0,0 +1,21 @@
1 Added: Class {
2 Added: #name : 'MFTCard',
3 Added: #superclass : 'MFTWidget',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'rendering' }
10 Added: MFTCard >> renderCardOn: html with: aBlock [
11 Added:
12 Added: html card: aBlock
13 Added: ]
14 Added:
15 Added: { #category : 'rendering' }
16 Added: MFTCard >> renderContentOn: html [
17 Added:
18 Added: self
19 Added: renderCardOn: html
20 Added: with: [ html cardBody: [ html paragraph: self defaultDescription ] ]
21 Added: ]
src/MyFitnessTracker-Components/MFTConfirmDialog.class.st
index 00000000..ce916f9d 000000..100644
@@ -0,0 +1,28 @@
1 Added: Class {
2 Added: #name : 'MFTConfirmDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #category : 'MyFitnessTracker-Components-Dialogs',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Dialogs'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTConfirmDialog >> heading [
11 Added:
12 Added: ^ 'You are about to {1} a {2}:' format: {
13 Added: action.
14 Added: component class }
15 Added: ]
16 Added:
17 Added: { #category : 'as yet unclassified' }
18 Added: MFTConfirmDialog >> renderContentOn: html [
19 Added:
20 Added: self renderDialogOn: html with: [
21 Added: html render: component.
22 Added: html label: [
23 Added: html text: 'Are you sure?'.
24 Added: action = #delete ifTrue: [
25 Added: html
26 Added: space;
27 Added: strong: 'This action cannot be undone.' ] ] ]
28 Added: ]
src/MyFitnessTracker-Components/MFTConfirmForm.class.st
index 00000000..07873f88 000000..100644
@@ -0,0 +1,34 @@
1 Added: Class {
2 Added: #name : 'MFTConfirmForm',
3 Added: #superclass : 'MFTForm',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'submorphs - add/remove' }
10 Added: MFTConfirmForm class >> delete [
11 Added:
12 Added: ^ self new
13 Added: modelObject: 'Confirm deletion?';
14 Added: yourself
15 Added: ]
16 Added:
17 Added: { #category : 'as yet unclassified' }
18 Added: MFTConfirmForm >> cancelForm [
19 Added:
20 Added: self answer: false
21 Added: ]
22 Added:
23 Added: { #category : 'initialization' }
24 Added: MFTConfirmForm >> initialize [
25 Added:
26 Added: super initialize .
27 Added: heading := 'Heads up!'
28 Added: ]
29 Added:
30 Added: { #category : 'as yet unclassified' }
31 Added: MFTConfirmForm >> submitForm [
32 Added:
33 Added: self answer: true
34 Added: ]
src/MyFitnessTracker-Components/MFTDateDialog.class.st
index 00000000..a2d6306f 000000..100644
@@ -0,0 +1,50 @@
1 Added: Class {
2 Added: #name : 'MFTDateDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'date'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'accessing' }
13 Added: MFTDateDialog >> date [
14 Added:
15 Added: ^ date
16 Added: ]
17 Added:
18 Added: { #category : 'accessing' }
19 Added: MFTDateDialog >> date: anObject [
20 Added:
21 Added: date := anObject
22 Added: ]
23 Added:
24 Added: { #category : 'initialization' }
25 Added: MFTDateDialog >> initialize [
26 Added:
27 Added: super initialize.
28 Added: date := Date today
29 Added: ]
30 Added:
31 Added: { #category : 'rendering' }
32 Added: MFTDateDialog >> renderContentOn: html [
33 Added:
34 Added: self renderDialogOn: html with: [
35 Added: html dateInput5 formControl
36 Added: value: date yyyymmdd;
37 Added: callback: [ :value |
38 Added: date := Date readFrom: value pattern: 'yyyy-mm-dd' ] ]
39 Added: ]
40 Added:
41 Added: { #category : 'as yet unclassified' }
42 Added: MFTDateDialog >> renderSubmitOn: html [
43 Added:
44 Added: html buttonGroup: [
45 Added: html formButton
46 Added: beSubmit;
47 Added: bePrimary;
48 Added: callback: [ self answer: date ];
49 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]) ]
50 Added: ]
src/MyFitnessTracker-Components/MFTDateFormComponent.class.st
index 00000000..c8eb264e 000000..100644
@@ -0,0 +1,24 @@
1 Added: Class {
2 Added: #name : 'MFTDateFormComponent',
3 Added: #superclass : 'MFTFormComponent',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'initialization' }
10 Added: MFTDateFormComponent >> initialize [
11 Added:
12 Added: super initialize.
13 Added: heading := 'Date'
14 Added: ]
15 Added:
16 Added: { #category : 'rendering' }
17 Added: MFTDateFormComponent >> renderContentOn: html [
18 Added:
19 Added: self renderFormComponentOn: html with: [
20 Added: html dateInput5 formControl
21 Added: value: modelObject date yyyymmdd;
22 Added: callback: [ :value |
23 Added: modelObject date: (Date readFrom: value pattern: 'yyyy-mm-dd') ] ]
24 Added: ]
src/MyFitnessTracker-Components/MFTDefaultFooter.class.st
index 00000000..5e599f2c 000000..100644
@@ -0,0 +1,18 @@
1 Added: Class {
2 Added: #name : 'MFTDefaultFooter',
3 Added: #superclass : 'MFTFooter',
4 Added: #category : 'MyFitnessTracker-Components',
5 Added: #package : 'MyFitnessTracker-Components'
6 Added: }
7 Added:
8 Added: { #category : 'rendering' }
9 Added: MFTDefaultFooter >> renderContentOn: html [
10 Added:
11 Added: self renderFooterOn: html with: [
12 Added: html paragraph: [
13 Added: html text:
14 Added: 'Copyright 2023–' , Date today year asString , ' Marius PETER '.
15 Added: html badge beSecondary with: (MFTUtils version
16 Added: ifNil: [ 'DEVELOP' ]
17 Added: ifNotNil: [ 'v' , MFTUtils version ]) ] ]
18 Added: ]
src/MyFitnessTracker-Components/MFTDialog.class.st
index 00000000..2ec20a0b 000000..100644
@@ -0,0 +1,174 @@
1 Added: Class {
2 Added: #name : 'MFTDialog',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'heading',
6 Added: 'subheading',
7 Added: 'component',
8 Added: 'action',
9 Added: 'completion'
10 Added: ],
11 Added: #category : 'MyFitnessTracker-Components-Dialogs',
12 Added: #package : 'MyFitnessTracker-Components',
13 Added: #tag : 'Dialogs'
14 Added: }
15 Added:
16 Added: { #category : 'actions' }
17 Added: MFTDialog class >> add: anObject [
18 Added:
19 Added: ^ self new
20 Added: action: #add;
21 Added: component: anObject;
22 Added: yourself
23 Added: ]
24 Added:
25 Added: { #category : 'actions' }
26 Added: MFTDialog class >> delete: anObject [
27 Added:
28 Added: ^ self new
29 Added: action: #delete;
30 Added: component: anObject;
31 Added: yourself
32 Added: ]
33 Added:
34 Added: { #category : 'actions' }
35 Added: MFTDialog class >> edit: anObject [
36 Added:
37 Added: ^ self new
38 Added: action: #edit;
39 Added: component: anObject;
40 Added: yourself
41 Added: ]
42 Added:
43 Added: { #category : 'accessing' }
44 Added: MFTDialog >> action [
45 Added:
46 Added: ^ action
47 Added: ]
48 Added:
49 Added: { #category : 'accessing' }
50 Added: MFTDialog >> action: anObject [
51 Added:
52 Added: action := anObject
53 Added: ]
54 Added:
55 Added: { #category : 'delegation' }
56 Added: MFTDialog >> answer [
57 Added:
58 Added: self answer: component
59 Added: ]
60 Added:
61 Added: { #category : 'accessing' }
62 Added: MFTDialog >> completion [
63 Added:
64 Added: ^ completion
65 Added: ]
66 Added:
67 Added: { #category : 'accessing' }
68 Added: MFTDialog >> completion: anObject [
69 Added:
70 Added: completion := anObject
71 Added: ]
72 Added:
73 Added: { #category : 'accessing' }
74 Added: MFTDialog >> component [
75 Added:
76 Added: ^ component
77 Added: ]
78 Added:
79 Added: { #category : 'accessing' }
80 Added: MFTDialog >> component: anObject [
81 Added:
82 Added: component := anObject
83 Added: ]
84 Added:
85 Added: { #category : 't - rotating' }
86 Added: MFTDialog >> heading [
87 Added:
88 Added: ^ action capitalized , ' ' , (heading ifNil: [
89 Added: ('^MFT(.*)Dialog$' asRegex
90 Added: search: self class name;
91 Added: subexpression: 2) asCapitalizedPhrase ifNil: [
92 Added: 'Default Component' ] ])
93 Added: ]
94 Added:
95 Added: { #category : 'accessing' }
96 Added: MFTDialog >> heading: aString [
97 Added:
98 Added: heading := aString
99 Added: ]
100 Added:
101 Added: { #category : 'initialization' }
102 Added: MFTDialog >> initialize [
103 Added:
104 Added: super initialize.
105 Added: action := #add
106 Added: ]
107 Added:
108 Added: { #category : 'rendering' }
109 Added: MFTDialog >> renderCompletionOn: html [
110 Added:
111 Added: completion ifNotNil: [
112 Added: html progress
113 Added: class: 'my-3';
114 Added: with: [
115 Added: html progressBar
116 Added: beStriped;
117 Added: beAnimated;
118 Added: successBackground;
119 Added: valueNow: completion;
120 Added: with: completion percent ] ]
121 Added: ]
122 Added:
123 Added: { #category : 'rendering' }
124 Added: MFTDialog >> renderContentOn: html [
125 Added:
126 Added: self renderDialogOn: html with: [
127 Added: html text:
128 Added: 'By default, ' , self class name , ' doesn''t do anything.' ]
129 Added: ]
130 Added:
131 Added: { #category : 'rendering' }
132 Added: MFTDialog >> renderDialogOn: html with: aBlock [
133 Added:
134 Added: html container
135 Added: style: 'max-width: 40rem';
136 Added: with: [
137 Added: html heading level1 with: self heading.
138 Added: subheading ifNotNil: [
139 Added: html heading level3 textMuted with: subheading ].
140 Added: html form: [
141 Added: aBlock value.
142 Added: html horizontalRule.
143 Added: self renderSubmitOn: html ].
144 Added: self renderCompletionOn: html ]
145 Added: ]
146 Added:
147 Added: { #category : 'rendering' }
148 Added: MFTDialog >> renderSubmitOn: html [
149 Added:
150 Added: html buttonGroup: [
151 Added: html formButton
152 Added: beSubmit;
153 Added: bePrimary;
154 Added: beDangerIf: action = #delete;
155 Added: callback: [ self answer: true ];
156 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
157 Added: html formButton
158 Added: beSubmit;
159 Added: beSecondary;
160 Added: callback: [ self answer: false ];
161 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
162 Added: ]
163 Added:
164 Added: { #category : 'accessing' }
165 Added: MFTDialog >> subheading [
166 Added:
167 Added: ^ subheading
168 Added: ]
169 Added:
170 Added: { #category : 'accessing' }
171 Added: MFTDialog >> subheading: aString [
172 Added:
173 Added: subheading := aString
174 Added: ]
src/MyFitnessTracker-Components/MFTDietArticle.class.st
index 00000000..ed5a714f 000000..100644
@@ -0,0 +1,6 @@
1 Added: Class {
2 Added: #name : 'MFTDietArticle',
3 Added: #superclass : 'MFTArticle',
4 Added: #category : 'MyFitnessTracker-Components',
5 Added: #package : 'MyFitnessTracker-Components'
6 Added: }
src/MyFitnessTracker-Components/MFTEmailSignupDialog.class.st
index 00000000..2d3a19e1 000000..100644
@@ -0,0 +1,66 @@
1 Added: Class {
2 Added: #name : 'MFTEmailSignupDialog',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'localPart',
6 Added: 'domain'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Dialogs',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Dialogs'
11 Added: }
12 Added:
13 Added: { #category : 'initialization' }
14 Added: MFTEmailSignupDialog >> initialize [
15 Added:
16 Added: super initialize.
17 Added: localPart := String new.
18 Added: domain := String new
19 Added: ]
20 Added:
21 Added: { #category : 'rendering' }
22 Added: MFTEmailSignupDialog >> renderContentOn: html [
23 Added:
24 Added: html div
25 Added: darkBackground;
26 Added: paddingTopAndBottom: 3;
27 Added: paddingLeftAndRight: 5;
28 Added: class: 'fixed-top';
29 Added: style: 'z-index: 1052';
30 Added: with: [
31 Added: html heading
32 Added: level3;
33 Added: whiteText;
34 Added: with: 'Get notified as soon as MFT is ready!'.
35 Added: html paragraph
36 Added: whiteText;
37 Added: with: [
38 Added: html
39 Added: text:
40 Added: 'You will receive a single e-mail indicating that My Fitness Tracker is usable and accepting new user registration.';
41 Added: space;
42 Added: text:
43 Added: 'The e-mail address provided shall be used for no other purpose whatsoever.' ].
44 Added: html form
45 Added: paddingTopAndBottom: 3;
46 Added: with: [
47 Added: html inputGroup with: [
48 Added: html formTextInput
49 Added: callback: [ :value | localPart := value ];
50 Added: placeholder: 'my-user'.
51 Added: html inputGroupAppend: [ html inputGroupText: '@' ].
52 Added: html formTextInput
53 Added: callback: [ :value | domain := value ];
54 Added: placeholder: 'example.com'.
55 Added: html inputGroupAppend: [
56 Added: html buttonGroup: [
57 Added: html formButton
58 Added: beSecondary;
59 Added: beSubmit;
60 Added: callback: [ self answer: localPart , '@' , domain ];
61 Added: with: 'Confirm'.
62 Added: html outlineButton
63 Added: beSecondary;
64 Added: callback: [ self answer: nil ];
65 Added: with: 'Cancel' ] ] ] ] ]
66 Added: ]
src/MyFitnessTracker-Components/MFTExercisesForm.class.st
index 00000000..1a54a41e 000000..100644
@@ -0,0 +1,46 @@
1 Added: Class {
2 Added: #name : 'MFTExercisesForm',
3 Added: #superclass : 'MFTForm',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTExercisesForm class >> forExerciseCount: anInteger [
11 Added:
12 Added: | exercises |
13 Added: exercises := OrderedCollection new: anInteger.
14 Added: 1 to: anInteger do: [ :i |
15 Added: exercises add: (MFTSQLite3Database allExercises at: i) ].
16 Added: ^ self new
17 Added: modelObject: exercises;
18 Added: yourself
19 Added: ]
20 Added:
21 Added: { #category : 'initialization' }
22 Added: MFTExercisesForm >> initialize [
23 Added:
24 Added: super initialize.
25 Added: modelObject := OrderedCollection new.
26 Added: heading := 'Exercises'
27 Added: ]
28 Added:
29 Added: { #category : 'rendering' }
30 Added: MFTExercisesForm >> renderContentOn: html [
31 Added:
32 Added: self renderFormOn: html with: [ self renderSelectExercisesOn: html ]
33 Added: ]
34 Added:
35 Added: { #category : 'rendering' }
36 Added: MFTExercisesForm >> renderSelectExercisesOn: html [
37 Added:
38 Added: modelObject doWithIndex: [ :selectedExercise :i |
39 Added: html formGroup: [
40 Added: html label: 'Exercise ' , i asString.
41 Added: html select formControl
42 Added: list: MFTSQLite3Database allExercises;
43 Added: selected: selectedExercise;
44 Added: callback: [ :exercise | modelObject at: i put: exercise ];
45 Added: labels: [ :each | each englishName ] ] ]
46 Added: ]
src/MyFitnessTracker-Components/MFTFooter.class.st
index 00000000..8f0d2ff0 000000..100644
@@ -0,0 +1,27 @@
1 Added: Class {
2 Added: #name : 'MFTFooter',
3 Added: #superclass : 'SBSComponent',
4 Added: #category : 'MyFitnessTracker-Components',
5 Added: #package : 'MyFitnessTracker-Components'
6 Added: }
7 Added:
8 Added: { #category : 'rendering' }
9 Added: MFTFooter >> renderContentOn: html [
10 Added:
11 Added: self
12 Added: renderFooterOn: html
13 Added: with: [ html text: 'I am the default footer' ]
14 Added: ]
15 Added:
16 Added: { #category : 'rendering' }
17 Added: MFTFooter >> renderFooterOn: html with: aBlock [
18 Added:
19 Added: html div
20 Added: marginTop: 3;
21 Added: paddingTopAndBottom: 3;
22 Added: class: 'bg-light';
23 Added: with: [
24 Added: html container
25 Added: class: 'd-flex justify-content-center';
26 Added: with: [ aBlock value ] ]
27 Added: ]
src/MyFitnessTracker-Components/MFTForm.class.st
index 00000000..609b3b21 000000..100644
@@ -0,0 +1,85 @@
1 Added: "
2 Added: I represent a user-fillable form.
3 Added:
4 Added: Upon submitting the form (""submit"" button), I return (`WAComponent>>#answer:`) the `#modelObject` with its attributes populated by the appropriate `MFTFormComponent` subclasses.
5 Added: Upon canceling the form (""cancel"" button), I return `nil`.
6 Added: "
7 Added: Class {
8 Added: #name : 'MFTForm',
9 Added: #superclass : 'SBSComponent',
10 Added: #instVars : [
11 Added: 'modelObject',
12 Added: 'heading'
13 Added: ],
14 Added: #category : 'MyFitnessTracker-Components-Forms',
15 Added: #package : 'MyFitnessTracker-Components',
16 Added: #tag : 'Forms'
17 Added: }
18 Added:
19 Added: { #category : 'as yet unclassified' }
20 Added: MFTForm >> cancelForm [
21 Added:
22 Added: self answer: nil
23 Added: ]
24 Added:
25 Added: { #category : 'initialization' }
26 Added: MFTForm >> initialize [
27 Added:
28 Added: super initialize.
29 Added: heading := 'Form heading'
30 Added: ]
31 Added:
32 Added: { #category : 'accessing' }
33 Added: MFTForm >> modelObject [
34 Added:
35 Added: ^ modelObject
36 Added: ]
37 Added:
38 Added: { #category : 'accessing' }
39 Added: MFTForm >> modelObject: anObject [
40 Added:
41 Added: modelObject := anObject
42 Added: ]
43 Added:
44 Added: { #category : 'rendering' }
45 Added: MFTForm >> renderContentOn: html [
46 Added:
47 Added: self renderFormOn: html with: [ html render: modelObject ]
48 Added: ]
49 Added:
50 Added: { #category : 'as yet unclassified' }
51 Added: MFTForm >> renderFormOn: html with: aBlock [
52 Added:
53 Added: html container
54 Added: style: 'max-width: 40rem';
55 Added: with: [
56 Added: html displayHeading
57 Added: level: 3;
58 Added: with: heading.
59 Added: html form: [
60 Added: aBlock value.
61 Added: html horizontalRule.
62 Added: self renderSubmitOn: html ] ]
63 Added: ]
64 Added:
65 Added: { #category : 'as yet unclassified' }
66 Added: MFTForm >> renderSubmitOn: html [
67 Added:
68 Added: html buttonGroup: [
69 Added: html formButton
70 Added: beSubmit;
71 Added: bePrimary;
72 Added: callback: [ self submitForm ];
73 Added: with: 'Submit'.
74 Added: html formButton
75 Added: beSubmit;
76 Added: beSecondary;
77 Added: callback: [ self cancelForm ];
78 Added: with: 'Cancel' ]
79 Added: ]
80 Added:
81 Added: { #category : 'as yet unclassified' }
82 Added: MFTForm >> submitForm [
83 Added:
84 Added: self answer: modelObject
85 Added: ]
src/MyFitnessTracker-Components/MFTFormComponent.class.st
index 00000000..ec3ee682 000000..100644
@@ -0,0 +1,92 @@
1 Added: "
2 Added: When instantiated with the `MFTFormComponent class>>#set:` message, I return an instance of the appropriate subclass for setting the model object attribute.
3 Added: "
4 Added: Class {
5 Added: #name : 'MFTFormComponent',
6 Added: #superclass : 'SBSComponent',
7 Added: #instVars : [
8 Added: 'heading',
9 Added: 'modelObject'
10 Added: ],
11 Added: #category : 'MyFitnessTracker-Components-Forms',
12 Added: #package : 'MyFitnessTracker-Components',
13 Added: #tag : 'Forms'
14 Added: }
15 Added:
16 Added: { #category : 'as yet unclassified' }
17 Added: MFTFormComponent class >> formComponentFor: anAttribute [
18 Added:
19 Added: | formComponents |
20 Added: formComponents := Dictionary newFrom: {
21 Added: (#date -> MFTDateFormComponent).
22 Added: (#setGroups -> MFTSetGroupsFormComponent).
23 Added: (#primaryMuscleGroup
24 Added: -> MFTPrimaryMuscleGroupFormComponent).
25 Added: (#secondaryMuscleGroups
26 Added: -> MFTSecondaryMuscleGroupsFormComponent) }.
27 Added:
28 Added: ^ formComponents at: anAttribute ifAbsent: [
29 Added: self error:
30 Added: ('no appropriate {1} subclass for setting attribute "{2}"'
31 Added: format: {
32 Added: self.
33 Added: anAttribute }) ]
34 Added: ]
35 Added:
36 Added: { #category : 'as yet unclassified' }
37 Added: MFTFormComponent class >> set: anAttribute [
38 Added:
39 Added: | formComponent |
40 Added: formComponent := self formComponentFor: anAttribute.
41 Added: ^ formComponent new
42 Added: modelObject: thisContext sender receiver modelObject;
43 Added: yourself
44 Added: ]
45 Added:
46 Added: { #category : 'accessing' }
47 Added: MFTFormComponent >> heading [
48 Added:
49 Added: ^ heading
50 Added: ]
51 Added:
52 Added: { #category : 'accessing' }
53 Added: MFTFormComponent >> heading: anObject [
54 Added:
55 Added: heading := anObject
56 Added: ]
57 Added:
58 Added: { #category : 'initialization' }
59 Added: MFTFormComponent >> initialize [
60 Added:
61 Added: super initialize
62 Added: ]
63 Added:
64 Added: { #category : 'accessing' }
65 Added: MFTFormComponent >> modelObject [
66 Added:
67 Added: ^ modelObject
68 Added: ]
69 Added:
70 Added: { #category : 'accessing' }
71 Added: MFTFormComponent >> modelObject: anObject [
72 Added:
73 Added: modelObject := anObject
74 Added: ]
75 Added:
76 Added: { #category : 'rendering' }
77 Added: MFTFormComponent >> renderContentOn: html [
78 Added:
79 Added: self renderFormComponentOn: html with: [ html render: modelObject ]
80 Added: ]
81 Added:
82 Added: { #category : 'as yet unclassified' }
83 Added: MFTFormComponent >> renderFormComponentOn: html with: aBlock [
84 Added:
85 Added: html formGroup
86 Added: class: 'my-4';
87 Added: with: [
88 Added: html paragraph
89 Added: heading: 3;
90 Added: with: [ html text: heading ].
91 Added: aBlock value ]
92 Added: ]
src/MyFitnessTracker-Components/MFTGraph.class.st
index 00000000..1ddca7ff 000000..100644
@@ -0,0 +1,72 @@
1 Added: Class {
2 Added: #name : 'MFTGraph',
3 Added: #superclass : 'MFTWidget',
4 Added: #instVars : [
5 Added: 'labels',
6 Added: 'data'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Widgets',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Widgets'
11 Added: }
12 Added:
13 Added: { #category : 'accessing' }
14 Added: MFTGraph >> data [
15 Added:
16 Added: ^ data
17 Added: ]
18 Added:
19 Added: { #category : 'accessing' }
20 Added: MFTGraph >> data: anObject [
21 Added:
22 Added: data := anObject
23 Added: ]
24 Added:
25 Added: { #category : 'initialization' }
26 Added: MFTGraph >> initialize [
27 Added:
28 Added: super initialize.
29 Added: labels := #( Monday Tuesday Wednesday Thursday Friday ).
30 Added: data := #( 5 1 6 2 7 )
31 Added: ]
32 Added:
33 Added: { #category : 'accessing' }
34 Added: MFTGraph >> labels [
35 Added:
36 Added: ^ labels
37 Added: ]
38 Added:
39 Added: { #category : 'accessing' }
40 Added: MFTGraph >> labels: anObject [
41 Added:
42 Added: labels := anObject
43 Added: ]
44 Added:
45 Added: { #category : 'rendering' }
46 Added: MFTGraph >> renderContentOn: html [
47 Added:
48 Added: html heading level5 with: self defaultDescription.
49 Added: html canvas id: 'defaultGraph'.
50 Added: html script:
51 Added: 'var ctx = document.getElementById("defaultGraph").getContext("2d");
52 Added: var defaultChart = new Chart(ctx, {
53 Added: type: "line",
54 Added: data: {
55 Added: labels: ' , labels asJavascript , ',
56 Added: datasets: [{
57 Added: label: "default data",
58 Added: data: ' , data asJavascript , ',
59 Added: borderWidth: 1
60 Added: }]
61 Added: }
62 Added: });'
63 Added: ]
64 Added:
65 Added: { #category : 'accessing' }
66 Added: MFTGraph >> title [
67 Added:
68 Added: ^ ('^MFT(.*)Graph$' asRegex
69 Added: search: self class name;
70 Added: subexpression: 2) asCapitalizedPhrase ifNil: [
71 Added: 'Default Graph' ]
72 Added: ]
src/MyFitnessTracker-Components/MFTHeaderComponent.class.st
index 00000000..0615e206 000000..100644
@@ -0,0 +1,6 @@
1 Added: Class {
2 Added: #name : 'MFTHeaderComponent',
3 Added: #superclass : 'SBSComponent',
4 Added: #category : 'MyFitnessTracker-Components',
5 Added: #package : 'MyFitnessTracker-Components'
6 Added: }
src/MyFitnessTracker-Components/MFTLandingPage.class.st
index 00000000..6e77c573 000000..100644
@@ -0,0 +1,55 @@
1 Added: Class {
2 Added: #name : 'MFTLandingPage',
3 Added: #superclass : 'MFTPage',
4 Added: #instVars : [
5 Added: 'cards'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Pages',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Pages'
10 Added: }
11 Added:
12 Added: { #category : 'accessing' }
13 Added: MFTLandingPage >> cards [
14 Added:
15 Added: ^ cards
16 Added: ]
17 Added:
18 Added: { #category : 'accessing' }
19 Added: MFTLandingPage >> cards: aMFTCardCollection [
20 Added:
21 Added: cards := aMFTCardCollection
22 Added: ]
23 Added:
24 Added: { #category : 'hooks' }
25 Added: MFTLandingPage >> children [
26 Added:
27 Added: ^ cards
28 Added: ]
29 Added:
30 Added: { #category : 'as yet unclassified' }
31 Added: MFTLandingPage >> defaultCards [
32 Added:
33 Added: ^ {
34 Added: MFTCard new.
35 Added: MFTCard new.
36 Added: MFTCard new }
37 Added: ]
38 Added:
39 Added: { #category : 'as yet unclassified' }
40 Added: MFTLandingPage >> initialize [
41 Added:
42 Added: super initialize.
43 Added: title := 'home'.
44 Added: cards := self defaultCards
45 Added: ]
46 Added:
47 Added: { #category : 'rendering' }
48 Added: MFTLandingPage >> renderContentOn: html [
49 Added:
50 Added: self renderPageOn: html with: [
51 Added: html div
52 Added: style:
53 Added: 'display: flex; flex-wrap: wrap; justify-content: space-around; gap: 1em';
54 Added: with: [ self cards do: [ :card | html render: card ] ] ]
55 Added: ]
src/MyFitnessTracker-Components/MFTLearnPage.class.st
index 00000000..a82f4ab8 000000..100644
@@ -0,0 +1,35 @@
1 Added: Class {
2 Added: #name : 'MFTLearnPage',
3 Added: #superclass : 'MFTPage',
4 Added: #instVars : [
5 Added: 'articles',
6 Added: 'activeArticle'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Pages',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Pages'
11 Added: }
12 Added:
13 Added: { #category : 'initialization' }
14 Added: MFTLearnPage >> initialize [
15 Added:
16 Added: super initialize.
17 Added: title := 'learn'.
18 Added: articles := {
19 Added: MFTAthletesArticle new.
20 Added: MFTMusclesArticle new }.
21 Added: activeArticle := articles first
22 Added: ]
23 Added:
24 Added: { #category : 'rendering' }
25 Added: MFTLearnPage >> renderContentOn: html [
26 Added:
27 Added: self renderPageOn: html with: [
28 Added: html navigation flexColumn with: [
29 Added: articles do: [ :article |
30 Added: html navigationLink
31 Added: beActiveIf: [ activeArticle = article ];
32 Added: callback: [ activeArticle := article ];
33 Added: with: article title capitalized ] ].
34 Added: html render: activeArticle ]
35 Added: ]
src/MyFitnessTracker-Components/MFTLog.class.st
index 00000000..d789a8e9 000000..100644
@@ -0,0 +1,28 @@
1 Added: Class {
2 Added: #name : 'MFTLog',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'title'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Logs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Logs'
10 Added: }
11 Added:
12 Added: { #category : 'rendering' }
13 Added: MFTLog >> renderLogOn: html with: aBlock [
14 Added:
15 Added: html div: aBlock
16 Added: ]
17 Added:
18 Added: { #category : 'accessing' }
19 Added: MFTLog >> title [
20 Added:
21 Added: ^ title
22 Added: ]
23 Added:
24 Added: { #category : 'accessing' }
25 Added: MFTLog >> title: anObject [
26 Added:
27 Added: title := anObject
28 Added: ]
src/MyFitnessTracker-Components/MFTLoginRegisterLogoutComponent.class.st
index 00000000..73eb5bc3 000000..100644
@@ -0,0 +1,154 @@
1 Added: Class {
2 Added: #name : 'MFTLoginRegisterLogoutComponent',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'user'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'as yet unclassified' }
12 Added: MFTLoginRegisterLogoutComponent >> attemptLogin: aMFTUser [
13 Added: "Attempt to match aMFTUser passwordHash against an existing user password_hash in the database."
14 Added:
15 Added: | existingUser |
16 Added: aMFTUser username = 'testMFT' ifTrue: [
17 Added: ^ self session login: MFTSQLite3Database getTestUser ].
18 Added: existingUser := MFTSQLite3Database getExistingUser: aMFTUser.
19 Added: aMFTUser passwordHash = existingUser passwordHash
20 Added: ifTrue: [ self session login: existingUser ]
21 Added: ifFalse: [ self inform: 'Login failed' ]
22 Added: ]
23 Added:
24 Added: { #category : 'initialization' }
25 Added: MFTLoginRegisterLogoutComponent >> initialize [
26 Added:
27 Added: super initialize.
28 Added: user := MFTUser new
29 Added: ]
30 Added:
31 Added: { #category : 'as yet unclassified' }
32 Added: MFTLoginRegisterLogoutComponent >> logout [
33 Added:
34 Added: self session logout
35 Added: ]
36 Added:
37 Added: { #category : 'rendering' }
38 Added: MFTLoginRegisterLogoutComponent >> renderContentOn: html [
39 Added:
40 Added: self session user isLoggedIn
41 Added: ifFalse: [ self renderLoginAndRegisterModalsOn: html ]
42 Added: ifTrue: [ self renderLogoutButtonOn: html ]
43 Added: ]
44 Added:
45 Added: { #category : 'rendering' }
46 Added: MFTLoginRegisterLogoutComponent >> renderLoginAndRegisterModalsOn: html [
47 Added: "Logging in and registering display modal components; they are not in a form."
48 Added:
49 Added: html buttonGroup: [
50 Added: html outlineButton
51 Added: beSecondary;
52 Added: beSmall;
53 Added: dataToggle: 'modal';
54 Added: dataTarget: '#loginModal';
55 Added: with: 'Login'.
56 Added: html outlineButton
57 Added: bePrimary;
58 Added: beSmall;
59 Added: dataToggle: 'modal';
60 Added: dataTarget: '#registerModal';
61 Added: with: 'Register' ].
62 Added: self renderLoginModalOn: html.
63 Added: self renderRegisterModalOn: html
64 Added: ]
65 Added:
66 Added: { #category : 'rendering' }
67 Added: MFTLoginRegisterLogoutComponent >> renderLoginModalOn: html [
68 Added:
69 Added: html modal
70 Added: id: 'loginModal';
71 Added: fade;
72 Added: with: [
73 Added: html modalDialog
74 Added: beCentered;
75 Added: with: [
76 Added: html modalContent: [
77 Added: html form: [
78 Added: html modalHeader: [
79 Added: html modalTitle
80 Added: level5;
81 Added: with: 'Welcome back!'.
82 Added: html modalCloseButton ].
83 Added: html modalBody with: [
84 Added: html formGroup: [
85 Added: html label: 'Username'.
86 Added: html textInput formControl callback: [ :value |
87 Added: user username: value ] ].
88 Added: html formGroup: [
89 Added: html label: 'Password'.
90 Added: html passwordInput formControl callback: [ :value |
91 Added: user passwordHashFromString: value ] ] ].
92 Added: html modalFooter: [
93 Added: html buttonGroup: [
94 Added: html formButton
95 Added: bePrimary;
96 Added: callback: [ self attemptLogin: user ];
97 Added: with: 'Login'.
98 Added: html formButton
99 Added: beSecondary;
100 Added: dataDismiss: 'modal';
101 Added: with: 'Cancel' ] ] ] ] ] ]
102 Added: ]
103 Added:
104 Added: { #category : 'rendering' }
105 Added: MFTLoginRegisterLogoutComponent >> renderLogoutButtonOn: html [
106 Added: "Logging out is an action; the button is in a form."
107 Added:
108 Added: html form: [
109 Added: html outlineButton
110 Added: beSecondary;
111 Added: beSmall;
112 Added: callback: [ self logout ];
113 Added: with: 'Logout' ]
114 Added: ]
115 Added:
116 Added: { #category : 'rendering' }
117 Added: MFTLoginRegisterLogoutComponent >> renderRegisterModalOn: html [
118 Added:
119 Added: html modal
120 Added: id: 'registerModal';
121 Added: fade;
122 Added: with: [
123 Added: html modalDialog
124 Added: beCentered;
125 Added: with: [
126 Added: html modalContent: [
127 Added: html form: [
128 Added: html modalHeader: [
129 Added: html modalTitle
130 Added: level5;
131 Added: with: 'Welcome aboard!'.
132 Added: html modalCloseButton ].
133 Added: html modalBody with: [
134 Added: html formGroup: [
135 Added: html label: 'Username'.
136 Added: html textInput formControl callback: [ :value |
137 Added: user username: value ] ].
138 Added: html formGroup: [
139 Added: html label: 'Password'.
140 Added: html passwordInput formControl callback: [ :value |
141 Added: user passwordHashFromString: value ] ] ].
142 Added: html modalFooter: [
143 Added: html buttonGroup: [
144 Added: html formButton
145 Added: bePrimary;
146 Added: callback: [
147 Added: MFTSQLite3Database registerNewUser: user.
148 Added: self attemptLogin: user ];
149 Added: with: 'Register'.
150 Added: html formButton
151 Added: beSecondary;
152 Added: dataDismiss: 'modal';
153 Added: with: 'Cancel' ] ] ] ] ] ]
154 Added: ]
src/MyFitnessTracker-Components/MFTLogsPage.class.st
index 00000000..11058155 000000..100644
@@ -0,0 +1,49 @@
1 Added: Class {
2 Added: #name : 'MFTLogsPage',
3 Added: #superclass : 'MFTPage',
4 Added: #instVars : [
5 Added: 'activeLog',
6 Added: 'logs'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Pages',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Pages'
11 Added: }
12 Added:
13 Added: { #category : 'hooks' }
14 Added: MFTLogsPage >> children [
15 Added:
16 Added: ^ logs
17 Added: ]
18 Added:
19 Added: { #category : 'initialization' }
20 Added: MFTLogsPage >> initialize [
21 Added:
22 Added: super initialize.
23 Added: title := 'logs'.
24 Added: logs := {
25 Added: MFTWorkoutsLog new.
26 Added: MFTWeightsLog new }.
27 Added: activeLog := logs first
28 Added: ]
29 Added:
30 Added: { #category : 'rendering' }
31 Added: MFTLogsPage >> renderContentOn: html [
32 Added:
33 Added: self renderPageOn: html with: [
34 Added: self renderLogNavigationOn: html.
35 Added: html render: activeLog ]
36 Added: ]
37 Added:
38 Added: { #category : 'rendering' }
39 Added: MFTLogsPage >> renderLogNavigationOn: html [
40 Added:
41 Added: html form
42 Added: class: 'mb-3';
43 Added: with: [
44 Added: html navigation flexColumn with: [
45 Added: logs do: [ :log |
46 Added: html navigationLink
47 Added: callback: [ activeLog := log ];
48 Added: with: log title ] ] ]
49 Added: ]
src/MyFitnessTracker-Components/MFTMainNavigationBarComponent.class.st
index 00000000..594c32da 000000..100644
@@ -0,0 +1,64 @@
1 Added: Class {
2 Added: #name : 'MFTMainNavigationBarComponent',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'loginRegisterLogout'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'hooks' }
12 Added: MFTMainNavigationBarComponent >> children [
13 Added:
14 Added: ^ { loginRegisterLogout }
15 Added: ]
16 Added:
17 Added: { #category : 'initialization' }
18 Added: MFTMainNavigationBarComponent >> initialize [
19 Added:
20 Added: super initialize.
21 Added: loginRegisterLogout := MFTLoginRegisterLogoutComponent new
22 Added: ]
23 Added:
24 Added: { #category : 'rendering' }
25 Added: MFTMainNavigationBarComponent >> renderContentOn: html [
26 Added:
27 Added: html navigationBar
28 Added: beLight;
29 Added: lightBackground;
30 Added: expandLarge;
31 Added: marginBottom: 3;
32 Added: paddingLeftAndRight: 3;
33 Added: style: 'position: sticky; top: 0; z-index: 1051';
34 Added: with: [ self renderNavigationBarItemsOn: html ]
35 Added: ]
36 Added:
37 Added: { #category : 'rendering' }
38 Added: MFTMainNavigationBarComponent >> renderNavigationBarItemsOn: html [
39 Added:
40 Added: | pm |
41 Added: pm := self session pageManager.
42 Added: html navigationBarBrand
43 Added: callback: [ pm setActivePageAt: #home ];
44 Added: with: 'MyFitnessTracker'.
45 Added: "The toggler is only visible when the screen width is reduced."
46 Added: html navigationBarToggler
47 Added: beButtonType;
48 Added: collapse;
49 Added: dataTarget: '#navbarCollapsed';
50 Added: with: [ html navigationBarTogglerIcon ].
51 Added: html navigationBarCollapse collapse
52 Added: id: 'navbarCollapsed';
53 Added: class: 'justify-content-between';
54 Added: with: [
55 Added: html navigationBarNavigation: [
56 Added: pm mainPages keysAndValuesDo: [ :name :page |
57 Added: html navigationItem
58 Added: beActiveIf: [ pm activePage = page ];
59 Added: with: [
60 Added: html navigationLink
61 Added: callback: [ pm setActivePageAt: name ];
62 Added: with: page title capitalized ] ] ].
63 Added: html render: loginRegisterLogout ]
64 Added: ]
src/MyFitnessTracker-Components/MFTMainPublicCard.class.st
index 00000000..3d5b30fb 000000..100644
@@ -0,0 +1,45 @@
1 Added: Class {
2 Added: #name : 'MFTMainPublicCard',
3 Added: #superclass : 'MFTCard',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'adding' }
10 Added: MFTMainPublicCard >> addWorkout [
11 Added:
12 Added: | newWorkout |
13 Added: newWorkout := self session pageManager activePage call:
14 Added: MFTWorkoutForm new.
15 Added: newWorkout
16 Added: ifNil: [ ^ self ]
17 Added: ifNotNil: [ self session pageManager setActivePageAt: #logs ].
18 Added:
19 Added: self session user isLoggedIn
20 Added: ifTrue: [ self session db insert: newWorkout ]
21 Added: ifFalse: [ self session user workouts add: newWorkout ]
22 Added: ]
23 Added:
24 Added: { #category : 'rendering' }
25 Added: MFTMainPublicCard >> renderContentOn: html [
26 Added:
27 Added: self renderCardOn: html with: [
28 Added: html jumbotron
29 Added: class: 'p-3 bg-light h-100';
30 Added: with: [
31 Added: html displayHeading
32 Added: level: 1;
33 Added: with: 'Log, plan, share your workouts.'.
34 Added: html heading
35 Added: level: 2;
36 Added: textMuted;
37 Added: with: 'Free Software never looked so fit!'.
38 Added: html form: [
39 Added: html formButton
40 Added: bePrimary;
41 Added: beLarge;
42 Added: class: 'mt-3';
43 Added: callback: [ self addWorkout ];
44 Added: with: 'Log a workout' ] ] ]
45 Added: ]
src/MyFitnessTracker-Components/MFTMainUserCard.class.st
index 00000000..f89a7aff 000000..100644
@@ -0,0 +1,41 @@
1 Added: Class {
2 Added: #name : 'MFTMainUserCard',
3 Added: #superclass : 'MFTCard',
4 Added: #instVars : [
5 Added: 'lastLoginDate',
6 Added: 'subtitle'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Widgets',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Widgets'
11 Added: }
12 Added:
13 Added: { #category : 'initialization' }
14 Added: MFTMainUserCard >> initialize [
15 Added:
16 Added: super initialize.
17 Added: lastLoginDate := self session user lastLoginDateAndTime.
18 Added: subtitle := 'Last logged in {1}, {2} at {3} UTC' format: {
19 Added: lastLoginDate dayOfWeekName.
20 Added: lastLoginDate asDate asString.
21 Added: lastLoginDate asTimeUTC asString }
22 Added: ]
23 Added:
24 Added: { #category : 'rendering' }
25 Added: MFTMainUserCard >> renderContentOn: html [
26 Added:
27 Added: | user |
28 Added: user := self session user.
29 Added: self renderCardOn: html with: [
30 Added: html jumbotron
31 Added: class: 'p-3 bg-light';
32 Added: with: [
33 Added: html displayHeading
34 Added: level: 1;
35 Added: with: [
36 Added: html
37 Added: text: 'Welcome, ';
38 Added: code: (user realFirstName ifEmpty: [ user username ]);
39 Added: text: '!' ].
40 Added: html big textMuted with: subtitle ] ]
41 Added: ]
src/MyFitnessTracker-Components/MFTMusclesArticle.class.st
index 00000000..db996cb3 000000..100644
@@ -0,0 +1,30 @@
1 Added: Class {
2 Added: #name : 'MFTMusclesArticle',
3 Added: #superclass : 'MFTArticle',
4 Added: #instVars : [
5 Added: 'muscleGroups'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'hooks' }
12 Added: MFTMusclesArticle >> children [
13 Added:
14 Added: ^ muscleGroups
15 Added: ]
16 Added:
17 Added: { #category : 'initialization' }
18 Added: MFTMusclesArticle >> initialize [
19 Added:
20 Added: super initialize.
21 Added: title := 'muscles'
22 Added: ]
23 Added:
24 Added: { #category : 'rendering' }
25 Added: MFTMusclesArticle >> renderContentOn: html [
26 Added:
27 Added: self renderArticleOn: html with: [
28 Added: MFTSQLite3Database allMuscleGroups do: [ :muscleGroup |
29 Added: html render: muscleGroup ] ]
30 Added: ]
src/MyFitnessTracker-Components/MFTPage.class.st
index 00000000..33f6a340 000000..100644
@@ -0,0 +1,24 @@
1 Added: Class {
2 Added: #name : 'MFTPage',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'title'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Pages',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Pages'
10 Added: }
11 Added:
12 Added: { #category : 'rendering' }
13 Added: MFTPage >> renderPageOn: html with: aBlock [
14 Added:
15 Added: html container
16 Added: style: 'max-width: 50rem';
17 Added: with: aBlock
18 Added: ]
19 Added:
20 Added: { #category : 'accessing' }
21 Added: MFTPage >> title [
22 Added:
23 Added: ^ title
24 Added: ]
src/MyFitnessTracker-Components/MFTPrimaryMuscleGroupDialog.class.st
index 00000000..588e0dca 000000..100644
@@ -0,0 +1,64 @@
1 Added: Class {
2 Added: #name : 'MFTPrimaryMuscleGroupDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'primaryMuscleGroup'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'initialization' }
13 Added: MFTPrimaryMuscleGroupDialog >> initialize [
14 Added:
15 Added: super initialize.
16 Added: primaryMuscleGroup := MFTMuscleGroup new.
17 Added:
18 Added: ]
19 Added:
20 Added: { #category : 'accessing' }
21 Added: MFTPrimaryMuscleGroupDialog >> primaryMuscleGroup [
22 Added:
23 Added: ^ primaryMuscleGroup
24 Added: ]
25 Added:
26 Added: { #category : 'accessing' }
27 Added: MFTPrimaryMuscleGroupDialog >> primaryMuscleGroup: anObject [
28 Added:
29 Added: primaryMuscleGroup := anObject
30 Added: ]
31 Added:
32 Added: { #category : 'rendering' }
33 Added: MFTPrimaryMuscleGroupDialog >> renderContentOn: html [
34 Added:
35 Added: | allMuscleGroups selectedMuscleGroup |
36 Added: allMuscleGroups := MFTSQLite3Database allMuscleGroups.
37 Added: selectedMuscleGroup := primaryMuscleGroup ifNotNil: [
38 Added: allMuscleGroups detect: [ :muscleGroup |
39 Added: muscleGroup englishName
40 Added: = primaryMuscleGroup englishName ] ].
41 Added: self renderDialogOn: html with: [
42 Added: html formGroup: [
43 Added: html select formControl
44 Added: list: allMuscleGroups;
45 Added: selected: selectedMuscleGroup;
46 Added: labels: [ :muscleGroup | muscleGroup englishName ];
47 Added: callback: [ :group | primaryMuscleGroup := group ] ] ]
48 Added: ]
49 Added:
50 Added: { #category : 'rendering' }
51 Added: MFTPrimaryMuscleGroupDialog >> renderSubmitOn: html [
52 Added:
53 Added: html buttonGroup: [
54 Added: html formButton
55 Added: beSubmit;
56 Added: bePrimary;
57 Added: callback: [ self answer: primaryMuscleGroup ];
58 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
59 Added: html formButton
60 Added: beSubmit;
61 Added: beSecondary;
62 Added: callback: [ self answer: nil ];
63 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
64 Added: ]
src/MyFitnessTracker-Components/MFTPrimaryMuscleGroupFormComponent.class.st
index 00000000..9eca34af 000000..100644
@@ -0,0 +1,32 @@
1 Added: Class {
2 Added: #name : 'MFTPrimaryMuscleGroupFormComponent',
3 Added: #superclass : 'MFTFormComponent',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'initialization' }
10 Added: MFTPrimaryMuscleGroupFormComponent >> initialize [
11 Added:
12 Added: super initialize.
13 Added: heading := 'Primary Group'
14 Added: ]
15 Added:
16 Added: { #category : 'rendering' }
17 Added: MFTPrimaryMuscleGroupFormComponent >> renderContentOn: html [
18 Added:
19 Added: | allMuscleGroups selectedMuscleGroup |
20 Added: allMuscleGroups := MFTSQLite3Database allMuscleGroups.
21 Added: selectedMuscleGroup := modelObject primaryMuscleGroup ifNotNil: [
22 Added: allMuscleGroups detect: [ :muscleGroup |
23 Added: muscleGroup englishName
24 Added: = modelObject primaryMuscleGroup englishName ] ].
25 Added:
26 Added: self renderFormComponentOn: html with: [
27 Added: html select formControl
28 Added: list: allMuscleGroups;
29 Added: selected: selectedMuscleGroup;
30 Added: labels: [ :muscleGroup | muscleGroup englishName ];
31 Added: callback: [ :group | modelObject primaryMuscleGroup: group ] ]
32 Added: ]
src/MyFitnessTracker-Components/MFTProfilePage.class.st
index 00000000..fd3aab7f 000000..100644
@@ -0,0 +1,50 @@
1 Added: Class {
2 Added: #name : 'MFTProfilePage',
3 Added: #superclass : 'MFTPage',
4 Added: #category : 'MyFitnessTracker-Components-Pages',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Pages'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTProfilePage >> editProfile [
11 Added:
12 Added: | updatedUser |
13 Added: updatedUser := self call: (MFTUserTask edit: self session user).
14 Added: updatedUser ifNil: [ ^ self ].
15 Added: self session user: updatedUser.
16 Added: self session user isLoggedIn ifTrue: [
17 Added: self session db updateUserWith: updatedUser ]
18 Added: ]
19 Added:
20 Added: { #category : 'initialization' }
21 Added: MFTProfilePage >> initialize [
22 Added:
23 Added: super initialize.
24 Added: title := 'profile'
25 Added: ]
26 Added:
27 Added: { #category : 'rendering' }
28 Added: MFTProfilePage >> renderContentOn: html [
29 Added:
30 Added: | user |
31 Added: user := self session user.
32 Added:
33 Added: self renderPageOn: html with: [
34 Added: html heading level1 with: [
35 Added: html
36 Added: code: self session user username;
37 Added: text: '''s profile' ].
38 Added: self renderProfileActionsOn: html.
39 Added: html render: user ]
40 Added: ]
41 Added:
42 Added: { #category : 'rendering' }
43 Added: MFTProfilePage >> renderProfileActionsOn: html [
44 Added:
45 Added: html form: [
46 Added: html formButton
47 Added: bePrimary;
48 Added: callback: [ self editProfile ];
49 Added: with: 'Edit profile' ]
50 Added: ]
src/MyFitnessTracker-Components/MFTPromisesCard.class.st
index 00000000..a2c2e1ff 000000..100644
@@ -0,0 +1,30 @@
1 Added: Class {
2 Added: #name : 'MFTPromisesCard',
3 Added: #superclass : 'MFTCard',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'rendering' }
10 Added: MFTPromisesCard >> renderContentOn: html [
11 Added:
12 Added: self renderCardOn: html with: [
13 Added: html cardHeader: 'My promises to all users:'.
14 Added: html cardBody: [
15 Added: html listGroup: [
16 Added: html
17 Added: listGroupItem:
18 Added: 'Every single feature shall always be free of charge.';
19 Added: listGroupItem:
20 Added: 'No personal user data shall ever be sold, under any circumstances.';
21 Added: listGroupItem:
22 Added: 'No external advertisements shall ever be displayed.' ].
23 Added: html form
24 Added: class: 'mt-3';
25 Added: with: [
26 Added: html outlineButton
27 Added: bePrimary;
28 Added: callback: [ self session pageManager setActivePageAt: #about ];
29 Added: with: 'Why did I create this web app?' ] ] ]
30 Added: ]
src/MyFitnessTracker-Components/MFTPublicLandingPage.class.st
index 00000000..93406184 000000..100644
@@ -0,0 +1,17 @@
1 Added: Class {
2 Added: #name : 'MFTPublicLandingPage',
3 Added: #superclass : 'MFTLandingPage',
4 Added: #category : 'MyFitnessTracker-Components-Pages',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Pages'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTPublicLandingPage >> defaultCards [
11 Added:
12 Added: ^ {
13 Added: MFTMainPublicCard new.
14 Added: MFTWorkoutsCard new.
15 Added: MFTWeightsCard new.
16 Added: MFTPromisesCard new }
17 Added: ]
src/MyFitnessTracker-Components/MFTRegisterProspectEmailHeader.class.st
index 00000000..597489c3 000000..100644
@@ -0,0 +1,137 @@
1 Added: Class {
2 Added: #name : 'MFTRegisterProspectEmailHeader',
3 Added: #superclass : 'MFTHeaderComponent',
4 Added: #instVars : [
5 Added: 'email',
6 Added: 'localPart',
7 Added: 'domain',
8 Added: 'isDismissed'
9 Added: ],
10 Added: #category : 'MyFitnessTracker-Components',
11 Added: #package : 'MyFitnessTracker-Components'
12 Added: }
13 Added:
14 Added: { #category : 'adding' }
15 Added: MFTRegisterProspectEmailHeader >> addUserEmail [
16 Added:
17 Added: | emailToCheck emailPattern |
18 Added: emailToCheck := self call: MFTEmailSignupDialog new.
19 Added: emailPattern := '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]{3,}\.[a-zA-Z]{2,}$'
20 Added: asRegex.
21 Added: (emailToCheck isNil or: [ (emailPattern matches: emailToCheck) not ])
22 Added: ifTrue: [ ^ nil ].
23 Added: email := emailToCheck.
24 Added: MFTSQLite3Database storeProspectEmail: email
25 Added: ]
26 Added:
27 Added: { #category : 'initialization' }
28 Added: MFTRegisterProspectEmailHeader >> initialize [
29 Added:
30 Added: super initialize.
31 Added: isDismissed := false
32 Added: ]
33 Added:
34 Added: { #category : 'accessing' }
35 Added: MFTRegisterProspectEmailHeader >> isDismissed [
36 Added:
37 Added: ^ isDismissed
38 Added: ]
39 Added:
40 Added: { #category : 'accessing' }
41 Added: MFTRegisterProspectEmailHeader >> isDismissed: anObject [
42 Added:
43 Added: isDismissed := anObject
44 Added: ]
45 Added:
46 Added: { #category : 'rendering' }
47 Added: MFTRegisterProspectEmailHeader >> renderContentOn: html [
48 Added:
49 Added: isDismissed ifTrue: [ ^ self ].
50 Added: email
51 Added: ifNil: [
52 Added: html alert
53 Added: beWarning;
54 Added: marginBottom: 0;
55 Added: with: [
56 Added: html alertHeading: 'This app is still in beta.'.
57 Added: html paragraph: [
58 Added: html
59 Added: text:
60 Added: 'My Fitness Tracker is still under heavy development, with improvements being made daily.';
61 Added: space;
62 Added: text: 'I can''t wait to share the finished product with you!' ].
63 Added: html form with: [
64 Added: html label
65 Added: style: 'margin-right: 1em';
66 Added: with: [ html strong: 'Want to know when version 1.0 is out?' ].
67 Added: html buttonGroup: [
68 Added: html formButton
69 Added: beInfo;
70 Added: callback: [ self addUserEmail ];
71 Added: with: 'E-mail me!'.
72 Added: html formButton
73 Added: beSecondary;
74 Added: callback: [ isDismissed := true ];
75 Added: with: 'I''m not interested' ] ] ] ]
76 Added: ifNotNil: [
77 Added: html alert
78 Added: beSuccess;
79 Added: beDismissible;
80 Added: marginBottom: 0;
81 Added: with: [
82 Added: html closeButton dataDismiss: 'alert'.
83 Added: html
84 Added: text: 'You''ll be notified at ';
85 Added: strong: email;
86 Added: text: ' when My Fitness Tracker is ready for you!' ] ]
87 Added: ]
88 Added:
89 Added: { #category : 'rendering' }
90 Added: MFTRegisterProspectEmailHeader >> renderEmailInputModalButtonOn: html [
91 Added:
92 Added: html formButton
93 Added: bePrimary;
94 Added: beSmall;
95 Added: dataToggle: 'modal';
96 Added: dataTarget: '#emailInputModal';
97 Added: with: 'E-mail me!'
98 Added: ]
99 Added:
100 Added: { #category : 'rendering' }
101 Added: MFTRegisterProspectEmailHeader >> renderEmailInputModalOn: html [
102 Added:
103 Added: html modal
104 Added: id: 'emailInputModal';
105 Added: fade;
106 Added: with: [
107 Added: html modalDialog
108 Added: beCentered;
109 Added: with: [
110 Added: html modalContent: [
111 Added: html form: [
112 Added: html modalHeader: [
113 Added: html modalTitle
114 Added: level5;
115 Added: with:
116 Added: 'You''ll be the first to know when My Fitness Tracker is ready to use.'.
117 Added: html modalCloseButton ].
118 Added:
119 Added: html modalBody: [
120 Added: html inputGroup: [
121 Added: html formTextInput
122 Added: callback: [ :value | localPart := value ];
123 Added: placeholder: 'my-user'.
124 Added: html inputGroupAppend: [ html inputGroupText: '@' ].
125 Added: html formTextInput
126 Added: callback: [ :value | domain := value ];
127 Added: placeholder: 'example.com' ] ].
128 Added:
129 Added: html modalFooter: [
130 Added: html paragraph:
131 Added: 'You will receive a single e-mail when the app is ready to use. Your e-mail address shall not be used in any other way.'.
132 Added: html formButton
133 Added: bePrimary;
134 Added: beSubmit;
135 Added: callback: [ email := localPart , '@' , domain ];
136 Added: with: 'Confirm' ] ] ] ] ]
137 Added: ]
src/MyFitnessTracker-Components/MFTRepsDistributionGraph.class.st
index 00000000..a7c27e54 000000..100644
@@ -0,0 +1,54 @@
1 Added: Class {
2 Added: #name : 'MFTRepsDistributionGraph',
3 Added: #superclass : 'MFTGraph',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTRepsDistributionGraph >> crunchTheNumbers [
11 Added: "TODO: This looks ugly."
12 Added:
13 Added: | sets repTally |
14 Added: sets := self session user workouts flatCollect: #sets.
15 Added: repTally := Dictionary new.
16 Added: sets do: [ :set |
17 Added: repTally at: set exercise englishName ifAbsentPut: [ 0 ].
18 Added: repTally
19 Added: at: set exercise englishName
20 Added: put: (repTally at: set exercise englishName) + set reps ].
21 Added:
22 Added: labels := repTally keys.
23 Added: data := repTally values
24 Added: ]
25 Added:
26 Added: { #category : 'initialization' }
27 Added: MFTRepsDistributionGraph >> initialize [
28 Added:
29 Added: super initialize.
30 Added: self crunchTheNumbers
31 Added: ]
32 Added:
33 Added: { #category : 'rendering' }
34 Added: MFTRepsDistributionGraph >> renderContentOn: html [
35 Added:
36 Added: html canvas id: 'repsVsTimeChart'.
37 Added: html script:
38 Added: 'var ctx = document.getElementById("repsVsTimeChart").getContext("2d");
39 Added: var workoutChart = new Chart(ctx, {
40 Added: type: "doughnut",
41 Added: data: {
42 Added: labels: ' , labels asJavascript , ',
43 Added: datasets: [{
44 Added: data: ' , data asJavascript , '
45 Added: }]
46 Added: },
47 Added: options: {
48 Added: title: {
49 Added: display: true,
50 Added: text: "Reps by exercise"
51 Added: }
52 Added: }
53 Added: });'
54 Added: ]
src/MyFitnessTracker-Components/MFTRootComponent.class.st
index 00000000..50853b9d 000000..100644
@@ -0,0 +1,101 @@
1 Added: Class {
2 Added: #name : 'MFTRootComponent',
3 Added: #superclass : 'SBSRootComponent',
4 Added: #instVars : [
5 Added: 'main'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'testing' }
12 Added: MFTRootComponent class >> canBeRoot [
13 Added:
14 Added: ^ true
15 Added: ]
16 Added:
17 Added: { #category : 'class initialization' }
18 Added: MFTRootComponent class >> initialize [
19 Added:
20 Added: | application libraries |
21 Added: application := WAAdmin register: self asApplicationAt: 'mft'.
22 Added: application preferenceAt: #sessionClass put: MFTSession.
23 Added: libraries := MFTUtils isDevelopmentImage
24 Added: ifTrue: [ self libraries at: #development ]
25 Added: ifFalse: [ self libraries at: #deployment ].
26 Added: libraries do: [ :library | application addLibrary: library ].
27 Added: ^ application
28 Added: ]
29 Added:
30 Added: { #category : 'class initialization' }
31 Added: MFTRootComponent class >> libraries [
32 Added:
33 Added: ^ Dictionary new
34 Added: at: #development put: {
35 Added: JQDevelopmentLibrary.
36 Added: JQUiDevelopmentLibrary.
37 Added: SBSDevelopmentLibrary };
38 Added: at: #deployment put: {
39 Added: JQGoogleLibrary.
40 Added: JQUiGoogleLibrary.
41 Added: SBSCDNDeploymentLibrary };
42 Added: yourself
43 Added: ]
44 Added:
45 Added: { #category : 'adding' }
46 Added: MFTRootComponent >> addBootstrapJSScriptTo: html [
47 Added:
48 Added: | library |
49 Added: library := MFTUtils isDevelopmentImage
50 Added: ifTrue: [ SBSDeploymentLibrary ]
51 Added: ifFalse: [ SBSCDNDeploymentLibrary ].
52 Added: library addLoadScriptTo: html
53 Added: ]
54 Added:
55 Added: { #category : 'rendering' }
56 Added: MFTRootComponent >> children [
57 Added:
58 Added: ^ { main }
59 Added: ]
60 Added:
61 Added: { #category : 'initialization' }
62 Added: MFTRootComponent >> initialize [
63 Added:
64 Added: super initialize.
65 Added: main := MFTScreenComponent new
66 Added: ]
67 Added:
68 Added: { #category : 'initialization' }
69 Added: MFTRootComponent >> main: aComponent [
70 Added:
71 Added: main := aComponent
72 Added: ]
73 Added:
74 Added: { #category : 'rendering' }
75 Added: MFTRootComponent >> renderContentOn: html [
76 Added:
77 Added: html script url: 'https://cdn.jsdelivr.net/npm/chart.js'.
78 Added: html render: main.
79 Added: self addBootstrapJSScriptTo: html
80 Added: ]
81 Added:
82 Added: { #category : 'updating' }
83 Added: MFTRootComponent >> updateRoot: anHtmlRoot [
84 Added:
85 Added: super updateRoot: anHtmlRoot.
86 Added: anHtmlRoot beHtml5.
87 Added: anHtmlRoot meta
88 Added: name: 'viewport';
89 Added: content: 'width=device-width, initial-scale=1'.
90 Added: anHtmlRoot title: 'My Fitness Tracker ' , self version.
91 Added: anHtmlRoot javascript url: 'https://cdn.jsdelivr.net/npm/chart.js'.
92 Added: anHtmlRoot link
93 Added: beShortcutIcon;
94 Added: url: MFTFileLibrary / #faviconPng
95 Added: ]
96 Added:
97 Added: { #category : 'versions' }
98 Added: MFTRootComponent >> version [
99 Added:
100 Added: ^ MFTUtils version ifNil: [ '[DEVELOP]' ]
101 Added: ]
src/MyFitnessTracker-Components/MFTSandboxPage.class.st
index 00000000..8458e230 000000..100644
@@ -0,0 +1,22 @@
1 Added: Class {
2 Added: #name : 'MFTSandboxPage',
3 Added: #superclass : 'MFTPage',
4 Added: #category : 'MyFitnessTracker-Components-Pages',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Pages'
7 Added: }
8 Added:
9 Added: { #category : 'initialization' }
10 Added: MFTSandboxPage >> initialize [
11 Added:
12 Added: super initialize.
13 Added: title := 'sandbox'
14 Added: ]
15 Added:
16 Added: { #category : 'rendering' }
17 Added: MFTSandboxPage >> renderContentOn: html [
18 Added:
19 Added: self renderPageOn: html with: [
20 Added: html text: 'Welcome to the sandbox page.'.
21 Added: MFTSQLite3Database allMuscleGroups do: [ :each | html render: each ] ]
22 Added: ]
src/MyFitnessTracker-Components/MFTScreenComponent.class.st
index 00000000..5fb09ad7 000000..100644
@@ -0,0 +1,38 @@
1 Added: Class {
2 Added: #name : 'MFTScreenComponent',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'pm'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components',
8 Added: #package : 'MyFitnessTracker-Components'
9 Added: }
10 Added:
11 Added: { #category : 'hooks' }
12 Added: MFTScreenComponent >> children [
13 Added:
14 Added: ^ {
15 Added: pm header.
16 Added: pm mainNavigationBar.
17 Added: pm activePage.
18 Added: pm footer }
19 Added: ]
20 Added:
21 Added: { #category : 'initialization' }
22 Added: MFTScreenComponent >> initialize [
23 Added:
24 Added: super initialize.
25 Added: pm := self session pageManager
26 Added: ]
27 Added:
28 Added: { #category : 'rendering' }
29 Added: MFTScreenComponent >> renderContentOn: html [
30 Added:
31 Added: (self session user isLoggedIn not and: [
32 Added: MFTUtils isDevelopmentImage not ]) ifTrue: [
33 Added: html render: pm header ].
34 Added: html
35 Added: render: pm mainNavigationBar;
36 Added: render: pm activePage;
37 Added: render: pm footer
38 Added: ]
src/MyFitnessTracker-Components/MFTSecondaryMuscleGroupsDialog.class.st
index 00000000..3d522760 000000..100644
@@ -0,0 +1,65 @@
1 Added: Class {
2 Added: #name : 'MFTSecondaryMuscleGroupsDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'secondaryMuscleGroups'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'initialization' }
13 Added: MFTSecondaryMuscleGroupsDialog >> initialize [
14 Added:
15 Added: super initialize.
16 Added: secondaryMuscleGroups := OrderedCollection new
17 Added: ]
18 Added:
19 Added: { #category : 'rendering' }
20 Added: MFTSecondaryMuscleGroupsDialog >> renderContentOn: html [
21 Added:
22 Added: | allMuscleGroups selectedMuscles |
23 Added: allMuscleGroups := MFTSQLite3Database allMuscleGroups.
24 Added: "selectedMuscles := allMuscles
25 Added: detect: [ :each |
26 Added: each englishName
27 Added: = (secondaryMuscles collect: #englishName) ]
28 Added: ifNone: [ nil ]."
29 Added:
30 Added: self renderDialogOn: html with: [
31 Added: html multiSelect formControl
32 Added: list: allMuscleGroups;
33 Added: "selected: selectedMuscles;"labels: [ :muscleGroup |
34 Added: muscleGroup englishName ];
35 Added: callback: [ :groups |
36 Added: groups ifNotEmpty: [ secondaryMuscleGroups := groups ] ] ]
37 Added: ]
38 Added:
39 Added: { #category : 'rendering' }
40 Added: MFTSecondaryMuscleGroupsDialog >> renderSubmitOn: html [
41 Added:
42 Added: html buttonGroup: [
43 Added: html formButton
44 Added: beSubmit;
45 Added: bePrimary;
46 Added: callback: [ self answer: secondaryMuscleGroups ];
47 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
48 Added: html formButton
49 Added: beSubmit;
50 Added: beSecondary;
51 Added: callback: [ self answer: OrderedCollection new ];
52 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
53 Added: ]
54 Added:
55 Added: { #category : 'accessing' }
56 Added: MFTSecondaryMuscleGroupsDialog >> secondaryMuscleGroups [
57 Added:
58 Added: ^ secondaryMuscleGroups
59 Added: ]
60 Added:
61 Added: { #category : 'accessing' }
62 Added: MFTSecondaryMuscleGroupsDialog >> secondaryMuscleGroups: anObject [
63 Added:
64 Added: secondaryMuscleGroups := anObject
65 Added: ]
src/MyFitnessTracker-Components/MFTSecondaryMuscleGroupsFormComponent.class.st
index 00000000..d65d407d 000000..100644
@@ -0,0 +1,40 @@
1 Added: Class {
2 Added: #name : 'MFTSecondaryMuscleGroupsFormComponent',
3 Added: #superclass : 'MFTFormComponent',
4 Added: #instVars : [
5 Added: 'allMuscleGroups'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Forms',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Forms'
10 Added: }
11 Added:
12 Added: { #category : 'as yet unclassified' }
13 Added: MFTSecondaryMuscleGroupsFormComponent >> getSelectedMuscleGroups [
14 Added:
15 Added: | selectedMuscleGroups |
16 Added: selectedMuscleGroups := allMuscleGroups select: [ :muscleGroup |
17 Added: modelObject secondaryMuscleGroupIds
18 Added: includes: muscleGroup id ].
19 Added: ^ selectedMuscleGroups
20 Added: ]
21 Added:
22 Added: { #category : 'initialization' }
23 Added: MFTSecondaryMuscleGroupsFormComponent >> initialize [
24 Added:
25 Added: super initialize.
26 Added: heading := 'Secondary Groups'.
27 Added: allMuscleGroups := MFTSQLite3Database allMuscleGroups
28 Added: ]
29 Added:
30 Added: { #category : 'rendering' }
31 Added: MFTSecondaryMuscleGroupsFormComponent >> renderContentOn: html [
32 Added:
33 Added: self renderFormComponentOn: html with: [
34 Added: html multiSelect formControl
35 Added: list: allMuscleGroups;
36 Added: selected: self getSelectedMuscleGroups;
37 Added: labels: [ :muscleGroup | muscleGroup englishName ];
38 Added: callback: [ :muscleGroups |
39 Added: modelObject secondaryMuscleGroups: muscleGroups ] ]
40 Added: ]
src/MyFitnessTracker-Components/MFTSetDialog.class.st
index 00000000..77f29c5b 000000..100644
@@ -0,0 +1,10 @@
1 Added: Class {
2 Added: #name : 'MFTSetDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'set'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
src/MyFitnessTracker-Components/MFTSetGroupDialog.class.st
index 00000000..ce2ef60b 000000..100644
@@ -0,0 +1,319 @@
1 Added: Class {
2 Added: #name : 'MFTSetGroupDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'allExercises',
6 Added: 'selectedExercises',
7 Added: 'setGroup'
8 Added: ],
9 Added: #category : 'MyFitnessTracker-Components-Dialogs',
10 Added: #package : 'MyFitnessTracker-Components',
11 Added: #tag : 'Dialogs'
12 Added: }
13 Added:
14 Added: { #category : 'as yet unclassified' }
15 Added: MFTSetGroupDialog >> addSet [
16 Added:
17 Added: | set |
18 Added: set := self call:
19 Added: (MFTSetDialog newForExercise: selectedExercises first).
20 Added: set ifNil: [ ^ self ].
21 Added: setGroup sets ifEmpty: [ setGroup := MFTSetGroup new ].
22 Added: setGroup addSet: (set exercise: selectedExercises first)
23 Added: ]
24 Added:
25 Added: { #category : 'as yet unclassified' }
26 Added: MFTSetGroupDialog >> addSets: aMFTExerciseCollection [
27 Added:
28 Added: | sets |
29 Added: sets := self call:
30 Added: ((MFTSetsDialog newForExercises:
31 Added: aMFTExerciseCollection) subheading:
32 Added: ((selectedExercises collect: #englishName) joinUsing: '/')).
33 Added: sets ifNotEmpty: [ setGroup addSets: sets ]
34 Added: ]
35 Added:
36 Added: { #category : 'as yet unclassified' }
37 Added: MFTSetGroupDialog >> editSet: aMFTSet [
38 Added:
39 Added: | oldSet newSet |
40 Added: oldSet := aMFTSet.
41 Added: newSet := self call:
42 Added: (MFTSetDialog
43 Added: edit: oldSet copy
44 Added: withExercise: selectedExercises first).
45 Added: newSet ifNotNil: [ setGroup updateSet: oldSet with: newSet ]
46 Added: ]
47 Added:
48 Added: { #category : 'as yet unclassified' }
49 Added: MFTSetGroupDialog >> editSets: aMFTSetCollection [
50 Added:
51 Added: | oldSets newSets |
52 Added: oldSets := aMFTSetCollection.
53 Added: newSets := self call:
54 Added: (MFTSetsDialog
55 Added: edit: oldSets copy
56 Added: withExercises: selectedExercises).
57 Added: newSets ifNotEmpty: [ setGroup updateSets: oldSets with: newSets ]
58 Added: ]
59 Added:
60 Added: { #category : 'initialization' }
61 Added: MFTSetGroupDialog >> initialize [
62 Added:
63 Added: super initialize.
64 Added: setGroup := MFTSetGroup new sets:
65 Added: (OrderedCollection with: (MFTSet new reps: 8)).
66 Added: allExercises := MFTSQLite3Database allExercises.
67 Added: selectedExercises := OrderedCollection with: allExercises first
68 Added: ]
69 Added:
70 Added: { #category : 'as yet unclassified' }
71 Added: MFTSetGroupDialog >> makeGiantSet [
72 Added:
73 Added: self heading: 'Giant Sets'.
74 Added: selectedExercises := OrderedCollection withAll:
75 Added: (allExercises copyFrom: 1 to: 5).
76 Added: self populateSetsForExercises: selectedExercises
77 Added: ]
78 Added:
79 Added: { #category : 'as yet unclassified' }
80 Added: MFTSetGroupDialog >> makeRegularExercise [
81 Added:
82 Added: self heading: 'Sets'.
83 Added: selectedExercises := OrderedCollection with: allExercises first.
84 Added: self populateSetsForExercises: selectedExercises
85 Added: ]
86 Added:
87 Added: { #category : 'as yet unclassified' }
88 Added: MFTSetGroupDialog >> makeSuperset [
89 Added:
90 Added: self heading: 'Supersets'.
91 Added: selectedExercises := OrderedCollection
92 Added: with: allExercises first
93 Added: with: allExercises second.
94 Added: self populateSetsForExercises: selectedExercises
95 Added: ]
96 Added:
97 Added: { #category : 'as yet unclassified' }
98 Added: MFTSetGroupDialog >> makeTriset [
99 Added:
100 Added: self heading: 'Tri-sets'.
101 Added: selectedExercises := OrderedCollection
102 Added: with: allExercises first
103 Added: with: allExercises second
104 Added: with: allExercises third.
105 Added: self populateSetsForExercises: selectedExercises
106 Added: ]
107 Added:
108 Added: { #category : 'as yet unclassified' }
109 Added: MFTSetGroupDialog >> populateSetsForExercises: aMFTExerciseCollection [
110 Added:
111 Added: setGroup := MFTSetGroup new sets:
112 Added: (aMFTExerciseCollection collect: [ :exercise |
113 Added: MFTSet new
114 Added: reps: 8;
115 Added: exercise: exercise ])
116 Added: ]
117 Added:
118 Added: { #category : 'as yet unclassified' }
119 Added: MFTSetGroupDialog >> renderConfigureSetGroupButtonsOn: html [
120 Added:
121 Added: selectedExercises size = 1
122 Added: ifTrue: [
123 Added: html outlineButton bePrimary beSmall
124 Added: class: 'me-2';
125 Added: callback: [ self addSet ];
126 Added: with: 'Add set' ]
127 Added: ifFalse: [
128 Added: html outlineButton bePrimary beSmall
129 Added: class: 'me-2';
130 Added: callback: [ self addSets: selectedExercises ];
131 Added: with: 'Add set group' ].
132 Added: html buttonGroup: [
133 Added: selectedExercises size ~~ 1 ifTrue: [
134 Added: html outlineButton beSecondary beSmall
135 Added: callback: [ self makeRegularExercise ];
136 Added: with: 'Regular exercise' ].
137 Added: selectedExercises size ~~ 2 ifTrue: [
138 Added: html outlineButton beSecondary beSmall
139 Added: callback: [ self makeSuperset ];
140 Added: with: 'Superset' ].
141 Added: selectedExercises size ~~ 3 ifTrue: [
142 Added: html outlineButton beSecondary beSmall
143 Added: callback: [ self makeTriset ];
144 Added: with: 'Tri-set' ].
145 Added: selectedExercises size < 4 ifTrue: [
146 Added: html outlineButton beSecondary beSmall
147 Added: callback: [ self makeGiantSet ];
148 Added: with: 'Giant set' ] ]
149 Added: ]
150 Added:
151 Added: { #category : 'rendering' }
152 Added: MFTSetGroupDialog >> renderContentOn: html [
153 Added:
154 Added: self renderDialogOn: html with: [
155 Added: self renderSelectExercisesOn: html.
156 Added: html horizontalRule.
157 Added: setGroup sets ifNotEmpty: [ self renderSetGroupTableOn: html ].
158 Added: self renderConfigureSetGroupButtonsOn: html ]
159 Added: ]
160 Added:
161 Added: { #category : 'as yet unclassified' }
162 Added: MFTSetGroupDialog >> renderSelectExercisesOn: html [
163 Added:
164 Added: | allSets |
165 Added: allSets := setGroup sets.
166 Added: selectedExercises doWithIndex: [ :selectedExercise :i |
167 Added: html formGroup: [
168 Added: html label: 'Exercise ' , (selectedExercises size > 1
169 Added: ifTrue: [ i asString ]
170 Added: ifFalse: [ '' ]).
171 Added: html select formControl
172 Added: list: allExercises;
173 Added: selected: selectedExercise;
174 Added: callback: [ :exercise |
175 Added: selectedExercises at: i put: exercise.
176 Added: self updateAllSelectedExercises ];
177 Added: labels: [ :each | each englishName ] ] ]
178 Added: ]
179 Added:
180 Added: { #category : 'rendering' }
181 Added: MFTSetGroupDialog >> renderSetGroupRowsOn: html [
182 Added:
183 Added: setGroup sets doWithIndex: [ :set :i |
184 Added: (i - 1 isDivisibleBy: selectedExercises size) ifTrue: [
185 Added: | selectedSets |
186 Added: selectedSets := setGroup sets atAll:
187 Added: (i to: i + selectedExercises size - 1).
188 Added: html tableRow with: [
189 Added: html tableData
190 Added: attributeAt: 'rowspan' put: selectedExercises size + 1;
191 Added: style: 'vertical-align: middle';
192 Added: with: [
193 Added: html buttonGroup: [
194 Added: html outlineButton
195 Added: beDanger;
196 Added: beSmall;
197 Added: callback: [ setGroup removeSets: selectedSets ];
198 Added: with: 'Remove'.
199 Added: html outlineButton
200 Added: beSecondary;
201 Added: beSmall;
202 Added: callback: [
203 Added: selectedSets size = 1
204 Added: ifTrue: [ self editSet: selectedSets first ]
205 Added: ifFalse: [ self editSets: selectedSets ] ];
206 Added: with: 'Edit'.
207 Added: selectedExercises size = 1 ifTrue: [
208 Added: html outlineButton
209 Added: beSecondary;
210 Added: beSmall;
211 Added: callback: [ setGroup duplicateSet: selectedSets first ];
212 Added: with: 'Duplicate' ] ] ] ] ].
213 Added:
214 Added: html tableRow: [ "This row spans the amount of sets for a given exercise."
215 Added: setGroup isIrregularSetGroup ifTrue: [
216 Added: html tableData with: set exercise englishName capitalized ].
217 Added: html tableData
218 Added: style: 'text-align: right';
219 Added: with: set reps.
220 Added: setGroup hasLoad ifTrue: [
221 Added: html tableData
222 Added: style: 'text-align: right';
223 Added: with: set load ].
224 Added: setGroup hasRpe ifTrue: [
225 Added: html tableData
226 Added: style: 'text-align: right';
227 Added: with: set rpe ].
228 Added: setGroup hasRestAfter ifTrue: [
229 Added: html tableData
230 Added: style: 'text-align: right';
231 Added: with: set restAfter ] ] ]
232 Added: ]
233 Added:
234 Added: { #category : 'rendering' }
235 Added: MFTSetGroupDialog >> renderSetGroupTableHeaderOn: html [
236 Added:
237 Added: html tableHead: [
238 Added: html tableHeading.
239 Added: setGroup isIrregularSetGroup ifTrue: [
240 Added: html tableHeading with: 'Exercise' ].
241 Added: html tableHeading
242 Added: style: 'text-align: right';
243 Added: with: 'Reps'.
244 Added: setGroup hasLoad ifTrue: [
245 Added: html tableHeading
246 Added: style: 'text-align: right';
247 Added: with: 'Load' ].
248 Added: setGroup hasRpe ifTrue: [
249 Added: html tableHeading
250 Added: style: 'text-align: right';
251 Added: with: 'RPE' ].
252 Added: setGroup hasRestAfter ifTrue: [
253 Added: html tableHeading
254 Added: style: 'text-align: right';
255 Added: with: 'Rest After (s)' ] ]
256 Added: ]
257 Added:
258 Added: { #category : 'rendering' }
259 Added: MFTSetGroupDialog >> renderSetGroupTableOn: html [
260 Added:
261 Added: html table
262 Added: class: 'table table-bordered';
263 Added: with: [
264 Added: self renderSetGroupTableHeaderOn: html.
265 Added: self renderSetGroupRowsOn: html ]
266 Added: ]
267 Added:
268 Added: { #category : 'as yet unclassified' }
269 Added: MFTSetGroupDialog >> renderSubmitOn: html [
270 Added:
271 Added: html buttonGroup: [
272 Added: html formButton
273 Added: beSubmit;
274 Added: bePrimary;
275 Added: callback: [ self answer: setGroup ];
276 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
277 Added: html formButton
278 Added: beSubmit;
279 Added: beSecondary;
280 Added: callback: [ self answer: nil ];
281 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
282 Added: ]
283 Added:
284 Added: { #category : 'as yet unclassified' }
285 Added: MFTSetGroupDialog >> selectedExercises [
286 Added:
287 Added: ^ selectedExercises
288 Added: ]
289 Added:
290 Added: { #category : 'as yet unclassified' }
291 Added: MFTSetGroupDialog >> selectedExercises: aMFTExerciseCollection [
292 Added:
293 Added: selectedExercises := aMFTExerciseCollection
294 Added: ]
295 Added:
296 Added: { #category : 'as yet unclassified' }
297 Added: MFTSetGroupDialog >> setGroup [
298 Added:
299 Added: ^ setGroup
300 Added: ]
301 Added:
302 Added: { #category : 'as yet unclassified' }
303 Added: MFTSetGroupDialog >> setGroup: anObject [
304 Added:
305 Added: setGroup := anObject
306 Added: ]
307 Added:
308 Added: { #category : 'as yet unclassified' }
309 Added: MFTSetGroupDialog >> updateAllSelectedExercises [
310 Added:
311 Added: | allSets |
312 Added: allSets := setGroup sets.
313 Added: selectedExercises doWithIndex: [ :selectedExercise :i |
314 Added: i to: allSets size by: selectedExercises size do: [ :j |
315 Added: | set |
316 Added: "Update every nth set to reflect the newly selected exercise selectedExercises at: i."
317 Added: set := allSets at: j.
318 Added: set exercise: selectedExercise ] ]
319 Added: ]
src/MyFitnessTracker-Components/MFTSetGroupForm.class.st
index 00000000..8359356f 000000..100644
@@ -0,0 +1,144 @@
1 Added: Class {
2 Added: #name : 'MFTSetGroupForm',
3 Added: #superclass : 'MFTForm',
4 Added: #instVars : [
5 Added: 'exerciseCount',
6 Added: 'renderRpe',
7 Added: 'renderRestAfter'
8 Added: ],
9 Added: #category : 'MyFitnessTracker-Components-Forms',
10 Added: #package : 'MyFitnessTracker-Components',
11 Added: #tag : 'Forms'
12 Added: }
13 Added:
14 Added: { #category : 'as yet unclassified' }
15 Added: MFTSetGroupForm class >> forExercises: anMFTExerciseCollection [
16 Added:
17 Added: | setGroup |
18 Added: setGroup := MFTSetGroup new addSets:
19 Added: (anMFTExerciseCollection collect: [ :exercise |
20 Added: MFTSet new
21 Added: exercise: exercise;
22 Added: reps: 8 ]).
23 Added: ^ self new
24 Added: modelObject: setGroup;
25 Added: exerciseCount: anMFTExerciseCollection size;
26 Added: yourself
27 Added: ]
28 Added:
29 Added: { #category : 'accessing' }
30 Added: MFTSetGroupForm >> exerciseCount: anInteger [
31 Added:
32 Added: exerciseCount := anInteger
33 Added: ]
34 Added:
35 Added: { #category : 'initialization' }
36 Added: MFTSetGroupForm >> initialize [
37 Added:
38 Added: super initialize.
39 Added: modelObject := MFTSetGroup new addSet: (MFTSet new reps: 8).
40 Added: heading := 'Sets'.
41 Added: renderRpe := false.
42 Added: renderRestAfter := false
43 Added: ]
44 Added:
45 Added: { #category : 'rendering' }
46 Added: MFTSetGroupForm >> renderContentOn: html [
47 Added:
48 Added: self renderFormOn: html with: [
49 Added: self renderSetsButtonGroupOn: html.
50 Added: self renderSetGroupTableOn: html ]
51 Added: ]
52 Added:
53 Added: { #category : 'rendering' }
54 Added: MFTSetGroupForm >> renderSetGroupRowsOn: html [
55 Added:
56 Added: | selectedExercises renderSetGroupExercisesName |
57 Added: selectedExercises := modelObject sets collect: #exercise.
58 Added: renderSetGroupExercisesName := modelObject isIrregularSetGroup.
59 Added:
60 Added: modelObject sets do: [ :set |
61 Added: html tableRow: [
62 Added: renderSetGroupExercisesName ifTrue: [
63 Added: html tableData with: set exercise englishName capitalized ].
64 Added: html tableData: [
65 Added: html numberInput formControl
66 Added: value: set reps;
67 Added: callback: [ :value | set reps: value asInteger ] ].
68 Added: html tableData: [
69 Added: html numberInput formControl
70 Added: value: set load;
71 Added: callback: [ :value |
72 Added: set load:
73 Added: (value ifNotEmpty: [ value asNumber ] ifEmpty: [ nil ]) ] ].
74 Added: renderRpe ifTrue: [
75 Added: html tableData: [
76 Added: html numberInput formControl
77 Added: value: set rpe;
78 Added: callback: [ :value |
79 Added: set rpe:
80 Added: (value ifNotEmpty: [ value asInteger ] ifEmpty: [ nil ]) ] ] ].
81 Added: renderRestAfter ifTrue: [
82 Added: html tableData: [
83 Added: html numberInput formControl
84 Added: value: set restAfter;
85 Added: callback: [ :value |
86 Added: set restAfter:
87 Added: (value ifNotEmpty: [ value asNumber ] ifEmpty: [ nil ]) ] ] ] ] ]
88 Added: ]
89 Added:
90 Added: { #category : 'rendering' }
91 Added: MFTSetGroupForm >> renderSetGroupTableHeaderOn: html [
92 Added:
93 Added: html tableHead: [
94 Added: modelObject isIrregularSetGroup ifTrue: [
95 Added: html tableHeading with: 'Exercise' ].
96 Added: html tableHeading with: 'Reps'.
97 Added: html tableHeading with: 'Load'.
98 Added: renderRpe ifTrue: [ html tableHeading with: 'RPE' ].
99 Added: renderRestAfter ifTrue: [ html tableHeading with: 'Rest After (s)' ] ]
100 Added: ]
101 Added:
102 Added: { #category : 'rendering' }
103 Added: MFTSetGroupForm >> renderSetGroupTableOn: html [
104 Added:
105 Added: html table
106 Added: class: 'table table-bordered';
107 Added: with: [
108 Added: self renderSetGroupTableHeaderOn: html.
109 Added: self renderSetGroupRowsOn: html ]
110 Added: ]
111 Added:
112 Added: { #category : 'rendering' }
113 Added: MFTSetGroupForm >> renderSetsButtonGroupOn: html [
114 Added:
115 Added: html buttonGroup
116 Added: class: 'my-3';
117 Added: with: [
118 Added: html outlineButton
119 Added: bePrimary;
120 Added: beSmall;
121 Added: callback: [ modelObject addSets: modelObject sets ];
122 Added: with: 'Add sets'.
123 Added: renderRpe ifFalse: [
124 Added: html outlineButton
125 Added: beSecondary;
126 Added: beSmall;
127 Added: callback: [ renderRpe := true ];
128 Added: with: 'Add RPE' ].
129 Added: renderRestAfter ifFalse: [
130 Added: html outlineButton
131 Added: beSecondary;
132 Added: beSmall;
133 Added: callback: [ renderRestAfter := true ];
134 Added: with: 'Add rest' ].
135 Added: html outlineButton
136 Added: beDanger;
137 Added: beSmall;
138 Added: callback: [
139 Added: | firstSets |
140 Added: firstSets := modelObject sets first: exerciseCount.
141 Added: modelObject := MFTSetGroup new addSets: firstSets.
142 Added: renderRpe := renderRestAfter := false ];
143 Added: with: 'Reset' ]
144 Added: ]
src/MyFitnessTracker-Components/MFTSetGroupTask.class.st
index 00000000..d9dc5c55 000000..100644
@@ -0,0 +1,63 @@
1 Added: Class {
2 Added: #name : 'MFTSetGroupTask',
3 Added: #superclass : 'WATask',
4 Added: #instVars : [
5 Added: 'exercises',
6 Added: 'exerciseCount',
7 Added: 'setGroup'
8 Added: ],
9 Added: #category : 'MyFitnessTracker-Components-Tasks',
10 Added: #package : 'MyFitnessTracker-Components',
11 Added: #tag : 'Tasks'
12 Added: }
13 Added:
14 Added: { #category : 'as yet unclassified' }
15 Added: MFTSetGroupTask class >> forExerciseCount: anInteger [
16 Added:
17 Added: ^ self new
18 Added: exerciseCount: anInteger;
19 Added: yourself
20 Added: ]
21 Added:
22 Added: { #category : 'accessing' }
23 Added: MFTSetGroupTask >> exerciseCount: anObject [
24 Added:
25 Added: exerciseCount := anObject
26 Added: ]
27 Added:
28 Added: { #category : 'accessing' }
29 Added: MFTSetGroupTask >> exercises [
30 Added:
31 Added: ^ exercises
32 Added: ]
33 Added:
34 Added: { #category : 'accessing' }
35 Added: MFTSetGroupTask >> exercises: anObject [
36 Added:
37 Added: exercises := anObject
38 Added: ]
39 Added:
40 Added: { #category : 'running' }
41 Added: MFTSetGroupTask >> go [
42 Added:
43 Added: exercises := self call:
44 Added: (MFTExercisesForm forExerciseCount: exerciseCount).
45 Added: exercises ifNil: [ self answer: nil ].
46 Added:
47 Added: setGroup := self call: (MFTSetGroupForm forExercises: exercises).
48 Added: setGroup ifNil: [ self answer: nil ].
49 Added:
50 Added: self answer: setGroup
51 Added: ]
52 Added:
53 Added: { #category : 'accessing' }
54 Added: MFTSetGroupTask >> setGroups [
55 Added:
56 Added: ^ setGroups
57 Added: ]
58 Added:
59 Added: { #category : 'accessing' }
60 Added: MFTSetGroupTask >> setGroups: anObject [
61 Added:
62 Added: setGroups := anObject
63 Added: ]
src/MyFitnessTracker-Components/MFTSetGroupsDialog.class.st
index 00000000..32043db5 000000..100644
@@ -0,0 +1,179 @@
1 Added: Class {
2 Added: #name : 'MFTSetGroupsDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'setGroups'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'as yet unclassified' }
13 Added: MFTSetGroupsDialog >> addExercise [
14 Added:
15 Added: | setGroup |
16 Added: setGroup := self call: (MFTSetGroupDialog new heading: 'Exercise').
17 Added: setGroup ifNotNil: [ setGroups add: setGroup ]
18 Added: ]
19 Added:
20 Added: { #category : 'as yet unclassified' }
21 Added: MFTSetGroupsDialog >> editSetGroup: aMFTSetGroup [
22 Added:
23 Added: | oldSetGroup newSetGroup |
24 Added: oldSetGroup := aMFTSetGroup.
25 Added: newSetGroup := self call: (MFTSetGroupDialog edit: aMFTSetGroup copy).
26 Added: newSetGroup ifNotNil: [
27 Added: setGroups at: (setGroups indexOf: oldSetGroup) put: newSetGroup ]
28 Added: ]
29 Added:
30 Added: { #category : 'as yet unclassified' }
31 Added: MFTSetGroupsDialog >> initialize [
32 Added:
33 Added: super initialize.
34 Added: setGroups := OrderedCollection new
35 Added: ]
36 Added:
37 Added: { #category : 'as yet unclassified' }
38 Added: MFTSetGroupsDialog >> renderAddSetGroupButtonsOn: html [
39 Added:
40 Added: html outlineButton
41 Added: bePrimary;
42 Added: beSmall;
43 Added: callback: [ self addExercise ];
44 Added: with: 'Add exercise'
45 Added: ]
46 Added:
47 Added: { #category : 'as yet unclassified' }
48 Added: MFTSetGroupsDialog >> renderContentOn: html [
49 Added:
50 Added: self renderDialogOn: html with: [
51 Added: setGroups ifNotEmpty: [ self renderSetsTableOn: html ].
52 Added: self renderAddSetGroupButtonsOn: html ]
53 Added: ]
54 Added:
55 Added: { #category : 'as yet unclassified' }
56 Added: MFTSetGroupsDialog >> renderLoad [
57 Added:
58 Added: ^ (setGroups flatCollect: #sets) anySatisfy: #hasLoad
59 Added: ]
60 Added:
61 Added: { #category : 'as yet unclassified' }
62 Added: MFTSetGroupsDialog >> renderRestAfter [
63 Added:
64 Added: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRestAfter
65 Added: ]
66 Added:
67 Added: { #category : 'as yet unclassified' }
68 Added: MFTSetGroupsDialog >> renderRpe [
69 Added:
70 Added: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRpe
71 Added: ]
72 Added:
73 Added: { #category : 'as yet unclassified' }
74 Added: MFTSetGroupsDialog >> renderSetGroupButtonsOn: html For: setGroup [
75 Added:
76 Added: html buttonGroup: [
77 Added: html outlineButton
78 Added: beDanger;
79 Added: beSmall;
80 Added: callback: [ setGroups remove: setGroup ];
81 Added: with: 'Remove'.
82 Added: html outlineButton
83 Added: beSecondary;
84 Added: beSmall;
85 Added: callback: [ self editSetGroup: setGroup ];
86 Added: with: 'Edit'.
87 Added: html outlineButton
88 Added: beSecondary;
89 Added: beSmall;
90 Added: callback: [
91 Added: setGroups add: setGroup afterIndex: (setGroups indexOf: setGroup) ];
92 Added: with: 'Duplicate' ]
93 Added: ]
94 Added:
95 Added: { #category : 'as yet unclassified' }
96 Added: MFTSetGroupsDialog >> renderSetGroupsRowsOn: html [
97 Added:
98 Added: | renderLoad renderRpe renderRestAfter |
99 Added: renderLoad := self renderLoad.
100 Added: renderRpe := self renderRpe.
101 Added: renderRestAfter := self renderRestAfter.
102 Added: setGroups do: [ :setGroup |
103 Added: html tableRow with: [
104 Added: html tableData
105 Added: attributeAt: 'rowspan' put: setGroup sets size + 1;
106 Added: style: 'vertical-align: middle';
107 Added: with: [ self renderSetGroupButtonsOn: html For: setGroup ] ].
108 Added: setGroup sets do: [ :set |
109 Added: html tableRow: [
110 Added: html tableData: set exercise englishName.
111 Added: html tableData: set reps.
112 Added: setGroup hasLoad ifTrue: [ html tableData: set load ].
113 Added: setGroup hasRpe ifTrue: [ html tableData: set rpe ].
114 Added: setGroup hasRestAfter ifTrue: [ html tableData: set restAfter ] ] ] ]
115 Added: ]
116 Added:
117 Added: { #category : 'as yet unclassified' }
118 Added: MFTSetGroupsDialog >> renderSetGroupsTableHeaderOn: html [
119 Added:
120 Added: html tableHead: [
121 Added: html
122 Added: tableHeading;
123 Added: tableHeading: 'Exercise';
124 Added: tableHeading: 'Reps'.
125 Added: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
126 Added: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
127 Added: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
128 Added: ]
129 Added:
130 Added: { #category : 'as yet unclassified' }
131 Added: MFTSetGroupsDialog >> renderSetsTableHeaderOn: html [
132 Added:
133 Added: html tableHead: [
134 Added: html
135 Added: tableHeading;
136 Added: tableHeading: 'Exercise';
137 Added: tableHeading: 'Reps'.
138 Added: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
139 Added: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
140 Added: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
141 Added: ]
142 Added:
143 Added: { #category : 'as yet unclassified' }
144 Added: MFTSetGroupsDialog >> renderSetsTableOn: html [
145 Added:
146 Added: html table
147 Added: class: 'table table-bordered';
148 Added: with: [
149 Added: self renderSetGroupsTableHeaderOn: html.
150 Added: self renderSetGroupsRowsOn: html ]
151 Added: ]
152 Added:
153 Added: { #category : 'as yet unclassified' }
154 Added: MFTSetGroupsDialog >> renderSubmitOn: html [
155 Added:
156 Added: html buttonGroup: [
157 Added: html formButton
158 Added: beSubmit;
159 Added: bePrimary;
160 Added: callback: [ self answer: setGroups ];
161 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
162 Added: html formButton
163 Added: beSubmit;
164 Added: beSecondary;
165 Added: callback: [ self answer: OrderedCollection new ];
166 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
167 Added: ]
168 Added:
169 Added: { #category : 'as yet unclassified' }
170 Added: MFTSetGroupsDialog >> setGroups [
171 Added:
172 Added: ^ setGroups
173 Added: ]
174 Added:
175 Added: { #category : 'as yet unclassified' }
176 Added: MFTSetGroupsDialog >> setGroups: anObject [
177 Added:
178 Added: setGroups := anObject
179 Added: ]
src/MyFitnessTracker-Components/MFTSetGroupsDialogOld.class.st
index 00000000..69878181 000000..100644
@@ -0,0 +1,179 @@
1 Added: Class {
2 Added: #name : 'MFTSetGroupsDialogOld',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'setGroups'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'adding' }
13 Added: MFTSetGroupsDialogOld >> addExercise [
14 Added:
15 Added: | setGroup |
16 Added: setGroup := self call: (MFTSetGroupDialog new heading: 'Exercise').
17 Added: setGroup ifNotNil: [ setGroups add: setGroup ]
18 Added: ]
19 Added:
20 Added: { #category : 'rendering' }
21 Added: MFTSetGroupsDialogOld >> editSetGroup: aMFTSetGroup [
22 Added:
23 Added: | oldSetGroup newSetGroup |
24 Added: oldSetGroup := aMFTSetGroup.
25 Added: newSetGroup := self call: (MFTSetGroupDialog edit: aMFTSetGroup copy).
26 Added: newSetGroup ifNotNil: [
27 Added: setGroups at: (setGroups indexOf: oldSetGroup) put: newSetGroup ]
28 Added: ]
29 Added:
30 Added: { #category : 'initialization' }
31 Added: MFTSetGroupsDialogOld >> initialize [
32 Added:
33 Added: super initialize.
34 Added: setGroups := OrderedCollection new
35 Added: ]
36 Added:
37 Added: { #category : 'rendering' }
38 Added: MFTSetGroupsDialogOld >> renderAddSetGroupButtonsOn: html [
39 Added:
40 Added: html outlineButton
41 Added: bePrimary;
42 Added: beSmall;
43 Added: callback: [ self addExercise ];
44 Added: with: 'Add exercise'
45 Added: ]
46 Added:
47 Added: { #category : 'rendering' }
48 Added: MFTSetGroupsDialogOld >> renderContentOn: html [
49 Added:
50 Added: self renderDialogOn: html with: [
51 Added: setGroups ifNotEmpty: [ self renderSetsTableOn: html ].
52 Added: self renderAddSetGroupButtonsOn: html ]
53 Added: ]
54 Added:
55 Added: { #category : 'as yet unclassified' }
56 Added: MFTSetGroupsDialogOld >> renderLoad [
57 Added:
58 Added: ^ (setGroups flatCollect: #sets) anySatisfy: #hasLoad
59 Added: ]
60 Added:
61 Added: { #category : 'as yet unclassified' }
62 Added: MFTSetGroupsDialogOld >> renderRestAfter [
63 Added:
64 Added: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRestAfter
65 Added: ]
66 Added:
67 Added: { #category : 'as yet unclassified' }
68 Added: MFTSetGroupsDialogOld >> renderRpe [
69 Added:
70 Added: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRpe
71 Added: ]
72 Added:
73 Added: { #category : 'as yet unclassified' }
74 Added: MFTSetGroupsDialogOld >> renderSetGroupButtonsOn: html For: setGroup [
75 Added:
76 Added: html buttonGroup: [
77 Added: html outlineButton
78 Added: beDanger;
79 Added: beSmall;
80 Added: callback: [ setGroups remove: setGroup ];
81 Added: with: 'Remove'.
82 Added: html outlineButton
83 Added: beSecondary;
84 Added: beSmall;
85 Added: callback: [ self editSetGroup: setGroup ];
86 Added: with: 'Edit'.
87 Added: html outlineButton
88 Added: beSecondary;
89 Added: beSmall;
90 Added: callback: [
91 Added: setGroups add: setGroup afterIndex: (setGroups indexOf: setGroup) ];
92 Added: with: 'Duplicate' ]
93 Added: ]
94 Added:
95 Added: { #category : 'as yet unclassified' }
96 Added: MFTSetGroupsDialogOld >> renderSetGroupsRowsOn: html [
97 Added:
98 Added: | renderLoad renderRpe renderRestAfter |
99 Added: renderLoad := self renderLoad.
100 Added: renderRpe := self renderRpe.
101 Added: renderRestAfter := self renderRestAfter.
102 Added: setGroups do: [ :setGroup |
103 Added: html tableRow with: [
104 Added: html tableData
105 Added: attributeAt: 'rowspan' put: setGroup sets size + 1;
106 Added: style: 'vertical-align: middle';
107 Added: with: [ self renderSetGroupButtonsOn: html For: setGroup ] ].
108 Added: setGroup sets do: [ :set |
109 Added: html tableRow: [
110 Added: html tableData: set exercise englishName.
111 Added: html tableData: set reps.
112 Added: setGroup hasLoad ifTrue: [ html tableData: set load ].
113 Added: setGroup hasRpe ifTrue: [ html tableData: set rpe ].
114 Added: setGroup hasRestAfter ifTrue: [ html tableData: set restAfter ] ] ] ]
115 Added: ]
116 Added:
117 Added: { #category : 'as yet unclassified' }
118 Added: MFTSetGroupsDialogOld >> renderSetGroupsTableHeaderOn: html [
119 Added:
120 Added: html tableHead: [
121 Added: html
122 Added: tableHeading;
123 Added: tableHeading: 'Exercise';
124 Added: tableHeading: 'Reps'.
125 Added: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
126 Added: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
127 Added: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
128 Added: ]
129 Added:
130 Added: { #category : 'as yet unclassified' }
131 Added: MFTSetGroupsDialogOld >> renderSetsTableHeaderOn: html [
132 Added:
133 Added: html tableHead: [
134 Added: html
135 Added: tableHeading;
136 Added: tableHeading: 'Exercise';
137 Added: tableHeading: 'Reps'.
138 Added: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
139 Added: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
140 Added: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
141 Added: ]
142 Added:
143 Added: { #category : 'as yet unclassified' }
144 Added: MFTSetGroupsDialogOld >> renderSetsTableOn: html [
145 Added:
146 Added: html table
147 Added: class: 'table table-bordered';
148 Added: with: [
149 Added: self renderSetGroupsTableHeaderOn: html.
150 Added: self renderSetGroupsRowsOn: html ]
151 Added: ]
152 Added:
153 Added: { #category : 'rendering' }
154 Added: MFTSetGroupsDialogOld >> renderSubmitOn: html [
155 Added:
156 Added: html buttonGroup: [
157 Added: html formButton
158 Added: beSubmit;
159 Added: bePrimary;
160 Added: callback: [ self answer: setGroups ];
161 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
162 Added: html formButton
163 Added: beSubmit;
164 Added: beSecondary;
165 Added: callback: [ self answer: OrderedCollection new ];
166 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
167 Added: ]
168 Added:
169 Added: { #category : 'accessing' }
170 Added: MFTSetGroupsDialogOld >> setGroups [
171 Added:
172 Added: ^ setGroups
173 Added: ]
174 Added:
175 Added: { #category : 'accessing' }
176 Added: MFTSetGroupsDialogOld >> setGroups: anObject [
177 Added:
178 Added: setGroups := anObject
179 Added: ]
src/MyFitnessTracker-Components/MFTSetGroupsFormComponent.class.st
index 00000000..e9b3b197 000000..100644
@@ -0,0 +1,62 @@
1 Added: Class {
2 Added: #name : 'MFTSetGroupsFormComponent',
3 Added: #superclass : 'MFTFormComponent',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'adding' }
10 Added: MFTSetGroupsFormComponent >> addSetGroupsForExerciseCount: anInteger [
11 Added:
12 Added: | setGroup |
13 Added: setGroup := self session pageManager activePage call:
14 Added: (MFTSetGroupTask forExerciseCount: anInteger).
15 Added: setGroup ifNotNil: [ modelObject addSetGroup: setGroup ]
16 Added: ]
17 Added:
18 Added: { #category : 'initialization' }
19 Added: MFTSetGroupsFormComponent >> initialize [
20 Added:
21 Added: super initialize.
22 Added: heading := 'Exercises'
23 Added: ]
24 Added:
25 Added: { #category : 'rendering' }
26 Added: MFTSetGroupsFormComponent >> renderContentOn: html [
27 Added:
28 Added: self renderFormComponentOn: html with: [
29 Added: modelObject renderSetGroupsTableOn: html.
30 Added: self renderSetGroupButtonsOn: html ]
31 Added: ]
32 Added:
33 Added: { #category : 'rendering' }
34 Added: MFTSetGroupsFormComponent >> renderSetGroupButtonsOn: html [
35 Added:
36 Added: html buttonGroup: [
37 Added: html outlineButton
38 Added: bePrimary;
39 Added: beSmall;
40 Added: callback: [ self addSetGroupsForExerciseCount: 1 ];
41 Added: with: 'Add exercise'.
42 Added: html outlineButton
43 Added: beSecondary;
44 Added: beSmall;
45 Added: callback: [ self addSetGroupsForExerciseCount: 2 ];
46 Added: with: 'Add superset'.
47 Added: html outlineButton
48 Added: beSecondary;
49 Added: beSmall;
50 Added: callback: [ self addSetGroupsForExerciseCount: 3 ];
51 Added: with: 'Add tri-set'.
52 Added: html outlineButton
53 Added: beSecondary;
54 Added: beSmall;
55 Added: callback: [ self addSetGroupsForExerciseCount: 4 ];
56 Added: with: 'Add giant set'.
57 Added: html outlineButton
58 Added: beDanger;
59 Added: beSmall;
60 Added: callback: [ modelObject setGroups removeAll ];
61 Added: with: 'Remove all' ]
62 Added: ]
src/MyFitnessTracker-Components/MFTSetsDialog.class.st
index 00000000..6b45701e 000000..100644
@@ -0,0 +1,10 @@
1 Added: Class {
2 Added: #name : 'MFTSetsDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'sets'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
src/MyFitnessTracker-Components/MFTStringDialog.class.st
index 00000000..bdd1863b 000000..100644
@@ -0,0 +1,58 @@
1 Added: Class {
2 Added: #name : 'MFTStringDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'string'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'as yet unclassified' }
13 Added: MFTStringDialog class >> edit: aString [
14 Added:
15 Added: ^ self new
16 Added: action: #edit;
17 Added: string: aString;
18 Added: yourself
19 Added: ]
20 Added:
21 Added: { #category : 'as yet unclassified' }
22 Added: MFTStringDialog >> initialize [
23 Added:
24 Added: super initialize.
25 Added: string := String new
26 Added: ]
27 Added:
28 Added: { #category : 'as yet unclassified' }
29 Added: MFTStringDialog >> renderContentOn: html [
30 Added:
31 Added: self renderDialogOn: html with: [
32 Added: html textInput formControl
33 Added: value: string;
34 Added: callback: [ :value | string := value ] ]
35 Added: ]
36 Added:
37 Added: { #category : 'as yet unclassified' }
38 Added: MFTStringDialog >> renderSubmitOn: html [
39 Added:
40 Added: html buttonGroup: [
41 Added: html formButton
42 Added: beSubmit;
43 Added: bePrimary;
44 Added: callback: [ self answer: string ];
45 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]) ]
46 Added: ]
47 Added:
48 Added: { #category : 'as yet unclassified' }
49 Added: MFTStringDialog >> string [
50 Added:
51 Added: ^ string
52 Added: ]
53 Added:
54 Added: { #category : 'as yet unclassified' }
55 Added: MFTStringDialog >> string: anObject [
56 Added:
57 Added: string := anObject
58 Added: ]
src/MyFitnessTracker-Components/MFTUserForm.class.st
index 00000000..cb0fff5c 000000..100644
@@ -0,0 +1,45 @@
1 Added: Class {
2 Added: #name : 'MFTUserForm',
3 Added: #superclass : 'MFTForm',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTUserForm class >> edit: aMFTWorkout [
11 Added:
12 Added: ^ self new
13 Added: modelObject: aMFTWorkout;
14 Added: yourself
15 Added: ]
16 Added:
17 Added: { #category : 'initialization' }
18 Added: MFTUserForm >> initialize [
19 Added:
20 Added: super initialize.
21 Added: modelObject := MFTWorkout new.
22 Added: heading := 'Workout'
23 Added: ]
24 Added:
25 Added: { #category : 'rendering' }
26 Added: MFTUserForm >> renderContentOn: html [
27 Added:
28 Added: self renderFormOn: html with: [
29 Added: html
30 Added: render: (MFTFormComponent set: #date);
31 Added: render: (MFTFormComponent set: #setGroups);
32 Added: render: (MFTFormComponent set: #primaryMuscleGroup);
33 Added: render: (MFTFormComponent set: #secondaryMuscleGroups) ]
34 Added: ]
35 Added:
36 Added: { #category : 'as yet unclassified' }
37 Added: MFTUserForm >> submitForm [
38 Added:
39 Added: modelObject setGroups ifEmpty: [
40 Added: (self call:
41 Added: (MFTConfirmForm new modelObject: 'No exercises were specified.'))
42 Added: ifFalse: [ self answer: nil ] ].
43 Added:
44 Added: self answer: modelObject
45 Added: ]
src/MyFitnessTracker-Components/MFTUserLandingPage.class.st
index 00000000..e8f549af 000000..100644
@@ -0,0 +1,15 @@
1 Added: Class {
2 Added: #name : 'MFTUserLandingPage',
3 Added: #superclass : 'MFTLandingPage',
4 Added: #category : 'MyFitnessTracker-Components-Pages',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Pages'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTUserLandingPage >> defaultCards [
11 Added:
12 Added: ^ {
13 Added: MFTMainUserCard new.
14 Added: MFTWorkoutsCard new }
15 Added: ]
src/MyFitnessTracker-Components/MFTUserTask.class.st
index 00000000..15cd6186 000000..100644
@@ -0,0 +1,85 @@
1 Added: Class {
2 Added: #name : 'MFTUserTask',
3 Added: #superclass : 'WATask',
4 Added: #instVars : [
5 Added: 'user',
6 Added: 'action'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Tasks',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Tasks'
11 Added: }
12 Added:
13 Added: { #category : 'actions' }
14 Added: MFTUserTask class >> edit: aMFTUser [
15 Added:
16 Added: ^ self new
17 Added: user: aMFTUser;
18 Added: action: #edit;
19 Added: yourself
20 Added: ]
21 Added:
22 Added: { #category : 'accessing' }
23 Added: MFTUserTask >> action [
24 Added:
25 Added: ^ action
26 Added: ]
27 Added:
28 Added: { #category : 'accessing' }
29 Added: MFTUserTask >> action: anObject [
30 Added:
31 Added: action := anObject
32 Added: ]
33 Added:
34 Added: { #category : 'running' }
35 Added: MFTUserTask >> go [
36 Added:
37 Added: user username: (self call: (MFTStringDialog new
38 Added: action: action;
39 Added: heading: 'username';
40 Added: string: user username;
41 Added: completion: 20)).
42 Added: user passwordHashFromString: (self call: (MFTStringDialog new
43 Added: action: action;
44 Added: heading: 'password';
45 Added: completion: 40)).
46 Added: user dateOfBirth: (self call: (MFTDateDialog new
47 Added: action: action;
48 Added: heading: 'date of birth';
49 Added: date: user dateOfBirth;
50 Added: completion: 60)).
51 Added: user realFirstName: (self call: (MFTStringDialog new
52 Added: action: action;
53 Added: heading: 'real first name';
54 Added: string: user realFirstName;
55 Added: completion: 80)).
56 Added: user realLastName: (self call: (MFTStringDialog new
57 Added: heading: 'real last name';
58 Added: string: user realLastName;
59 Added: completion: 100)).
60 Added:
61 Added: (self call: (MFTConfirmDialog new
62 Added: action: action;
63 Added: component: user))
64 Added: ifTrue: [ self answer: user ]
65 Added: ifFalse: [ self answer: nil ]
66 Added: ]
67 Added:
68 Added: { #category : 'initialization' }
69 Added: MFTUserTask >> initialize [
70 Added:
71 Added: super initialize.
72 Added: user := MFTUser new
73 Added: ]
74 Added:
75 Added: { #category : 'accessing' }
76 Added: MFTUserTask >> user [
77 Added:
78 Added: ^ user
79 Added: ]
80 Added:
81 Added: { #category : 'accessing' }
82 Added: MFTUserTask >> user: anObject [
83 Added:
84 Added: user := anObject
85 Added: ]
src/MyFitnessTracker-Components/MFTWeightDialog.class.st
index 00000000..046225df 000000..100644
@@ -0,0 +1,76 @@
1 Added: Class {
2 Added: #name : 'MFTWeightDialog',
3 Added: #superclass : 'MFTDialog',
4 Added: #instVars : [
5 Added: 'weight'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Dialogs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Dialogs'
10 Added: }
11 Added:
12 Added: { #category : 'actions' }
13 Added: MFTWeightDialog class >> edit: aMFTWeight [
14 Added:
15 Added: ^ self new
16 Added: action: #edit;
17 Added: weight: aMFTWeight;
18 Added: yourself
19 Added: ]
20 Added:
21 Added: { #category : 'initialization' }
22 Added: MFTWeightDialog >> initialize [
23 Added:
24 Added: super initialize.
25 Added: weight := MFTWeight new
26 Added: ]
27 Added:
28 Added: { #category : 'rendering' }
29 Added: MFTWeightDialog >> renderContentOn: html [
30 Added:
31 Added: self renderDialogOn: html with: [
32 Added: html formGroup: [
33 Added: html label: 'Date'.
34 Added: html dateInput5 formControl
35 Added: value: weight date yyyymmdd;
36 Added: callback: [ :value |
37 Added: weight date: (Date readFrom: value pattern: 'yyyy-mm-dd') ] ].
38 Added: html formGroup: [
39 Added: html label: 'Weight'.
40 Added: html numberInput formControl
41 Added: value: (weight value = 0
42 Added: ifTrue: [ nil ]
43 Added: ifFalse: [ weight value ]);
44 Added: placeholder: weight value;
45 Added: callback: [ :value |
46 Added: value ifNotEmpty: [ weight value: value asNumber ] ] ] ]
47 Added: ]
48 Added:
49 Added: { #category : 'rendering' }
50 Added: MFTWeightDialog >> renderSubmitOn: html [
51 Added:
52 Added: html buttonGroup: [
53 Added: html formButton
54 Added: beSubmit;
55 Added: bePrimary;
56 Added: callback: [
57 Added: self answer: (weight value ifNotNil: [ weight ] ifNil: [ nil ]) ];
58 Added: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
59 Added: html formButton
60 Added: beSubmit;
61 Added: beSecondary;
62 Added: callback: [ self answer: nil ];
63 Added: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
64 Added: ]
65 Added:
66 Added: { #category : 'accessing' }
67 Added: MFTWeightDialog >> weight [
68 Added:
69 Added: ^ weight
70 Added: ]
71 Added:
72 Added: { #category : 'accessing' }
73 Added: MFTWeightDialog >> weight: aMFTWeight [
74 Added:
75 Added: weight := aMFTWeight
76 Added: ]
src/MyFitnessTracker-Components/MFTWeightVsTimeGraph.class.st
index 00000000..6aa2850c 000000..100644
@@ -0,0 +1,29 @@
1 Added: Class {
2 Added: #name : 'MFTWeightVsTimeGraph',
3 Added: #superclass : 'MFTGraph',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'rendering' }
10 Added: MFTWeightVsTimeGraph >> renderContentOn: html [
11 Added:
12 Added: labels := self session user weights collect: [ :weight |
13 Added: weight date yyyymmdd ].
14 Added: data := self session user weights collect: #value.
15 Added:
16 Added: html canvas id: 'weightVsTimeChart'.
17 Added: html script:
18 Added: 'var ctx = document.getElementById("weightVsTimeChart").getContext("2d");
19 Added: var weightChart = new Chart(ctx, {
20 Added: type: "line",
21 Added: data: {
22 Added: labels: ' , labels asJavascript , ',
23 Added: datasets: [{
24 Added: label: "weight",
25 Added: data: ' , data asJavascript , ',
26 Added: }]
27 Added: },
28 Added: });'
29 Added: ]
src/MyFitnessTracker-Components/MFTWeightsCard.class.st
index 00000000..a48b2460 000000..100644
@@ -0,0 +1,54 @@
1 Added: Class {
2 Added: #name : 'MFTWeightsCard',
3 Added: #superclass : 'MFTCard',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'adding' }
10 Added: MFTWeightsCard >> addWeight [
11 Added:
12 Added: | newWeight |
13 Added: newWeight := self session pageManager activePage call:
14 Added: MFTWeightDialog new.
15 Added: (self session user weights anySatisfy: [ :existingWeight |
16 Added: newWeight date = existingWeight date and: [
17 Added: newWeight value = existingWeight value ] ]) ifTrue: [ ^ self ].
18 Added:
19 Added: self session user isLoggedIn
20 Added: ifTrue: [ self session db insert: newWeight ]
21 Added: ifFalse: [ self session user weights add: newWeight ]
22 Added: ]
23 Added:
24 Added: { #category : 'rendering' }
25 Added: MFTWeightsCard >> renderContentOn: html [
26 Added:
27 Added: self renderCardOn: html with: [
28 Added: html cardHeader: 'Weights'.
29 Added: html cardBody: [
30 Added: html paragraph: 'Great job logging your weight '
31 Added: , self session user weights size asString , ' times!'.
32 Added: html form
33 Added: class: 'mb-3';
34 Added: with: [
35 Added: html buttonGroup
36 Added: beSmall;
37 Added: with: [
38 Added: html outlineButton
39 Added: bePrimary;
40 Added: callback: [ self addWeight ];
41 Added: with: 'Log weight'.
42 Added: html outlineButton
43 Added: beSecondary;
44 Added: callback: [ self viewAnalytics ];
45 Added: with: 'View progress' ] ].
46 Added: html render: MFTWeightVsTimeGraph new ] ]
47 Added: ]
48 Added:
49 Added: { #category : 'as yet unclassified' }
50 Added: MFTWeightsCard >> viewAnalytics [
51 Added:
52 Added: self session pageManager activePage call:
53 Added: (MFTAnalyticsPage for: #weights)
54 Added: ]
src/MyFitnessTracker-Components/MFTWeightsLog.class.st
index 00000000..82c25bc5 000000..100644
@@ -0,0 +1,141 @@
1 Added: Class {
2 Added: #name : 'MFTWeightsLog',
3 Added: #superclass : 'MFTLog',
4 Added: #instVars : [
5 Added: 'weights'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Logs',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Logs'
10 Added: }
11 Added:
12 Added: { #category : 'adding' }
13 Added: MFTWeightsLog >> addWeight [
14 Added:
15 Added: | newWeight |
16 Added: newWeight := self call: MFTWeightDialog new.
17 Added: newWeight ifNil: [ ^ self ].
18 Added: (weights anySatisfy: [ :existingWeight |
19 Added: existingWeight date = newWeight date and: [
20 Added: existingWeight value = newWeight value ] ]) ifTrue: [ ^ self ].
21 Added:
22 Added: self session user isLoggedIn
23 Added: ifTrue: [ self session db insert: newWeight ]
24 Added: ifFalse: [ weights add: newWeight ]
25 Added: ]
26 Added:
27 Added: { #category : 'accessing' }
28 Added: MFTWeightsLog >> editWeight: oldWeight [
29 Added:
30 Added: | newWeight |
31 Added: newWeight := self call: (MFTWeightDialog edit: oldWeight copy).
32 Added: (oldWeight value = newWeight value and: [
33 Added: oldWeight date = newWeight date ]) ifTrue: [ ^ self ].
34 Added:
35 Added: self session user isLoggedIn
36 Added: ifTrue: [ self session db update: oldWeight with: newWeight ]
37 Added: ifFalse: [
38 Added: weights
39 Added: remove: oldWeight;
40 Added: add: newWeight ]
41 Added: ]
42 Added:
43 Added: { #category : 'initialization' }
44 Added: MFTWeightsLog >> initialize [
45 Added:
46 Added: super initialize.
47 Added: title := 'weights'.
48 Added: weights := OrderedCollection new
49 Added: ]
50 Added:
51 Added: { #category : 'as yet unclassified' }
52 Added: MFTWeightsLog >> randomWittyCTA [
53 Added:
54 Added: | listOfStrings randomString |
55 Added: listOfStrings := #( 'First time?' 'Get your sweat on!'
56 Added: 'Go go go!' 'Go get ''em, Tiger!' ).
57 Added: randomString := listOfStrings atRandom.
58 Added: ^ randomString
59 Added: ]
60 Added:
61 Added: { #category : 'accessing' }
62 Added: MFTWeightsLog >> removeWeight: aMFTWeight [
63 Added:
64 Added: self session user isLoggedIn
65 Added: ifTrue: [ self session db delete: aMFTWeight ]
66 Added: ifFalse: [ weights remove: aMFTWeight ]
67 Added: ]
68 Added:
69 Added: { #category : 'rendering' }
70 Added: MFTWeightsLog >> renderActionsButtonGroupOn: html [
71 Added:
72 Added: html form: [
73 Added: html buttonGroup: [
74 Added: html formButton
75 Added: bePrimary;
76 Added: callback: [ self addWeight ];
77 Added: with: 'Log weight'.
78 Added: html formButton
79 Added: beSecondary;
80 Added: callback: [ self viewAnalytics ];
81 Added: with: 'View progress' ] ]
82 Added: ]
83 Added:
84 Added: { #category : 'rendering' }
85 Added: MFTWeightsLog >> renderContentOn: html [
86 Added:
87 Added: weights := self session user weights sort: [ :a :b | a date > b date ].
88 Added: self renderLogOn: html with: [
89 Added: weights ifEmpty: [
90 Added: html jumbotron: [ html heading: self randomWittyCTA ] ].
91 Added: self renderActionsButtonGroupOn: html.
92 Added: weights ifNotEmpty: [ self renderWeightsAsTableOn: html ] ]
93 Added: ]
94 Added:
95 Added: { #category : 'rendering' }
96 Added: MFTWeightsLog >> renderWeightActionsButtonGroupOn: html for: aMFTWeight [
97 Added:
98 Added: html form: [
99 Added: html buttonGroup
100 Added: beSmall;
101 Added: with: [
102 Added: html formButton
103 Added: beSecondary;
104 Added: formControl;
105 Added: callback: [ self editWeight: aMFTWeight ];
106 Added: with: 'Edit'.
107 Added: html formButton
108 Added: beDanger;
109 Added: formControl;
110 Added: callback: [ self removeWeight: aMFTWeight ];
111 Added: with: 'Delete' ] ]
112 Added: ]
113 Added:
114 Added: { #category : 'rendering' }
115 Added: MFTWeightsLog >> renderWeightsAsTableOn: html [
116 Added:
117 Added: html table
118 Added: class: 'table table-striped';
119 Added: with: [
120 Added: html tableHead: [
121 Added: html
122 Added: tableHeading;
123 Added: tableHeading: 'Date'.
124 Added: html tableHeading
125 Added: style: 'text-align: right';
126 Added: with: 'Value' ].
127 Added: weights do: [ :weight |
128 Added: html tableRow: [
129 Added: html tableData: [
130 Added: self renderWeightActionsButtonGroupOn: html for: weight ].
131 Added: html tableData: weight date yyyymmdd.
132 Added: html tableData
133 Added: style: 'text-align: right';
134 Added: with: weight value ] ] ]
135 Added: ]
136 Added:
137 Added: { #category : 'adding' }
138 Added: MFTWeightsLog >> viewAnalytics [
139 Added:
140 Added: self call: (MFTAnalyticsPage for: #weights)
141 Added: ]
src/MyFitnessTracker-Components/MFTWidget.class.st
index 00000000..ce232af0 000000..100644
@@ -0,0 +1,46 @@
1 Added: Class {
2 Added: #name : 'MFTWidget',
3 Added: #superclass : 'SBSComponent',
4 Added: #instVars : [
5 Added: 'title'
6 Added: ],
7 Added: #category : 'MyFitnessTracker-Components-Widgets',
8 Added: #package : 'MyFitnessTracker-Components',
9 Added: #tag : 'Widgets'
10 Added: }
11 Added:
12 Added: { #category : 'accessing' }
13 Added: MFTWidget >> defaultDescription [
14 Added:
15 Added: ^ 'I am a ' , self class name
16 Added: ]
17 Added:
18 Added: { #category : 'initialization' }
19 Added: MFTWidget >> initialize [
20 Added:
21 Added: super initialize.
22 Added: title := String new
23 Added: ]
24 Added:
25 Added: { #category : 'rendering' }
26 Added: MFTWidget >> renderContentOn: html [
27 Added:
28 Added: html div: [
29 Added: title ifNotEmpty: [
30 Added: html heading
31 Added: level5;
32 Added: with: self title ].
33 Added: html paragraph: self defaultDescription ]
34 Added: ]
35 Added:
36 Added: { #category : 'accessing' }
37 Added: MFTWidget >> title [
38 Added:
39 Added: ^ title
40 Added: ]
41 Added:
42 Added: { #category : 'accessing' }
43 Added: MFTWidget >> title: aString [
44 Added:
45 Added: title := aString
46 Added: ]
src/MyFitnessTracker-Components/MFTWorkoutForm.class.st
index 00000000..cfef255a 000000..100644
@@ -0,0 +1,45 @@
1 Added: Class {
2 Added: #name : 'MFTWorkoutForm',
3 Added: #superclass : 'MFTForm',
4 Added: #category : 'MyFitnessTracker-Components-Forms',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Forms'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTWorkoutForm class >> edit: aMFTWorkout [
11 Added:
12 Added: ^ self new
13 Added: modelObject: aMFTWorkout;
14 Added: yourself
15 Added: ]
16 Added:
17 Added: { #category : 'initialization' }
18 Added: MFTWorkoutForm >> initialize [
19 Added:
20 Added: super initialize.
21 Added: modelObject := MFTWorkout new.
22 Added: heading := 'Workout'
23 Added: ]
24 Added:
25 Added: { #category : 'rendering' }
26 Added: MFTWorkoutForm >> renderContentOn: html [
27 Added:
28 Added: self renderFormOn: html with: [
29 Added: html
30 Added: render: (MFTFormComponent set: #date);
31 Added: render: (MFTFormComponent set: #setGroups);
32 Added: render: (MFTFormComponent set: #primaryMuscleGroup);
33 Added: render: (MFTFormComponent set: #secondaryMuscleGroups) ]
34 Added: ]
35 Added:
36 Added: { #category : 'as yet unclassified' }
37 Added: MFTWorkoutForm >> submitForm [
38 Added:
39 Added: modelObject setGroups ifEmpty: [
40 Added: (self call:
41 Added: (MFTConfirmForm new modelObject: 'No exercises were specified.'))
42 Added: ifFalse: [ self answer: nil ] ].
43 Added:
44 Added: self answer: modelObject
45 Added: ]
src/MyFitnessTracker-Components/MFTWorkoutTask.class.st
index 00000000..c4618229 000000..100644
@@ -0,0 +1,101 @@
1 Added: Class {
2 Added: #name : 'MFTWorkoutTask',
3 Added: #superclass : 'WATask',
4 Added: #instVars : [
5 Added: 'workout',
6 Added: 'action'
7 Added: ],
8 Added: #category : 'MyFitnessTracker-Components-Tasks',
9 Added: #package : 'MyFitnessTracker-Components',
10 Added: #tag : 'Tasks'
11 Added: }
12 Added:
13 Added: { #category : 'actions' }
14 Added: MFTWorkoutTask class >> edit: aMFTWorkout [
15 Added:
16 Added: ^ self new
17 Added: workout: aMFTWorkout;
18 Added: action: #edit;
19 Added: yourself
20 Added: ]
21 Added:
22 Added: { #category : 'accessing' }
23 Added: MFTWorkoutTask >> action [
24 Added:
25 Added: ^ action
26 Added: ]
27 Added:
28 Added: { #category : 'accessing' }
29 Added: MFTWorkoutTask >> action: anObject [
30 Added:
31 Added: action := anObject
32 Added: ]
33 Added:
34 Added: { #category : 'running' }
35 Added: MFTWorkoutTask >> go [
36 Added:
37 Added: | primaryMuscleGroup secondaryMuscleGroups |
38 Added: workout userId: self session user id.
39 Added: workout date: (self call: (MFTDateDialog new
40 Added: action: action;
41 Added: date: workout date;
42 Added: completion: 20)).
43 Added: workout setGroups: (self call: (MFTSetGroupsDialog new
44 Added: action: action;
45 Added: heading: 'Exercises';
46 Added: setGroups: workout setGroups;
47 Added: completion: 40)).
48 Added: primaryMuscleGroup := self call: (MFTPrimaryMuscleGroupDialog new
49 Added: action: action;
50 Added: primaryMuscleGroup:
51 Added: workout primaryMuscleGroup;
52 Added: completion: 60).
53 Added: primaryMuscleGroup ifNotNil: [
54 Added: workout primaryMuscleGroupId: primaryMuscleGroup id.
55 Added: secondaryMuscleGroups := self call:
56 Added: (MFTSecondaryMuscleGroupsDialog new
57 Added: action: action;
58 Added: secondaryMuscleGroups:
59 Added: workout secondaryMuscleGroups;
60 Added: completion: 80).
61 Added: workout secondaryMuscleGroupIds:
62 Added: (secondaryMuscleGroups collect: #id) ].
63 Added:
64 Added: (self call: (MFTConfirmDialog new
65 Added: action: action;
66 Added: component: workout))
67 Added: ifTrue: [
68 Added: self updateSetsAttributes.
69 Added: self answer: workout ]
70 Added: ifFalse: [ self answer: nil ]
71 Added: ]
72 Added:
73 Added: { #category : 'initialization' }
74 Added: MFTWorkoutTask >> initialize [
75 Added:
76 Added: super initialize.
77 Added: workout := MFTWorkout new.
78 Added: action := #add
79 Added: ]
80 Added:
81 Added: { #category : 'as yet unclassified' }
82 Added: MFTWorkoutTask >> updateSetsAttributes [
83 Added:
84 Added: workout setGroups doWithIndex: [ :setGroup :i |
85 Added: setGroup sets doWithIndex: [ :set :j |
86 Added: set
87 Added: groupId: i;
88 Added: number: j ] ]
89 Added: ]
90 Added:
91 Added: { #category : 'accessing' }
92 Added: MFTWorkoutTask >> workout [
93 Added:
94 Added: ^ workout
95 Added: ]
96 Added:
97 Added: { #category : 'accessing' }
98 Added: MFTWorkoutTask >> workout: anObject [
99 Added:
100 Added: workout := anObject
101 Added: ]
src/MyFitnessTracker-Components/MFTWorkoutVolumePerWeekGraph.class.st
index 00000000..289b3aa2 000000..100644
@@ -0,0 +1,46 @@
1 Added: Class {
2 Added: #name : 'MFTWorkoutVolumePerWeekGraph',
3 Added: #superclass : 'MFTGraph',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'as yet unclassified' }
10 Added: MFTWorkoutVolumePerWeekGraph >> crunchTheNumbers [
11 Added: "TODO: not working at all!"
12 Added:
13 Added: | datasets datasetsAsJs |
14 Added: labels := Week dayNames.
15 Added: data := self session user workouts groupedBy: [ :each |
16 Added: each date dayOfYear // 7 ].
17 Added: "datasets := {
18 Added: { 1. 2. 0. 0. 3. 5. 3 }.
19 Added: { 3. 4. 3. 0. 0. 0. 6 } }."
20 Added: datasetsAsJs := data keysAndValuesDo: [ :k :v |
21 Added: '{ label: ' , (#w , k asString) asJavascript
22 Added: , ', data: ' , (v collect: #volume) asJavascript
23 Added: , '},' ]
24 Added: ]
25 Added:
26 Added: { #category : 'initialization' }
27 Added: MFTWorkoutVolumePerWeekGraph >> initialize [
28 Added:
29 Added: super initialize.
30 Added: self crunchTheNumbers
31 Added: ]
32 Added:
33 Added: { #category : 'rendering' }
34 Added: MFTWorkoutVolumePerWeekGraph >> renderContentOn: html [
35 Added:
36 Added: html canvas id: 'workoutVolumePerWeekChart'.
37 Added: html script:
38 Added: 'var ctx = document.getElementById("workoutVolumePerWeekChart").getContext("2d");
39 Added: var weightChart = new Chart(ctx, {
40 Added: type: "line",
41 Added: data: {
42 Added: labels: ' , labels asJavascript , ',
43 Added: datasets: [ ' , data asJavascript , ' ]
44 Added: },
45 Added: });'
46 Added: ]
src/MyFitnessTracker-Components/MFTWorkoutVolumeVsTimeGraph.class.st
index 00000000..cf78adff 000000..100644
@@ -0,0 +1,31 @@
1 Added: Class {
2 Added: #name : 'MFTWorkoutVolumeVsTimeGraph',
3 Added: #superclass : 'MFTGraph',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'rendering' }
10 Added: MFTWorkoutVolumeVsTimeGraph >> renderContentOn: html [
11 Added:
12 Added: | workouts |
13 Added: workouts := self session user workouts sort: [ :a :b |
14 Added: a date < b date ].
15 Added: labels := workouts collect: [ :workout | workout date yyyymmdd ].
16 Added: data := workouts collect: #volume.
17 Added:
18 Added: html canvas id: 'workoutVolumeVsTimeChart'.
19 Added: html script:
20 Added: 'var ctx = document.getElementById("workoutVolumeVsTimeChart").getContext("2d");
21 Added: var weightChart = new Chart(ctx, {
22 Added: type: "line",
23 Added: data: {
24 Added: labels: ' , labels asJavascript , ',
25 Added: datasets: [{
26 Added: label: "total workout volume",
27 Added: data: ' , data asJavascript , ',
28 Added: }]
29 Added: },
30 Added: });'
31 Added: ]
src/MyFitnessTracker-Components/MFTWorkoutsCard.class.st
index 00000000..9d959d0d 000000..100644
@@ -0,0 +1,53 @@
1 Added: Class {
2 Added: #name : 'MFTWorkoutsCard',
3 Added: #superclass : 'MFTCard',
4 Added: #category : 'MyFitnessTracker-Components-Widgets',
5 Added: #package : 'MyFitnessTracker-Components',
6 Added: #tag : 'Widgets'
7 Added: }
8 Added:
9 Added: { #category : 'adding' }
10 Added: MFTWorkoutsCard >> addWorkout [
11 Added:
12 Added: | newWorkout |
13 Added: newWorkout := self session pageManager activePage call:
14 Added: MFTWorkoutTask new.
15 Added: newWorkout ifNil: [ ^ self ].
16 Added:
17 Added: self session user isLoggedIn
18 Added: ifTrue: [ self session db insert: newWorkout ]
19 Added: ifFalse: [ self session user workouts add: newWorkout ]
20 Added: ]
21 Added:
22 Added: { #category : 'rendering' }
23 Added: MFTWorkoutsCard >> renderContentOn: html [
24 Added:
25 Added: self renderCardOn: html with: [
26 Added: html cardHeader: 'Workouts'.
27 Added: html cardBody: [
28 Added: html paragraph:
29 Added: 'Great job logging ' , self session user workouts size asString
30 Added: , ' workouts!'.
31 Added: html form
32 Added: class: 'my-3';
33 Added: with: [
34 Added: html buttonGroup
35 Added: beSmall;
36 Added: with: [
37 Added: html outlineButton
38 Added: bePrimary;
39 Added: callback: [ self addWorkout ];
40 Added: with: 'Log workout'.
41 Added: html outlineButton
42 Added: beSecondary;
43 Added: callback: [ self viewAnalytics ];
44 Added: with: 'View progress' ] ].
45 Added: html render: MFTRepsDistributionGraph new ] ]
46 Added: ]
47 Added:
48 Added: { #category : 'adding' }
49 Added: MFTWorkoutsCard >> viewAnalytics [
50 Added:
51 Added: self session pageManager activePage call:
52 Added: (MFTAnalyticsPage for: #workouts)
53 Added: ]
src/MyFitnessTracker-Components/MFTWorkoutsLog.class.st
index 00000000..be40d837 000000..100644
@@ -0,0 +1,172 @@
1 Added: "
2 Added: I represent the list of user workouts retrieved from the database.
3 Added:
4 Added: I am rendered by `MFTRootComponent` when the user views their workouts. I know about user workouts retrieved from the database.
5 Added:
6 Added: * Collaborators
7 Added:
8 Added: - I work with lists of `MFTWorkout`s.
9 Added: - I might work with `MFTExercise class`canonical exercises once the variable is implemented.
10 Added:
11 Added: Public API and Key Messages
12 Added:
13 Added: - message one
14 Added: - message two
15 Added: - (for bonus points) how to create instances.
16 Added:
17 Added: One simple example is simply gorgeous.
18 Added:
19 Added: Internal Representation and Key Implementation Points.
20 Added:
21 Added:
22 Added: Implementation Points
23 Added: "
24 Added: Class {
25 Added: #name : 'MFTWorkoutsLog',
26 Added: #superclass : 'MFTLog',
27 Added: #instVars : [
28 Added: 'workouts'
29 Added: ],
30 Added: #category : 'MyFitnessTracker-Components-Logs',
31 Added: #package : 'MyFitnessTracker-Components',
32 Added: #tag : 'Logs'
33 Added: }
34 Added:
35 Added: { #category : 'adding' }
36 Added: MFTWorkoutsLog >> addWorkout [
37 Added:
38 Added: | newWorkout |
39 Added: newWorkout := self call: MFTWorkoutForm new.
40 Added: newWorkout ifNil: [ ^ self ].
41 Added:
42 Added: self session user isLoggedIn
43 Added: ifTrue: [ self session db insert: newWorkout ]
44 Added: ifFalse: [ workouts add: newWorkout ]
45 Added: ]
46 Added:
47 Added: { #category : 'hooks' }
48 Added: MFTWorkoutsLog >> children [
49 Added:
50 Added: ^ self session user workouts
51 Added: ]
52 Added:
53 Added: { #category : 'accessing' }
54 Added: MFTWorkoutsLog >> confirmDelete: workout [
55 Added:
56 Added: (self call: (MFTConfirmForm delete)) ifFalse: [ ^ self ].
57 Added: self session user isLoggedIn
58 Added: ifTrue: [ self session db delete: workout ]
59 Added: ifFalse: [ workouts remove: workout ]
60 Added: ]
61 Added:
62 Added: { #category : 'as yet unclassified' }
63 Added: MFTWorkoutsLog >> editWorkout: oldWorkout [
64 Added:
65 Added: | newWorkout |
66 Added: newWorkout := self call: (MFTWorkoutForm edit: oldWorkout copy).
67 Added: newWorkout ifNil: [ ^ self ].
68 Added:
69 Added: self session user isLoggedIn
70 Added: ifTrue: [ self session db update: oldWorkout with: newWorkout ]
71 Added: ifFalse: [
72 Added: workouts
73 Added: remove: oldWorkout;
74 Added: add: newWorkout ]
75 Added: ]
76 Added:
77 Added: { #category : 'initialization' }
78 Added: MFTWorkoutsLog >> initialize [
79 Added:
80 Added: super initialize.
81 Added: title := 'workouts'.
82 Added: workouts := OrderedCollection new
83 Added: ]
84 Added:
85 Added: { #category : 'as yet unclassified' }
86 Added: MFTWorkoutsLog >> randomWittyCTA [
87 Added:
88 Added: | listOfStrings randomString |
89 Added: listOfStrings := #( 'First time?' 'Get your sweat on!'
90 Added: 'Go go go!' 'Go get ''em, Tiger!' ).
91 Added: randomString := listOfStrings atRandom.
92 Added: ^ randomString
93 Added: ]
94 Added:
95 Added: { #category : 'rendering' }
96 Added: MFTWorkoutsLog >> renderActionsButtonGroupOn: html [
97 Added:
98 Added: html form: [
99 Added: html buttonGroup: [
100 Added: html formButton
101 Added: bePrimary;
102 Added: callback: [ self addWorkout ];
103 Added: with: 'Log workout'.
104 Added: html formButton
105 Added: beSecondary;
106 Added: callback: [ self viewAnalytics ];
107 Added: with: 'View progress' ] ]
108 Added: ]
109 Added:
110 Added: { #category : 'rendering' }
111 Added: MFTWorkoutsLog >> renderContentOn: html [
112 Added:
113 Added: workouts := self session user workouts sort: [ :a :b |
114 Added: a date > b date ].
115 Added: self renderLogOn: html with: [
116 Added: workouts ifEmpty: [
117 Added: html jumbotron: [ html heading: self randomWittyCTA ] ].
118 Added: self renderActionsButtonGroupOn: html.
119 Added: workouts ifNotEmpty: [ self renderWorkoutsAsAccordionOn: html ] ]
120 Added: ]
121 Added:
122 Added: { #category : 'rendering' }
123 Added: MFTWorkoutsLog >> renderWorkoutActionsButtonGroup: html for: workout [
124 Added:
125 Added: html form: [
126 Added: html buttonGroup: [
127 Added: html formButton
128 Added: bePrimary;
129 Added: callback: [ self editWorkout: workout ];
130 Added: with: 'Edit'.
131 Added: html formButton
132 Added: beDanger;
133 Added: callback: [ self confirmDelete: workout ];
134 Added: with: 'Delete' ] ]
135 Added: ]
136 Added:
137 Added: { #category : 'rendering' }
138 Added: MFTWorkoutsLog >> renderWorkoutsAsAccordionOn: html [
139 Added:
140 Added: html accordion
141 Added: id: 'accordion';
142 Added: class: 'my-3';
143 Added: with: [
144 Added: workouts doWithIndex: [ :workout :i |
145 Added: html accordionItem: [
146 Added: html accordionHeading: [
147 Added: html accordionButton
148 Added: dataToggle: 'collapse';
149 Added: dataTarget: '#collapse' , i asString;
150 Added: with: [
151 Added: html text:
152 Added: workout date yyyymmdd , ', ' , workout date dayOfWeekName.
153 Added: workout primaryMuscleGroup ifNotNil: [
154 Added: html
155 Added: text: ':';
156 Added: space;
157 Added: emphasis: workout primaryMuscleGroup englishName ] ] ].
158 Added: html accordionCollapse
159 Added: id: 'collapse' , i asString;
160 Added: class: 'collapse';
161 Added: dataAttributeAt: 'bs-parent' put: '#accordion';
162 Added: with: [
163 Added: html accordionBody with: [
164 Added: html render: workout.
165 Added: self renderWorkoutActionsButtonGroup: html for: workout ] ] ] ] ]
166 Added: ]
167 Added:
168 Added: { #category : 'adding' }
169 Added: MFTWorkoutsLog >> viewAnalytics [
170 Added:
171 Added: self call: (MFTAnalyticsPage for: #workouts)
172 Added: ]
src/MyFitnessTracker-Components/package.st
index 00000000..ba43af47 000000..100644
@@ -0,0 +1,1 @@
1 Added: Package { #name : 'MyFitnessTracker-Components' }
src/MyFitnessTracker/MFTAboutPage.class.st
index a46cb4a9..00000000 100644..000000
@@ -1,87 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTAboutPage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'initialization' }
10 Removed: MFTAboutPage >> initialize [
11 Removed:
12 Removed: super initialize.
13 Removed: title := 'about'
14 Removed: ]
15 Removed:
16 Removed: { #category : 'rendering' }
17 Removed: MFTAboutPage >> renderBackgroundOn: html [
18 Removed:
19 Removed: html heading level1 with: 'Background'.
20 Removed: html heading level2 with: 'Why I built this web app'.
21 Removed: html
22 Removed: paragraph:
23 Removed: 'I wanted a convenient way to record, perform data analysis, and create visualizations for my workouts.';
24 Removed: paragraph:
25 Removed: 'The following features were, and still are, essential for me:';
26 Removed: unorderedList: [
27 Removed: html
28 Removed: listItem: 'Free access to all app features,';
29 Removed: listItem: 'Easy import and export of my training data,';
30 Removed: listItem:
31 Removed: 'An extensible interface to suit a wide range of training routines.' ];
32 Removed: paragraph:
33 Removed: 'What better way than to build my own Personal Fitness Tracker?!'.
34 Removed: html heading level2 with: 'Who I am'.
35 Removed: html paragraph:
36 Removed: 'I am an engineer working in Europe, with a deep passion for health and fitness. Publishing My Fitness Tracker is a way for me to give thanks to everyone who has inspired me throughtout my fitness journey.'
37 Removed: ]
38 Removed:
39 Removed: { #category : 'rendering' }
40 Removed: MFTAboutPage >> renderCatchOn: html [
41 Removed:
42 Removed: html heading level1 dangerText with: 'The catch'.
43 Removed: html
44 Removed: paragraph:
45 Removed: 'I''ve made some debatable compromises when it comes to My Fitness Tracker:';
46 Removed: unorderedList: [
47 Removed: html
48 Removed: listItem: 'No external advertisement,';
49 Removed: listItem:
50 Removed: 'No cookies or personally identifying information stored,';
51 Removed: listItem:
52 Removed: 'No paid feature, except for the storage of your training data beyond ten workouts.' ];
53 Removed: paragraph:
54 Removed: 'I know these design choices might frustrate and maybe even anger certain users; '
55 Removed: ,
56 Removed: 'thankfully, all previously existing fitness tracking services do not abide by these design principles.';
57 Removed: paragraph:
58 Removed: 'I am developing My Fitness Tracker for my own personal use case, first and foremost; '
59 Removed: ,
60 Removed: 'secondly, for the benefit of as many other fitness enthusiasts as possible; '
61 Removed: ,
62 Removed: 'thirdly, for the enjoyment that developing this web application brings me. '
63 Removed: ,
64 Removed: 'The paid feature enables me to increase the amount of fitness enthusiasts I can cater to.'
65 Removed: ]
66 Removed:
67 Removed: { #category : 'rendering' }
68 Removed: MFTAboutPage >> renderContentOn: html [
69 Removed:
70 Removed: self renderPageOn: html with: [
71 Removed: self renderVisionOn: html.
72 Removed: self renderBackgroundOn: html.
73 Removed: self renderCatchOn: html ]
74 Removed: ]
75 Removed:
76 Removed: { #category : 'rendering' }
77 Removed: MFTAboutPage >> renderVisionOn: html [
78 Removed:
79 Removed: html heading level1 with: 'The Vision'.
80 Removed: html paragraph: [
81 Removed: html text: 'Free, and eventually '.
82 Removed: html anchor
83 Removed: url: 'https://fsfe.org/index.en.html';
84 Removed: with: 'libre'.
85 Removed: html text:
86 Removed: ' fitness tracking for all to enjoy. No user data tracking and reselling; no features blocked for any reason.' ]
87 Removed: ]
src/MyFitnessTracker/MFTActionsCard.class.st
index 57837d27..00000000 100644..000000
@@ -1,18 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTActionsCard',
3 Removed: #superclass : 'MFTCard',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTActionsCard >> renderContentOn: html [
11 Removed:
12 Removed: self renderCardOn: html with: [
13 Removed: html form: [
14 Removed: html formButton
15 Removed: formControl;
16 Removed: callback: [ MFTWorkoutTask new ];
17 Removed: with: 'Log Workout' ] ]
18 Removed: ]
src/MyFitnessTracker/MFTAnalyticsPage.class.st
index c806b3f3..00000000 100644..000000
@@ -1,70 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTAnalyticsPage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #instVars : [
5 Removed: 'type'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'instance creation' }
13 Removed: MFTAnalyticsPage class >> for: aSymbol [
14 Removed:
15 Removed: ^ self new
16 Removed: type: aSymbol;
17 Removed: yourself
18 Removed: ]
19 Removed:
20 Removed: { #category : 'accessing' }
21 Removed: MFTAnalyticsPage >> analytics [
22 Removed:
23 Removed: ^ Dictionary newFrom: {
24 Removed: (#workouts -> {
25 Removed: MFTRepsDistributionGraph new.
26 Removed: MFTWorkoutVolumeVsTimeGraph new
27 Removed: "MFTWorkoutVolumePerWeekGraph new" }).
28 Removed: (#weights -> { MFTWeightVsTimeGraph new }) }
29 Removed: ]
30 Removed:
31 Removed: { #category : 'rendering' }
32 Removed: MFTAnalyticsPage >> renderActionsButtonGroupOn: html [
33 Removed:
34 Removed: html form class: 'my-3'; with: [
35 Removed: html buttonGroup: [
36 Removed: html formButton
37 Removed: bePrimary;
38 Removed: callback: [ self answer ];
39 Removed: with: 'Return' ] ]
40 Removed: ]
41 Removed:
42 Removed: { #category : 'rendering' }
43 Removed: MFTAnalyticsPage >> renderContentOn: html [
44 Removed:
45 Removed: | components |
46 Removed: components := self analytics at: type.
47 Removed:
48 Removed: self renderPageOn: html with: [
49 Removed: self renderActionsButtonGroupOn: html.
50 Removed: html div
51 Removed: style:
52 Removed: 'display: flex; flex-wrap: wrap; justify-content: space-around; gap: 1em';
53 Removed: with: [
54 Removed: components do: [ :each |
55 Removed: html card: [
56 Removed: html cardHeader: each title.
57 Removed: html render: each ] ] ] ]
58 Removed: ]
59 Removed:
60 Removed: { #category : 'accessing' }
61 Removed: MFTAnalyticsPage >> type [
62 Removed:
63 Removed: ^ type
64 Removed: ]
65 Removed:
66 Removed: { #category : 'accessing' }
67 Removed: MFTAnalyticsPage >> type: anObject [
68 Removed:
69 Removed: type := anObject
70 Removed: ]
src/MyFitnessTracker/MFTArticle.class.st
index a79a5cd7..00000000 100644..000000
@@ -1,29 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTArticle',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'title'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'rendering' }
13 Removed: MFTArticle >> renderArticleOn: html with: aBlock [
14 Removed:
15 Removed: html heading: title capitalized.
16 Removed: html render: aBlock
17 Removed: ]
18 Removed:
19 Removed: { #category : 'accessing' }
20 Removed: MFTArticle >> title [
21 Removed:
22 Removed: ^ title
23 Removed: ]
24 Removed:
25 Removed: { #category : 'accessing' }
26 Removed: MFTArticle >> title: aString [
27 Removed:
28 Removed: title := aString
29 Removed: ]
src/MyFitnessTracker/MFTAthletesArticle.class.st
index ef39c9b6..00000000 100644..000000
@@ -1,26 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTAthletesArticle',
3 Removed: #superclass : 'MFTArticle',
4 Removed: #instVars : [
5 Removed: 'athletes'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'initialization' }
13 Removed: MFTAthletesArticle >> initialize [
14 Removed:
15 Removed: super initialize.
16 Removed: title := 'athletes'.
17 Removed: athletes := { MFTMikeMentzer new }
18 Removed: ]
19 Removed:
20 Removed: { #category : 'rendering' }
21 Removed: MFTAthletesArticle >> renderContentOn: html [
22 Removed:
23 Removed: self
24 Removed: renderArticleOn: html
25 Removed: with: [ athletes do: [ :athlete | athlete renderContentOn: html ] ]
26 Removed: ]
src/MyFitnessTracker/MFTCard.class.st
index 5aaa8269..00000000 100644..000000
@@ -1,21 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTCard',
3 Removed: #superclass : 'MFTWidget',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTCard >> renderCardOn: html with: aBlock [
11 Removed:
12 Removed: html card: aBlock
13 Removed: ]
14 Removed:
15 Removed: { #category : 'rendering' }
16 Removed: MFTCard >> renderContentOn: html [
17 Removed:
18 Removed: self
19 Removed: renderCardOn: html
20 Removed: with: [ html cardBody: [ html paragraph: self defaultDescription ] ]
21 Removed: ]
src/MyFitnessTracker/MFTConfirmDialog.class.st
index 8fec1951..00000000 100644..000000
@@ -1,28 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTConfirmDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #category : 'MyFitnessTracker-Dialogs',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Dialogs'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTConfirmDialog >> heading [
11 Removed:
12 Removed: ^ 'You are about to {1} a {2}:' format: {
13 Removed: action.
14 Removed: component class }
15 Removed: ]
16 Removed:
17 Removed: { #category : 'as yet unclassified' }
18 Removed: MFTConfirmDialog >> renderContentOn: html [
19 Removed:
20 Removed: self renderDialogOn: html with: [
21 Removed: html render: component.
22 Removed: html label: [
23 Removed: html text: 'Are you sure?'.
24 Removed: action = #delete ifTrue: [
25 Removed: html
26 Removed: space;
27 Removed: strong: 'This action cannot be undone.' ] ] ]
28 Removed: ]
src/MyFitnessTracker/MFTConfirmForm.class.st
index 91076d2d..00000000 100644..000000
@@ -1,34 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTConfirmForm',
3 Removed: #superclass : 'MFTForm',
4 Removed: #category : 'MyFitnessTracker-Forms',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Forms'
7 Removed: }
8 Removed:
9 Removed: { #category : 'submorphs - add/remove' }
10 Removed: MFTConfirmForm class >> delete [
11 Removed:
12 Removed: ^ self new
13 Removed: modelObject: 'Confirm deletion?';
14 Removed: yourself
15 Removed: ]
16 Removed:
17 Removed: { #category : 'as yet unclassified' }
18 Removed: MFTConfirmForm >> cancelForm [
19 Removed:
20 Removed: self answer: false
21 Removed: ]
22 Removed:
23 Removed: { #category : 'initialization' }
24 Removed: MFTConfirmForm >> initialize [
25 Removed:
26 Removed: super initialize .
27 Removed: heading := 'Heads up!'
28 Removed: ]
29 Removed:
30 Removed: { #category : 'as yet unclassified' }
31 Removed: MFTConfirmForm >> submitForm [
32 Removed:
33 Removed: self answer: true
34 Removed: ]
src/MyFitnessTracker/MFTDateDialog.class.st
index 6d563dd6..00000000 100644..000000
@@ -1,50 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTDateDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'date'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'accessing' }
13 Removed: MFTDateDialog >> date [
14 Removed:
15 Removed: ^ date
16 Removed: ]
17 Removed:
18 Removed: { #category : 'accessing' }
19 Removed: MFTDateDialog >> date: anObject [
20 Removed:
21 Removed: date := anObject
22 Removed: ]
23 Removed:
24 Removed: { #category : 'initialization' }
25 Removed: MFTDateDialog >> initialize [
26 Removed:
27 Removed: super initialize.
28 Removed: date := Date today
29 Removed: ]
30 Removed:
31 Removed: { #category : 'rendering' }
32 Removed: MFTDateDialog >> renderContentOn: html [
33 Removed:
34 Removed: self renderDialogOn: html with: [
35 Removed: html dateInput5 formControl
36 Removed: value: date yyyymmdd;
37 Removed: callback: [ :value |
38 Removed: date := Date readFrom: value pattern: 'yyyy-mm-dd' ] ]
39 Removed: ]
40 Removed:
41 Removed: { #category : 'as yet unclassified' }
42 Removed: MFTDateDialog >> renderSubmitOn: html [
43 Removed:
44 Removed: html buttonGroup: [
45 Removed: html formButton
46 Removed: beSubmit;
47 Removed: bePrimary;
48 Removed: callback: [ self answer: date ];
49 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]) ]
50 Removed: ]
src/MyFitnessTracker/MFTDateFormComponent.class.st
index 651cf557..00000000 100644..000000
@@ -1,24 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTDateFormComponent',
3 Removed: #superclass : 'MFTFormComponent',
4 Removed: #category : 'MyFitnessTracker-Forms',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Forms'
7 Removed: }
8 Removed:
9 Removed: { #category : 'initialization' }
10 Removed: MFTDateFormComponent >> initialize [
11 Removed:
12 Removed: super initialize.
13 Removed: heading := 'Date'
14 Removed: ]
15 Removed:
16 Removed: { #category : 'rendering' }
17 Removed: MFTDateFormComponent >> renderContentOn: html [
18 Removed:
19 Removed: self renderFormComponentOn: html with: [
20 Removed: html dateInput5 formControl
21 Removed: value: modelObject date yyyymmdd;
22 Removed: callback: [ :value |
23 Removed: modelObject date: (Date readFrom: value pattern: 'yyyy-mm-dd') ] ]
24 Removed: ]
src/MyFitnessTracker/MFTDefaultFooter.class.st
index 6bc2d9a0..00000000 100644..000000
@@ -1,19 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTDefaultFooter',
3 Removed: #superclass : 'MFTFooter',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTDefaultFooter >> renderContentOn: html [
11 Removed:
12 Removed: self renderFooterOn: html with: [
13 Removed: html paragraph: [
14 Removed: html text:
15 Removed: 'Copyright 2023–' , Date today year asString , ' Marius PETER '.
16 Removed: html badge beSecondary with: (MFTUtils version
17 Removed: ifNil: [ 'DEVELOP' ]
18 Removed: ifNotNil: [ 'v' , MFTUtils version ]) ] ]
19 Removed: ]
src/MyFitnessTracker/MFTDialog.class.st
index 02ea9f4d..00000000 100644..000000
@@ -1,174 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTDialog',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'heading',
6 Removed: 'subheading',
7 Removed: 'component',
8 Removed: 'action',
9 Removed: 'completion'
10 Removed: ],
11 Removed: #category : 'MyFitnessTracker-Dialogs',
12 Removed: #package : 'MyFitnessTracker',
13 Removed: #tag : 'Dialogs'
14 Removed: }
15 Removed:
16 Removed: { #category : 'actions' }
17 Removed: MFTDialog class >> add: anObject [
18 Removed:
19 Removed: ^ self new
20 Removed: action: #add;
21 Removed: component: anObject;
22 Removed: yourself
23 Removed: ]
24 Removed:
25 Removed: { #category : 'actions' }
26 Removed: MFTDialog class >> delete: anObject [
27 Removed:
28 Removed: ^ self new
29 Removed: action: #delete;
30 Removed: component: anObject;
31 Removed: yourself
32 Removed: ]
33 Removed:
34 Removed: { #category : 'actions' }
35 Removed: MFTDialog class >> edit: anObject [
36 Removed:
37 Removed: ^ self new
38 Removed: action: #edit;
39 Removed: component: anObject;
40 Removed: yourself
41 Removed: ]
42 Removed:
43 Removed: { #category : 'accessing' }
44 Removed: MFTDialog >> action [
45 Removed:
46 Removed: ^ action
47 Removed: ]
48 Removed:
49 Removed: { #category : 'accessing' }
50 Removed: MFTDialog >> action: anObject [
51 Removed:
52 Removed: action := anObject
53 Removed: ]
54 Removed:
55 Removed: { #category : 'delegation' }
56 Removed: MFTDialog >> answer [
57 Removed:
58 Removed: self answer: component
59 Removed: ]
60 Removed:
61 Removed: { #category : 'accessing' }
62 Removed: MFTDialog >> completion [
63 Removed:
64 Removed: ^ completion
65 Removed: ]
66 Removed:
67 Removed: { #category : 'accessing' }
68 Removed: MFTDialog >> completion: anObject [
69 Removed:
70 Removed: completion := anObject
71 Removed: ]
72 Removed:
73 Removed: { #category : 'accessing' }
74 Removed: MFTDialog >> component [
75 Removed:
76 Removed: ^ component
77 Removed: ]
78 Removed:
79 Removed: { #category : 'accessing' }
80 Removed: MFTDialog >> component: anObject [
81 Removed:
82 Removed: component := anObject
83 Removed: ]
84 Removed:
85 Removed: { #category : 't - rotating' }
86 Removed: MFTDialog >> heading [
87 Removed:
88 Removed: ^ action capitalized , ' ' , (heading ifNil: [
89 Removed: ('^MFT(.*)Dialog$' asRegex
90 Removed: search: self class name;
91 Removed: subexpression: 2) asCapitalizedPhrase ifNil: [
92 Removed: 'Default Component' ] ])
93 Removed: ]
94 Removed:
95 Removed: { #category : 'accessing' }
96 Removed: MFTDialog >> heading: aString [
97 Removed:
98 Removed: heading := aString
99 Removed: ]
100 Removed:
101 Removed: { #category : 'initialization' }
102 Removed: MFTDialog >> initialize [
103 Removed:
104 Removed: super initialize.
105 Removed: action := #add
106 Removed: ]
107 Removed:
108 Removed: { #category : 'rendering' }
109 Removed: MFTDialog >> renderCompletionOn: html [
110 Removed:
111 Removed: completion ifNotNil: [
112 Removed: html progress
113 Removed: class: 'my-3';
114 Removed: with: [
115 Removed: html progressBar
116 Removed: beStriped;
117 Removed: beAnimated;
118 Removed: successBackground;
119 Removed: valueNow: completion;
120 Removed: with: completion percent ] ]
121 Removed: ]
122 Removed:
123 Removed: { #category : 'rendering' }
124 Removed: MFTDialog >> renderContentOn: html [
125 Removed:
126 Removed: self renderDialogOn: html with: [
127 Removed: html text:
128 Removed: 'By default, ' , self class name , ' doesn''t do anything.' ]
129 Removed: ]
130 Removed:
131 Removed: { #category : 'rendering' }
132 Removed: MFTDialog >> renderDialogOn: html with: aBlock [
133 Removed:
134 Removed: html container
135 Removed: style: 'max-width: 40rem';
136 Removed: with: [
137 Removed: html heading level1 with: self heading.
138 Removed: subheading ifNotNil: [
139 Removed: html heading level3 textMuted with: subheading ].
140 Removed: html form: [
141 Removed: aBlock value.
142 Removed: html horizontalRule.
143 Removed: self renderSubmitOn: html ].
144 Removed: self renderCompletionOn: html ]
145 Removed: ]
146 Removed:
147 Removed: { #category : 'rendering' }
148 Removed: MFTDialog >> renderSubmitOn: html [
149 Removed:
150 Removed: html buttonGroup: [
151 Removed: html formButton
152 Removed: beSubmit;
153 Removed: bePrimary;
154 Removed: beDangerIf: action = #delete;
155 Removed: callback: [ self answer: true ];
156 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
157 Removed: html formButton
158 Removed: beSubmit;
159 Removed: beSecondary;
160 Removed: callback: [ self answer: false ];
161 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
162 Removed: ]
163 Removed:
164 Removed: { #category : 'accessing' }
165 Removed: MFTDialog >> subheading [
166 Removed:
167 Removed: ^ subheading
168 Removed: ]
169 Removed:
170 Removed: { #category : 'accessing' }
171 Removed: MFTDialog >> subheading: aString [
172 Removed:
173 Removed: subheading := aString
174 Removed: ]
src/MyFitnessTracker/MFTDietArticle.class.st
index f1b9ec41..00000000 100644..000000
@@ -1,7 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTDietArticle',
3 Removed: #superclass : 'MFTArticle',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
src/MyFitnessTracker/MFTEmailSignupDialog.class.st
index 7b3b8275..00000000 100644..000000
@@ -1,66 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTEmailSignupDialog',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'localPart',
6 Removed: 'domain'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Dialogs',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Dialogs'
11 Removed: }
12 Removed:
13 Removed: { #category : 'initialization' }
14 Removed: MFTEmailSignupDialog >> initialize [
15 Removed:
16 Removed: super initialize.
17 Removed: localPart := String new.
18 Removed: domain := String new
19 Removed: ]
20 Removed:
21 Removed: { #category : 'rendering' }
22 Removed: MFTEmailSignupDialog >> renderContentOn: html [
23 Removed:
24 Removed: html div
25 Removed: darkBackground;
26 Removed: paddingTopAndBottom: 3;
27 Removed: paddingLeftAndRight: 5;
28 Removed: class: 'fixed-top';
29 Removed: style: 'z-index: 1052';
30 Removed: with: [
31 Removed: html heading
32 Removed: level3;
33 Removed: whiteText;
34 Removed: with: 'Get notified as soon as MFT is ready!'.
35 Removed: html paragraph
36 Removed: whiteText;
37 Removed: with: [
38 Removed: html
39 Removed: text:
40 Removed: 'You will receive a single e-mail indicating that My Fitness Tracker is usable and accepting new user registration.';
41 Removed: space;
42 Removed: text:
43 Removed: 'The e-mail address provided shall be used for no other purpose whatsoever.' ].
44 Removed: html form
45 Removed: paddingTopAndBottom: 3;
46 Removed: with: [
47 Removed: html inputGroup with: [
48 Removed: html formTextInput
49 Removed: callback: [ :value | localPart := value ];
50 Removed: placeholder: 'my-user'.
51 Removed: html inputGroupAppend: [ html inputGroupText: '@' ].
52 Removed: html formTextInput
53 Removed: callback: [ :value | domain := value ];
54 Removed: placeholder: 'example.com'.
55 Removed: html inputGroupAppend: [
56 Removed: html buttonGroup: [
57 Removed: html formButton
58 Removed: beSecondary;
59 Removed: beSubmit;
60 Removed: callback: [ self answer: localPart , '@' , domain ];
61 Removed: with: 'Confirm'.
62 Removed: html outlineButton
63 Removed: beSecondary;
64 Removed: callback: [ self answer: nil ];
65 Removed: with: 'Cancel' ] ] ] ] ]
66 Removed: ]
src/MyFitnessTracker/MFTExercisesForm.class.st
index 070cbb5f..00000000 100644..000000
@@ -1,46 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTExercisesForm',
3 Removed: #superclass : 'MFTForm',
4 Removed: #category : 'MyFitnessTracker-Forms',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Forms'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTExercisesForm class >> forExerciseCount: anInteger [
11 Removed:
12 Removed: | exercises |
13 Removed: exercises := OrderedCollection new: anInteger.
14 Removed: 1 to: anInteger do: [ :i |
15 Removed: exercises add: (MFTSQLite3Database allExercises at: i) ].
16 Removed: ^ self new
17 Removed: modelObject: exercises;
18 Removed: yourself
19 Removed: ]
20 Removed:
21 Removed: { #category : 'initialization' }
22 Removed: MFTExercisesForm >> initialize [
23 Removed:
24 Removed: super initialize.
25 Removed: modelObject := OrderedCollection new.
26 Removed: heading := 'Exercises'
27 Removed: ]
28 Removed:
29 Removed: { #category : 'rendering' }
30 Removed: MFTExercisesForm >> renderContentOn: html [
31 Removed:
32 Removed: self renderFormOn: html with: [ self renderSelectExercisesOn: html ]
33 Removed: ]
34 Removed:
35 Removed: { #category : 'rendering' }
36 Removed: MFTExercisesForm >> renderSelectExercisesOn: html [
37 Removed:
38 Removed: modelObject doWithIndex: [ :selectedExercise :i |
39 Removed: html formGroup: [
40 Removed: html label: 'Exercise ' , i asString.
41 Removed: html select formControl
42 Removed: list: MFTSQLite3Database allExercises;
43 Removed: selected: selectedExercise;
44 Removed: callback: [ :exercise | modelObject at: i put: exercise ];
45 Removed: labels: [ :each | each englishName ] ] ]
46 Removed: ]
src/MyFitnessTracker/MFTFooter.class.st
index 3c8edfc3..00000000 100644..000000
@@ -1,28 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTFooter',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTFooter >> renderContentOn: html [
11 Removed:
12 Removed: self
13 Removed: renderFooterOn: html
14 Removed: with: [ html text: 'I am the default footer' ]
15 Removed: ]
16 Removed:
17 Removed: { #category : 'rendering' }
18 Removed: MFTFooter >> renderFooterOn: html with: aBlock [
19 Removed:
20 Removed: html div
21 Removed: marginTop: 3;
22 Removed: paddingTopAndBottom: 3;
23 Removed: class: 'bg-light';
24 Removed: with: [
25 Removed: html container
26 Removed: class: 'd-flex justify-content-center';
27 Removed: with: [ aBlock value ] ]
28 Removed: ]
src/MyFitnessTracker/MFTForm.class.st
index f12a79fc..00000000 100644..000000
@@ -1,85 +0,0 @@
1 Removed: "
2 Removed: I represent a user-fillable form.
3 Removed:
4 Removed: Upon submitting the form (""submit"" button), I return (`WAComponent>>#answer:`) the `#modelObject` with its attributes populated by the appropriate `MFTFormComponent` subclasses.
5 Removed: Upon canceling the form (""cancel"" button), I return `nil`.
6 Removed: "
7 Removed: Class {
8 Removed: #name : 'MFTForm',
9 Removed: #superclass : 'SBSComponent',
10 Removed: #instVars : [
11 Removed: 'modelObject',
12 Removed: 'heading'
13 Removed: ],
14 Removed: #category : 'MyFitnessTracker-Forms',
15 Removed: #package : 'MyFitnessTracker',
16 Removed: #tag : 'Forms'
17 Removed: }
18 Removed:
19 Removed: { #category : 'as yet unclassified' }
20 Removed: MFTForm >> cancelForm [
21 Removed:
22 Removed: self answer: nil
23 Removed: ]
24 Removed:
25 Removed: { #category : 'initialization' }
26 Removed: MFTForm >> initialize [
27 Removed:
28 Removed: super initialize.
29 Removed: heading := 'Form heading'
30 Removed: ]
31 Removed:
32 Removed: { #category : 'accessing' }
33 Removed: MFTForm >> modelObject [
34 Removed:
35 Removed: ^ modelObject
36 Removed: ]
37 Removed:
38 Removed: { #category : 'accessing' }
39 Removed: MFTForm >> modelObject: anObject [
40 Removed:
41 Removed: modelObject := anObject
42 Removed: ]
43 Removed:
44 Removed: { #category : 'rendering' }
45 Removed: MFTForm >> renderContentOn: html [
46 Removed:
47 Removed: self renderFormOn: html with: [ html render: modelObject ]
48 Removed: ]
49 Removed:
50 Removed: { #category : 'as yet unclassified' }
51 Removed: MFTForm >> renderFormOn: html with: aBlock [
52 Removed:
53 Removed: html container
54 Removed: style: 'max-width: 40rem';
55 Removed: with: [
56 Removed: html displayHeading
57 Removed: level: 3;
58 Removed: with: heading.
59 Removed: html form: [
60 Removed: aBlock value.
61 Removed: html horizontalRule.
62 Removed: self renderSubmitOn: html ] ]
63 Removed: ]
64 Removed:
65 Removed: { #category : 'as yet unclassified' }
66 Removed: MFTForm >> renderSubmitOn: html [
67 Removed:
68 Removed: html buttonGroup: [
69 Removed: html formButton
70 Removed: beSubmit;
71 Removed: bePrimary;
72 Removed: callback: [ self submitForm ];
73 Removed: with: 'Submit'.
74 Removed: html formButton
75 Removed: beSubmit;
76 Removed: beSecondary;
77 Removed: callback: [ self cancelForm ];
78 Removed: with: 'Cancel' ]
79 Removed: ]
80 Removed:
81 Removed: { #category : 'as yet unclassified' }
82 Removed: MFTForm >> submitForm [
83 Removed:
84 Removed: self answer: modelObject
85 Removed: ]
src/MyFitnessTracker/MFTFormComponent.class.st
index fa9cbbdd..00000000 100644..000000
@@ -1,92 +0,0 @@
1 Removed: "
2 Removed: When instantiated with the `MFTFormComponent class>>#set:` message, I return an instance of the appropriate subclass for setting the model object attribute.
3 Removed: "
4 Removed: Class {
5 Removed: #name : 'MFTFormComponent',
6 Removed: #superclass : 'SBSComponent',
7 Removed: #instVars : [
8 Removed: 'heading',
9 Removed: 'modelObject'
10 Removed: ],
11 Removed: #category : 'MyFitnessTracker-Forms',
12 Removed: #package : 'MyFitnessTracker',
13 Removed: #tag : 'Forms'
14 Removed: }
15 Removed:
16 Removed: { #category : 'as yet unclassified' }
17 Removed: MFTFormComponent class >> formComponentFor: anAttribute [
18 Removed:
19 Removed: | formComponents |
20 Removed: formComponents := Dictionary newFrom: {
21 Removed: (#date -> MFTDateFormComponent).
22 Removed: (#setGroups -> MFTSetGroupsFormComponent).
23 Removed: (#primaryMuscleGroup
24 Removed: -> MFTPrimaryMuscleGroupFormComponent).
25 Removed: (#secondaryMuscleGroups
26 Removed: -> MFTSecondaryMuscleGroupsFormComponent) }.
27 Removed:
28 Removed: ^ formComponents at: anAttribute ifAbsent: [
29 Removed: self error:
30 Removed: ('no appropriate {1} subclass for setting attribute "{2}"'
31 Removed: format: {
32 Removed: self.
33 Removed: anAttribute }) ]
34 Removed: ]
35 Removed:
36 Removed: { #category : 'as yet unclassified' }
37 Removed: MFTFormComponent class >> set: anAttribute [
38 Removed:
39 Removed: | formComponent |
40 Removed: formComponent := self formComponentFor: anAttribute.
41 Removed: ^ formComponent new
42 Removed: modelObject: thisContext sender receiver modelObject;
43 Removed: yourself
44 Removed: ]
45 Removed:
46 Removed: { #category : 'accessing' }
47 Removed: MFTFormComponent >> heading [
48 Removed:
49 Removed: ^ heading
50 Removed: ]
51 Removed:
52 Removed: { #category : 'accessing' }
53 Removed: MFTFormComponent >> heading: anObject [
54 Removed:
55 Removed: heading := anObject
56 Removed: ]
57 Removed:
58 Removed: { #category : 'initialization' }
59 Removed: MFTFormComponent >> initialize [
60 Removed:
61 Removed: super initialize
62 Removed: ]
63 Removed:
64 Removed: { #category : 'accessing' }
65 Removed: MFTFormComponent >> modelObject [
66 Removed:
67 Removed: ^ modelObject
68 Removed: ]
69 Removed:
70 Removed: { #category : 'accessing' }
71 Removed: MFTFormComponent >> modelObject: anObject [
72 Removed:
73 Removed: modelObject := anObject
74 Removed: ]
75 Removed:
76 Removed: { #category : 'rendering' }
77 Removed: MFTFormComponent >> renderContentOn: html [
78 Removed:
79 Removed: self renderFormComponentOn: html with: [ html render: modelObject ]
80 Removed: ]
81 Removed:
82 Removed: { #category : 'as yet unclassified' }
83 Removed: MFTFormComponent >> renderFormComponentOn: html with: aBlock [
84 Removed:
85 Removed: html formGroup
86 Removed: class: 'my-4';
87 Removed: with: [
88 Removed: html paragraph
89 Removed: heading: 3;
90 Removed: with: [ html text: heading ].
91 Removed: aBlock value ]
92 Removed: ]
src/MyFitnessTracker/MFTGraph.class.st
index 1cc0ec4e..00000000 100644..000000
@@ -1,72 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTGraph',
3 Removed: #superclass : 'MFTWidget',
4 Removed: #instVars : [
5 Removed: 'labels',
6 Removed: 'data'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Components',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Components'
11 Removed: }
12 Removed:
13 Removed: { #category : 'accessing' }
14 Removed: MFTGraph >> data [
15 Removed:
16 Removed: ^ data
17 Removed: ]
18 Removed:
19 Removed: { #category : 'accessing' }
20 Removed: MFTGraph >> data: anObject [
21 Removed:
22 Removed: data := anObject
23 Removed: ]
24 Removed:
25 Removed: { #category : 'initialization' }
26 Removed: MFTGraph >> initialize [
27 Removed:
28 Removed: super initialize.
29 Removed: labels := #( Monday Tuesday Wednesday Thursday Friday ).
30 Removed: data := #( 5 1 6 2 7 )
31 Removed: ]
32 Removed:
33 Removed: { #category : 'accessing' }
34 Removed: MFTGraph >> labels [
35 Removed:
36 Removed: ^ labels
37 Removed: ]
38 Removed:
39 Removed: { #category : 'accessing' }
40 Removed: MFTGraph >> labels: anObject [
41 Removed:
42 Removed: labels := anObject
43 Removed: ]
44 Removed:
45 Removed: { #category : 'rendering' }
46 Removed: MFTGraph >> renderContentOn: html [
47 Removed:
48 Removed: html heading level5 with: self defaultDescription.
49 Removed: html canvas id: 'defaultGraph'.
50 Removed: html script:
51 Removed: 'var ctx = document.getElementById("defaultGraph").getContext("2d");
52 Removed: var defaultChart = new Chart(ctx, {
53 Removed: type: "line",
54 Removed: data: {
55 Removed: labels: ' , labels asJavascript , ',
56 Removed: datasets: [{
57 Removed: label: "default data",
58 Removed: data: ' , data asJavascript , ',
59 Removed: borderWidth: 1
60 Removed: }]
61 Removed: }
62 Removed: });'
63 Removed: ]
64 Removed:
65 Removed: { #category : 'accessing' }
66 Removed: MFTGraph >> title [
67 Removed:
68 Removed: ^ ('^MFT(.*)Graph$' asRegex
69 Removed: search: self class name;
70 Removed: subexpression: 2) asCapitalizedPhrase ifNil: [
71 Removed: 'Default Graph' ]
72 Removed: ]
src/MyFitnessTracker/MFTHeaderComponent.class.st
index 166ad8a5..00000000 100644..000000
@@ -1,7 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTHeaderComponent',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
src/MyFitnessTracker/MFTLandingPage.class.st
index 3be46f9b..00000000 100644..000000
@@ -1,55 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTLandingPage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #instVars : [
5 Removed: 'cards'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'accessing' }
13 Removed: MFTLandingPage >> cards [
14 Removed:
15 Removed: ^ cards
16 Removed: ]
17 Removed:
18 Removed: { #category : 'accessing' }
19 Removed: MFTLandingPage >> cards: aMFTCardCollection [
20 Removed:
21 Removed: cards := aMFTCardCollection
22 Removed: ]
23 Removed:
24 Removed: { #category : 'hooks' }
25 Removed: MFTLandingPage >> children [
26 Removed:
27 Removed: ^ cards
28 Removed: ]
29 Removed:
30 Removed: { #category : 'as yet unclassified' }
31 Removed: MFTLandingPage >> defaultCards [
32 Removed:
33 Removed: ^ {
34 Removed: MFTCard new.
35 Removed: MFTCard new.
36 Removed: MFTCard new }
37 Removed: ]
38 Removed:
39 Removed: { #category : 'as yet unclassified' }
40 Removed: MFTLandingPage >> initialize [
41 Removed:
42 Removed: super initialize.
43 Removed: title := 'home'.
44 Removed: cards := self defaultCards
45 Removed: ]
46 Removed:
47 Removed: { #category : 'rendering' }
48 Removed: MFTLandingPage >> renderContentOn: html [
49 Removed:
50 Removed: self renderPageOn: html with: [
51 Removed: html div
52 Removed: style:
53 Removed: 'display: flex; flex-wrap: wrap; justify-content: space-around; gap: 1em';
54 Removed: with: [ self cards do: [ :card | html render: card ] ] ]
55 Removed: ]
src/MyFitnessTracker/MFTLearnPage.class.st
index efc8c349..00000000 100644..000000
@@ -1,35 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTLearnPage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #instVars : [
5 Removed: 'articles',
6 Removed: 'activeArticle'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Components',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Components'
11 Removed: }
12 Removed:
13 Removed: { #category : 'initialization' }
14 Removed: MFTLearnPage >> initialize [
15 Removed:
16 Removed: super initialize.
17 Removed: title := 'learn'.
18 Removed: articles := {
19 Removed: MFTAthletesArticle new.
20 Removed: MFTMusclesArticle new }.
21 Removed: activeArticle := articles first
22 Removed: ]
23 Removed:
24 Removed: { #category : 'rendering' }
25 Removed: MFTLearnPage >> renderContentOn: html [
26 Removed:
27 Removed: self renderPageOn: html with: [
28 Removed: html navigation flexColumn with: [
29 Removed: articles do: [ :article |
30 Removed: html navigationLink
31 Removed: beActiveIf: [ activeArticle = article ];
32 Removed: callback: [ activeArticle := article ];
33 Removed: with: article title capitalized ] ].
34 Removed: html render: activeArticle ]
35 Removed: ]
src/MyFitnessTracker/MFTLog.class.st
index d805e44b..00000000 100644..000000
@@ -1,28 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTLog',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'title'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'rendering' }
13 Removed: MFTLog >> renderLogOn: html with: aBlock [
14 Removed:
15 Removed: html div: aBlock
16 Removed: ]
17 Removed:
18 Removed: { #category : 'accessing' }
19 Removed: MFTLog >> title [
20 Removed:
21 Removed: ^ title
22 Removed: ]
23 Removed:
24 Removed: { #category : 'accessing' }
25 Removed: MFTLog >> title: anObject [
26 Removed:
27 Removed: title := anObject
28 Removed: ]
src/MyFitnessTracker/MFTLoginRegisterLogoutComponent.class.st
index 8352aa92..00000000 100644..000000
@@ -1,155 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTLoginRegisterLogoutComponent',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'user'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'as yet unclassified' }
13 Removed: MFTLoginRegisterLogoutComponent >> attemptLogin: aMFTUser [
14 Removed: "Attempt to match aMFTUser passwordHash against an existing user password_hash in the database."
15 Removed:
16 Removed: | existingUser |
17 Removed: aMFTUser username = 'testMFT' ifTrue: [
18 Removed: ^ self session login: MFTSQLite3Database getTestUser ].
19 Removed: existingUser := MFTSQLite3Database getExistingUser: aMFTUser.
20 Removed: aMFTUser passwordHash = existingUser passwordHash
21 Removed: ifTrue: [ self session login: existingUser ]
22 Removed: ifFalse: [ self inform: 'Login failed' ]
23 Removed: ]
24 Removed:
25 Removed: { #category : 'initialization' }
26 Removed: MFTLoginRegisterLogoutComponent >> initialize [
27 Removed:
28 Removed: super initialize.
29 Removed: user := MFTUser new
30 Removed: ]
31 Removed:
32 Removed: { #category : 'as yet unclassified' }
33 Removed: MFTLoginRegisterLogoutComponent >> logout [
34 Removed:
35 Removed: self session logout
36 Removed: ]
37 Removed:
38 Removed: { #category : 'rendering' }
39 Removed: MFTLoginRegisterLogoutComponent >> renderContentOn: html [
40 Removed:
41 Removed: self session user isLoggedIn
42 Removed: ifFalse: [ self renderLoginAndRegisterModalsOn: html ]
43 Removed: ifTrue: [ self renderLogoutButtonOn: html ]
44 Removed: ]
45 Removed:
46 Removed: { #category : 'rendering' }
47 Removed: MFTLoginRegisterLogoutComponent >> renderLoginAndRegisterModalsOn: html [
48 Removed: "Logging in and registering display modal components; they are not in a form."
49 Removed:
50 Removed: html buttonGroup: [
51 Removed: html outlineButton
52 Removed: beSecondary;
53 Removed: beSmall;
54 Removed: dataToggle: 'modal';
55 Removed: dataTarget: '#loginModal';
56 Removed: with: 'Login'.
57 Removed: html outlineButton
58 Removed: bePrimary;
59 Removed: beSmall;
60 Removed: dataToggle: 'modal';
61 Removed: dataTarget: '#registerModal';
62 Removed: with: 'Register' ].
63 Removed: self renderLoginModalOn: html.
64 Removed: self renderRegisterModalOn: html
65 Removed: ]
66 Removed:
67 Removed: { #category : 'rendering' }
68 Removed: MFTLoginRegisterLogoutComponent >> renderLoginModalOn: html [
69 Removed:
70 Removed: html modal
71 Removed: id: 'loginModal';
72 Removed: fade;
73 Removed: with: [
74 Removed: html modalDialog
75 Removed: beCentered;
76 Removed: with: [
77 Removed: html modalContent: [
78 Removed: html form: [
79 Removed: html modalHeader: [
80 Removed: html modalTitle
81 Removed: level5;
82 Removed: with: 'Welcome back!'.
83 Removed: html modalCloseButton ].
84 Removed: html modalBody with: [
85 Removed: html formGroup: [
86 Removed: html label: 'Username'.
87 Removed: html textInput formControl callback: [ :value |
88 Removed: user username: value ] ].
89 Removed: html formGroup: [
90 Removed: html label: 'Password'.
91 Removed: html passwordInput formControl callback: [ :value |
92 Removed: user passwordHashFromString: value ] ] ].
93 Removed: html modalFooter: [
94 Removed: html buttonGroup: [
95 Removed: html formButton
96 Removed: bePrimary;
97 Removed: callback: [ self attemptLogin: user ];
98 Removed: with: 'Login'.
99 Removed: html formButton
100 Removed: beSecondary;
101 Removed: dataDismiss: 'modal';
102 Removed: with: 'Cancel' ] ] ] ] ] ]
103 Removed: ]
104 Removed:
105 Removed: { #category : 'rendering' }
106 Removed: MFTLoginRegisterLogoutComponent >> renderLogoutButtonOn: html [
107 Removed: "Logging out is an action; the button is in a form."
108 Removed:
109 Removed: html form: [
110 Removed: html outlineButton
111 Removed: beSecondary;
112 Removed: beSmall;
113 Removed: callback: [ self logout ];
114 Removed: with: 'Logout' ]
115 Removed: ]
116 Removed:
117 Removed: { #category : 'rendering' }
118 Removed: MFTLoginRegisterLogoutComponent >> renderRegisterModalOn: html [
119 Removed:
120 Removed: html modal
121 Removed: id: 'registerModal';
122 Removed: fade;
123 Removed: with: [
124 Removed: html modalDialog
125 Removed: beCentered;
126 Removed: with: [
127 Removed: html modalContent: [
128 Removed: html form: [
129 Removed: html modalHeader: [
130 Removed: html modalTitle
131 Removed: level5;
132 Removed: with: 'Welcome aboard!'.
133 Removed: html modalCloseButton ].
134 Removed: html modalBody with: [
135 Removed: html formGroup: [
136 Removed: html label: 'Username'.
137 Removed: html textInput formControl callback: [ :value |
138 Removed: user username: value ] ].
139 Removed: html formGroup: [
140 Removed: html label: 'Password'.
141 Removed: html passwordInput formControl callback: [ :value |
142 Removed: user passwordHashFromString: value ] ] ].
143 Removed: html modalFooter: [
144 Removed: html buttonGroup: [
145 Removed: html formButton
146 Removed: bePrimary;
147 Removed: callback: [
148 Removed: MFTSQLite3Database registerNewUser: user.
149 Removed: self attemptLogin: user ];
150 Removed: with: 'Register'.
151 Removed: html formButton
152 Removed: beSecondary;
153 Removed: dataDismiss: 'modal';
154 Removed: with: 'Cancel' ] ] ] ] ] ]
155 Removed: ]
src/MyFitnessTracker/MFTLogsPage.class.st
index 5ca4531e..00000000 100644..000000
@@ -1,49 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTLogsPage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #instVars : [
5 Removed: 'activeLog',
6 Removed: 'logs'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Components',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Components'
11 Removed: }
12 Removed:
13 Removed: { #category : 'hooks' }
14 Removed: MFTLogsPage >> children [
15 Removed:
16 Removed: ^ logs
17 Removed: ]
18 Removed:
19 Removed: { #category : 'initialization' }
20 Removed: MFTLogsPage >> initialize [
21 Removed:
22 Removed: super initialize.
23 Removed: title := 'logs'.
24 Removed: logs := {
25 Removed: MFTWorkoutsLog new.
26 Removed: MFTWeightsLog new }.
27 Removed: activeLog := logs first
28 Removed: ]
29 Removed:
30 Removed: { #category : 'rendering' }
31 Removed: MFTLogsPage >> renderContentOn: html [
32 Removed:
33 Removed: self renderPageOn: html with: [
34 Removed: self renderLogNavigationOn: html.
35 Removed: html render: activeLog ]
36 Removed: ]
37 Removed:
38 Removed: { #category : 'rendering' }
39 Removed: MFTLogsPage >> renderLogNavigationOn: html [
40 Removed:
41 Removed: html form
42 Removed: class: 'mb-3';
43 Removed: with: [
44 Removed: html navigation flexColumn with: [
45 Removed: logs do: [ :log |
46 Removed: html navigationLink
47 Removed: callback: [ activeLog := log ];
48 Removed: with: log title ] ] ]
49 Removed: ]
src/MyFitnessTracker/MFTMainNavigationBarComponent.class.st
index 54d11488..00000000 100644..000000
@@ -1,65 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTMainNavigationBarComponent',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'loginRegisterLogout'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'hooks' }
13 Removed: MFTMainNavigationBarComponent >> children [
14 Removed:
15 Removed: ^ { loginRegisterLogout }
16 Removed: ]
17 Removed:
18 Removed: { #category : 'initialization' }
19 Removed: MFTMainNavigationBarComponent >> initialize [
20 Removed:
21 Removed: super initialize.
22 Removed: loginRegisterLogout := MFTLoginRegisterLogoutComponent new
23 Removed: ]
24 Removed:
25 Removed: { #category : 'rendering' }
26 Removed: MFTMainNavigationBarComponent >> renderContentOn: html [
27 Removed:
28 Removed: html navigationBar
29 Removed: beLight;
30 Removed: lightBackground;
31 Removed: expandLarge;
32 Removed: marginBottom: 3;
33 Removed: paddingLeftAndRight: 3;
34 Removed: style: 'position: sticky; top: 0; z-index: 1051';
35 Removed: with: [ self renderNavigationBarItemsOn: html ]
36 Removed: ]
37 Removed:
38 Removed: { #category : 'rendering' }
39 Removed: MFTMainNavigationBarComponent >> renderNavigationBarItemsOn: html [
40 Removed:
41 Removed: | pm |
42 Removed: pm := self session pageManager.
43 Removed: html navigationBarBrand
44 Removed: callback: [ pm setActivePageAt: #home ];
45 Removed: with: 'MyFitnessTracker'.
46 Removed: "The toggler is only visible when the screen width is reduced."
47 Removed: html navigationBarToggler
48 Removed: beButtonType;
49 Removed: collapse;
50 Removed: dataTarget: '#navbarCollapsed';
51 Removed: with: [ html navigationBarTogglerIcon ].
52 Removed: html navigationBarCollapse collapse
53 Removed: id: 'navbarCollapsed';
54 Removed: class: 'justify-content-between';
55 Removed: with: [
56 Removed: html navigationBarNavigation: [
57 Removed: pm mainPages keysAndValuesDo: [ :name :page |
58 Removed: html navigationItem
59 Removed: beActiveIf: [ pm activePage = page ];
60 Removed: with: [
61 Removed: html navigationLink
62 Removed: callback: [ pm setActivePageAt: name ];
63 Removed: with: page title capitalized ] ] ].
64 Removed: html render: loginRegisterLogout ]
65 Removed: ]
src/MyFitnessTracker/MFTMainPublicCard.class.st
index 71a1c827..00000000 100644..000000
@@ -1,45 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTMainPublicCard',
3 Removed: #superclass : 'MFTCard',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'adding' }
10 Removed: MFTMainPublicCard >> addWorkout [
11 Removed:
12 Removed: | newWorkout |
13 Removed: newWorkout := self session pageManager activePage call:
14 Removed: MFTWorkoutForm new.
15 Removed: newWorkout
16 Removed: ifNil: [ ^ self ]
17 Removed: ifNotNil: [ self session pageManager setActivePageAt: #logs ].
18 Removed:
19 Removed: self session user isLoggedIn
20 Removed: ifTrue: [ self session db insert: newWorkout ]
21 Removed: ifFalse: [ self session user workouts add: newWorkout ]
22 Removed: ]
23 Removed:
24 Removed: { #category : 'rendering' }
25 Removed: MFTMainPublicCard >> renderContentOn: html [
26 Removed:
27 Removed: self renderCardOn: html with: [
28 Removed: html jumbotron
29 Removed: class: 'p-3 bg-light h-100';
30 Removed: with: [
31 Removed: html displayHeading
32 Removed: level: 1;
33 Removed: with: 'Log, plan, share your workouts.'.
34 Removed: html heading
35 Removed: level: 2;
36 Removed: textMuted;
37 Removed: with: 'Free Software never looked so fit!'.
38 Removed: html form: [
39 Removed: html formButton
40 Removed: bePrimary;
41 Removed: beLarge;
42 Removed: class: 'mt-3';
43 Removed: callback: [ self addWorkout ];
44 Removed: with: 'Log a workout' ] ] ]
45 Removed: ]
src/MyFitnessTracker/MFTMainUserCard.class.st
index 78e58fb9..00000000 100644..000000
@@ -1,41 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTMainUserCard',
3 Removed: #superclass : 'MFTCard',
4 Removed: #instVars : [
5 Removed: 'lastLoginDate',
6 Removed: 'subtitle'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Components',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Components'
11 Removed: }
12 Removed:
13 Removed: { #category : 'initialization' }
14 Removed: MFTMainUserCard >> initialize [
15 Removed:
16 Removed: super initialize.
17 Removed: lastLoginDate := self session user lastLoginDateAndTime.
18 Removed: subtitle := 'Last logged in {1}, {2} at {3} UTC' format: {
19 Removed: lastLoginDate dayOfWeekName.
20 Removed: lastLoginDate asDate asString.
21 Removed: lastLoginDate asTimeUTC asString }
22 Removed: ]
23 Removed:
24 Removed: { #category : 'rendering' }
25 Removed: MFTMainUserCard >> renderContentOn: html [
26 Removed:
27 Removed: | user |
28 Removed: user := self session user.
29 Removed: self renderCardOn: html with: [
30 Removed: html jumbotron
31 Removed: class: 'p-3 bg-light';
32 Removed: with: [
33 Removed: html displayHeading
34 Removed: level: 1;
35 Removed: with: [
36 Removed: html
37 Removed: text: 'Welcome, ';
38 Removed: code: (user realFirstName ifEmpty: [ user username ]);
39 Removed: text: '!' ].
40 Removed: html big textMuted with: subtitle ] ]
41 Removed: ]
src/MyFitnessTracker/MFTMusclesArticle.class.st
index 4d358560..00000000 100644..000000
@@ -1,31 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTMusclesArticle',
3 Removed: #superclass : 'MFTArticle',
4 Removed: #instVars : [
5 Removed: 'muscleGroups'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'hooks' }
13 Removed: MFTMusclesArticle >> children [
14 Removed:
15 Removed: ^ muscleGroups
16 Removed: ]
17 Removed:
18 Removed: { #category : 'initialization' }
19 Removed: MFTMusclesArticle >> initialize [
20 Removed:
21 Removed: super initialize.
22 Removed: title := 'muscles'
23 Removed: ]
24 Removed:
25 Removed: { #category : 'rendering' }
26 Removed: MFTMusclesArticle >> renderContentOn: html [
27 Removed:
28 Removed: self renderArticleOn: html with: [
29 Removed: MFTSQLite3Database allMuscleGroups do: [ :muscleGroup |
30 Removed: html render: muscleGroup ] ]
31 Removed: ]
src/MyFitnessTracker/MFTPage.class.st
index 2fd959aa..00000000 100644..000000
@@ -1,24 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTPage',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'title'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'rendering' }
13 Removed: MFTPage >> renderPageOn: html with: aBlock [
14 Removed:
15 Removed: html container
16 Removed: style: 'max-width: 50rem';
17 Removed: with: aBlock
18 Removed: ]
19 Removed:
20 Removed: { #category : 'accessing' }
21 Removed: MFTPage >> title [
22 Removed:
23 Removed: ^ title
24 Removed: ]
src/MyFitnessTracker/MFTPrimaryMuscleGroupDialog.class.st
index ac680c5a..00000000 100644..000000
@@ -1,64 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTPrimaryMuscleGroupDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'primaryMuscleGroup'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'initialization' }
13 Removed: MFTPrimaryMuscleGroupDialog >> initialize [
14 Removed:
15 Removed: super initialize.
16 Removed: primaryMuscleGroup := MFTMuscleGroup new.
17 Removed:
18 Removed: ]
19 Removed:
20 Removed: { #category : 'accessing' }
21 Removed: MFTPrimaryMuscleGroupDialog >> primaryMuscleGroup [
22 Removed:
23 Removed: ^ primaryMuscleGroup
24 Removed: ]
25 Removed:
26 Removed: { #category : 'accessing' }
27 Removed: MFTPrimaryMuscleGroupDialog >> primaryMuscleGroup: anObject [
28 Removed:
29 Removed: primaryMuscleGroup := anObject
30 Removed: ]
31 Removed:
32 Removed: { #category : 'rendering' }
33 Removed: MFTPrimaryMuscleGroupDialog >> renderContentOn: html [
34 Removed:
35 Removed: | allMuscleGroups selectedMuscleGroup |
36 Removed: allMuscleGroups := MFTSQLite3Database allMuscleGroups.
37 Removed: selectedMuscleGroup := primaryMuscleGroup ifNotNil: [
38 Removed: allMuscleGroups detect: [ :muscleGroup |
39 Removed: muscleGroup englishName
40 Removed: = primaryMuscleGroup englishName ] ].
41 Removed: self renderDialogOn: html with: [
42 Removed: html formGroup: [
43 Removed: html select formControl
44 Removed: list: allMuscleGroups;
45 Removed: selected: selectedMuscleGroup;
46 Removed: labels: [ :muscleGroup | muscleGroup englishName ];
47 Removed: callback: [ :group | primaryMuscleGroup := group ] ] ]
48 Removed: ]
49 Removed:
50 Removed: { #category : 'rendering' }
51 Removed: MFTPrimaryMuscleGroupDialog >> renderSubmitOn: html [
52 Removed:
53 Removed: html buttonGroup: [
54 Removed: html formButton
55 Removed: beSubmit;
56 Removed: bePrimary;
57 Removed: callback: [ self answer: primaryMuscleGroup ];
58 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
59 Removed: html formButton
60 Removed: beSubmit;
61 Removed: beSecondary;
62 Removed: callback: [ self answer: nil ];
63 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
64 Removed: ]
src/MyFitnessTracker/MFTPrimaryMuscleGroupFormComponent.class.st
index b735a4f9..00000000 100644..000000
@@ -1,32 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTPrimaryMuscleGroupFormComponent',
3 Removed: #superclass : 'MFTFormComponent',
4 Removed: #category : 'MyFitnessTracker-Forms',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Forms'
7 Removed: }
8 Removed:
9 Removed: { #category : 'initialization' }
10 Removed: MFTPrimaryMuscleGroupFormComponent >> initialize [
11 Removed:
12 Removed: super initialize.
13 Removed: heading := 'Primary Group'
14 Removed: ]
15 Removed:
16 Removed: { #category : 'rendering' }
17 Removed: MFTPrimaryMuscleGroupFormComponent >> renderContentOn: html [
18 Removed:
19 Removed: | allMuscleGroups selectedMuscleGroup |
20 Removed: allMuscleGroups := MFTSQLite3Database allMuscleGroups.
21 Removed: selectedMuscleGroup := modelObject primaryMuscleGroup ifNotNil: [
22 Removed: allMuscleGroups detect: [ :muscleGroup |
23 Removed: muscleGroup englishName
24 Removed: = modelObject primaryMuscleGroup englishName ] ].
25 Removed:
26 Removed: self renderFormComponentOn: html with: [
27 Removed: html select formControl
28 Removed: list: allMuscleGroups;
29 Removed: selected: selectedMuscleGroup;
30 Removed: labels: [ :muscleGroup | muscleGroup englishName ];
31 Removed: callback: [ :group | modelObject primaryMuscleGroup: group ] ]
32 Removed: ]
src/MyFitnessTracker/MFTProfilePage.class.st
index 2fd9a4bc..00000000 100644..000000
@@ -1,50 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTProfilePage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTProfilePage >> editProfile [
11 Removed:
12 Removed: | updatedUser |
13 Removed: updatedUser := self call: (MFTUserTask edit: self session user).
14 Removed: updatedUser ifNil: [ ^ self ].
15 Removed: self session user: updatedUser.
16 Removed: self session user isLoggedIn ifTrue: [
17 Removed: self session db updateUserWith: updatedUser ]
18 Removed: ]
19 Removed:
20 Removed: { #category : 'initialization' }
21 Removed: MFTProfilePage >> initialize [
22 Removed:
23 Removed: super initialize.
24 Removed: title := 'profile'
25 Removed: ]
26 Removed:
27 Removed: { #category : 'rendering' }
28 Removed: MFTProfilePage >> renderContentOn: html [
29 Removed:
30 Removed: | user |
31 Removed: user := self session user.
32 Removed:
33 Removed: self renderPageOn: html with: [
34 Removed: html heading level1 with: [
35 Removed: html
36 Removed: code: self session user username;
37 Removed: text: '''s profile' ].
38 Removed: self renderProfileActionsOn: html.
39 Removed: html render: user ]
40 Removed: ]
41 Removed:
42 Removed: { #category : 'rendering' }
43 Removed: MFTProfilePage >> renderProfileActionsOn: html [
44 Removed:
45 Removed: html form: [
46 Removed: html formButton
47 Removed: bePrimary;
48 Removed: callback: [ self editProfile ];
49 Removed: with: 'Edit profile' ]
50 Removed: ]
src/MyFitnessTracker/MFTPromisesCard.class.st
index fa5e114a..00000000 100644..000000
@@ -1,30 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTPromisesCard',
3 Removed: #superclass : 'MFTCard',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTPromisesCard >> renderContentOn: html [
11 Removed:
12 Removed: self renderCardOn: html with: [
13 Removed: html cardHeader: 'My promises to all users:'.
14 Removed: html cardBody: [
15 Removed: html listGroup: [
16 Removed: html
17 Removed: listGroupItem:
18 Removed: 'Every single feature shall always be free of charge.';
19 Removed: listGroupItem:
20 Removed: 'No personal user data shall ever be sold, under any circumstances.';
21 Removed: listGroupItem:
22 Removed: 'No external advertisements shall ever be displayed.' ].
23 Removed: html form
24 Removed: class: 'mt-3';
25 Removed: with: [
26 Removed: html outlineButton
27 Removed: bePrimary;
28 Removed: callback: [ self session pageManager setActivePageAt: #about ];
29 Removed: with: 'Why did I create this web app?' ] ] ]
30 Removed: ]
src/MyFitnessTracker/MFTPublicLandingPage.class.st
index 2c450109..00000000 100644..000000
@@ -1,17 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTPublicLandingPage',
3 Removed: #superclass : 'MFTLandingPage',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTPublicLandingPage >> defaultCards [
11 Removed:
12 Removed: ^ {
13 Removed: MFTMainPublicCard new.
14 Removed: MFTWorkoutsCard new.
15 Removed: MFTWeightsCard new.
16 Removed: MFTPromisesCard new }
17 Removed: ]
src/MyFitnessTracker/MFTRegisterProspectEmailHeader.class.st
index bd0b7df8..00000000 100644..000000
@@ -1,138 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTRegisterProspectEmailHeader',
3 Removed: #superclass : 'MFTHeaderComponent',
4 Removed: #instVars : [
5 Removed: 'email',
6 Removed: 'localPart',
7 Removed: 'domain',
8 Removed: 'isDismissed'
9 Removed: ],
10 Removed: #category : 'MyFitnessTracker-Components',
11 Removed: #package : 'MyFitnessTracker',
12 Removed: #tag : 'Components'
13 Removed: }
14 Removed:
15 Removed: { #category : 'adding' }
16 Removed: MFTRegisterProspectEmailHeader >> addUserEmail [
17 Removed:
18 Removed: | emailToCheck emailPattern |
19 Removed: emailToCheck := self call: MFTEmailSignupDialog new.
20 Removed: emailPattern := '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]{3,}\.[a-zA-Z]{2,}$'
21 Removed: asRegex.
22 Removed: (emailToCheck isNil or: [ (emailPattern matches: emailToCheck) not ])
23 Removed: ifTrue: [ ^ nil ].
24 Removed: email := emailToCheck.
25 Removed: MFTSQLite3Database storeProspectEmail: email
26 Removed: ]
27 Removed:
28 Removed: { #category : 'initialization' }
29 Removed: MFTRegisterProspectEmailHeader >> initialize [
30 Removed:
31 Removed: super initialize.
32 Removed: isDismissed := false
33 Removed: ]
34 Removed:
35 Removed: { #category : 'accessing' }
36 Removed: MFTRegisterProspectEmailHeader >> isDismissed [
37 Removed:
38 Removed: ^ isDismissed
39 Removed: ]
40 Removed:
41 Removed: { #category : 'accessing' }
42 Removed: MFTRegisterProspectEmailHeader >> isDismissed: anObject [
43 Removed:
44 Removed: isDismissed := anObject
45 Removed: ]
46 Removed:
47 Removed: { #category : 'rendering' }
48 Removed: MFTRegisterProspectEmailHeader >> renderContentOn: html [
49 Removed:
50 Removed: isDismissed ifTrue: [ ^ self ].
51 Removed: email
52 Removed: ifNil: [
53 Removed: html alert
54 Removed: beWarning;
55 Removed: marginBottom: 0;
56 Removed: with: [
57 Removed: html alertHeading: 'This app is still in beta.'.
58 Removed: html paragraph: [
59 Removed: html
60 Removed: text:
61 Removed: 'My Fitness Tracker is still under heavy development, with improvements being made daily.';
62 Removed: space;
63 Removed: text: 'I can''t wait to share the finished product with you!' ].
64 Removed: html form with: [
65 Removed: html label
66 Removed: style: 'margin-right: 1em';
67 Removed: with: [ html strong: 'Want to know when version 1.0 is out?' ].
68 Removed: html buttonGroup: [
69 Removed: html formButton
70 Removed: beInfo;
71 Removed: callback: [ self addUserEmail ];
72 Removed: with: 'E-mail me!'.
73 Removed: html formButton
74 Removed: beSecondary;
75 Removed: callback: [ isDismissed := true ];
76 Removed: with: 'I''m not interested' ] ] ] ]
77 Removed: ifNotNil: [
78 Removed: html alert
79 Removed: beSuccess;
80 Removed: beDismissible;
81 Removed: marginBottom: 0;
82 Removed: with: [
83 Removed: html closeButton dataDismiss: 'alert'.
84 Removed: html
85 Removed: text: 'You''ll be notified at ';
86 Removed: strong: email;
87 Removed: text: ' when My Fitness Tracker is ready for you!' ] ]
88 Removed: ]
89 Removed:
90 Removed: { #category : 'rendering' }
91 Removed: MFTRegisterProspectEmailHeader >> renderEmailInputModalButtonOn: html [
92 Removed:
93 Removed: html formButton
94 Removed: bePrimary;
95 Removed: beSmall;
96 Removed: dataToggle: 'modal';
97 Removed: dataTarget: '#emailInputModal';
98 Removed: with: 'E-mail me!'
99 Removed: ]
100 Removed:
101 Removed: { #category : 'rendering' }
102 Removed: MFTRegisterProspectEmailHeader >> renderEmailInputModalOn: html [
103 Removed:
104 Removed: html modal
105 Removed: id: 'emailInputModal';
106 Removed: fade;
107 Removed: with: [
108 Removed: html modalDialog
109 Removed: beCentered;
110 Removed: with: [
111 Removed: html modalContent: [
112 Removed: html form: [
113 Removed: html modalHeader: [
114 Removed: html modalTitle
115 Removed: level5;
116 Removed: with:
117 Removed: 'You''ll be the first to know when My Fitness Tracker is ready to use.'.
118 Removed: html modalCloseButton ].
119 Removed:
120 Removed: html modalBody: [
121 Removed: html inputGroup: [
122 Removed: html formTextInput
123 Removed: callback: [ :value | localPart := value ];
124 Removed: placeholder: 'my-user'.
125 Removed: html inputGroupAppend: [ html inputGroupText: '@' ].
126 Removed: html formTextInput
127 Removed: callback: [ :value | domain := value ];
128 Removed: placeholder: 'example.com' ] ].
129 Removed:
130 Removed: html modalFooter: [
131 Removed: html paragraph:
132 Removed: 'You will receive a single e-mail when the app is ready to use. Your e-mail address shall not be used in any other way.'.
133 Removed: html formButton
134 Removed: bePrimary;
135 Removed: beSubmit;
136 Removed: callback: [ email := localPart , '@' , domain ];
137 Removed: with: 'Confirm' ] ] ] ] ]
138 Removed: ]
src/MyFitnessTracker/MFTRepsDistributionGraph.class.st
index 6689f7ff..00000000 100644..000000
@@ -1,54 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTRepsDistributionGraph',
3 Removed: #superclass : 'MFTGraph',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTRepsDistributionGraph >> crunchTheNumbers [
11 Removed: "TODO: This looks ugly."
12 Removed:
13 Removed: | sets repTally |
14 Removed: sets := self session user workouts flatCollect: #sets.
15 Removed: repTally := Dictionary new.
16 Removed: sets do: [ :set |
17 Removed: repTally at: set exercise englishName ifAbsentPut: [ 0 ].
18 Removed: repTally
19 Removed: at: set exercise englishName
20 Removed: put: (repTally at: set exercise englishName) + set reps ].
21 Removed:
22 Removed: labels := repTally keys.
23 Removed: data := repTally values
24 Removed: ]
25 Removed:
26 Removed: { #category : 'initialization' }
27 Removed: MFTRepsDistributionGraph >> initialize [
28 Removed:
29 Removed: super initialize.
30 Removed: self crunchTheNumbers
31 Removed: ]
32 Removed:
33 Removed: { #category : 'rendering' }
34 Removed: MFTRepsDistributionGraph >> renderContentOn: html [
35 Removed:
36 Removed: html canvas id: 'repsVsTimeChart'.
37 Removed: html script:
38 Removed: 'var ctx = document.getElementById("repsVsTimeChart").getContext("2d");
39 Removed: var workoutChart = new Chart(ctx, {
40 Removed: type: "doughnut",
41 Removed: data: {
42 Removed: labels: ' , labels asJavascript , ',
43 Removed: datasets: [{
44 Removed: data: ' , data asJavascript , '
45 Removed: }]
46 Removed: },
47 Removed: options: {
48 Removed: title: {
49 Removed: display: true,
50 Removed: text: "Reps by exercise"
51 Removed: }
52 Removed: }
53 Removed: });'
54 Removed: ]
src/MyFitnessTracker/MFTRootComponent.class.st
index 0cfde590..00000000 100644..000000
@@ -1,102 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTRootComponent',
3 Removed: #superclass : 'SBSRootComponent',
4 Removed: #instVars : [
5 Removed: 'main'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'testing' }
13 Removed: MFTRootComponent class >> canBeRoot [
14 Removed:
15 Removed: ^ true
16 Removed: ]
17 Removed:
18 Removed: { #category : 'class initialization' }
19 Removed: MFTRootComponent class >> initialize [
20 Removed:
21 Removed: | application libraries |
22 Removed: application := WAAdmin register: self asApplicationAt: 'mft'.
23 Removed: application preferenceAt: #sessionClass put: MFTSession.
24 Removed: libraries := MFTUtils isDevelopmentImage
25 Removed: ifTrue: [ self libraries at: #development ]
26 Removed: ifFalse: [ self libraries at: #deployment ].
27 Removed: libraries do: [ :library | application addLibrary: library ].
28 Removed: ^ application
29 Removed: ]
30 Removed:
31 Removed: { #category : 'class initialization' }
32 Removed: MFTRootComponent class >> libraries [
33 Removed:
34 Removed: ^ Dictionary new
35 Removed: at: #development put: {
36 Removed: JQDevelopmentLibrary.
37 Removed: JQUiDevelopmentLibrary.
38 Removed: SBSDevelopmentLibrary };
39 Removed: at: #deployment put: {
40 Removed: JQGoogleLibrary.
41 Removed: JQUiGoogleLibrary.
42 Removed: SBSCDNDeploymentLibrary };
43 Removed: yourself
44 Removed: ]
45 Removed:
46 Removed: { #category : 'adding' }
47 Removed: MFTRootComponent >> addBootstrapJSScriptTo: html [
48 Removed:
49 Removed: | library |
50 Removed: library := MFTUtils isDevelopmentImage
51 Removed: ifTrue: [ SBSDeploymentLibrary ]
52 Removed: ifFalse: [ SBSCDNDeploymentLibrary ].
53 Removed: library addLoadScriptTo: html
54 Removed: ]
55 Removed:
56 Removed: { #category : 'rendering' }
57 Removed: MFTRootComponent >> children [
58 Removed:
59 Removed: ^ { main }
60 Removed: ]
61 Removed:
62 Removed: { #category : 'initialization' }
63 Removed: MFTRootComponent >> initialize [
64 Removed:
65 Removed: super initialize.
66 Removed: main := MFTScreenComponent new
67 Removed: ]
68 Removed:
69 Removed: { #category : 'initialization' }
70 Removed: MFTRootComponent >> main: aComponent [
71 Removed:
72 Removed: main := aComponent
73 Removed: ]
74 Removed:
75 Removed: { #category : 'rendering' }
76 Removed: MFTRootComponent >> renderContentOn: html [
77 Removed:
78 Removed: html script url: 'https://cdn.jsdelivr.net/npm/chart.js'.
79 Removed: html render: main.
80 Removed: self addBootstrapJSScriptTo: html
81 Removed: ]
82 Removed:
83 Removed: { #category : 'updating' }
84 Removed: MFTRootComponent >> updateRoot: anHtmlRoot [
85 Removed:
86 Removed: super updateRoot: anHtmlRoot.
87 Removed: anHtmlRoot beHtml5.
88 Removed: anHtmlRoot meta
89 Removed: name: 'viewport';
90 Removed: content: 'width=device-width, initial-scale=1'.
91 Removed: anHtmlRoot title: 'My Fitness Tracker ' , self version.
92 Removed: anHtmlRoot javascript url: 'https://cdn.jsdelivr.net/npm/chart.js'.
93 Removed: anHtmlRoot link
94 Removed: beShortcutIcon;
95 Removed: url: MFTFileLibrary / #faviconPng
96 Removed: ]
97 Removed:
98 Removed: { #category : 'versions' }
99 Removed: MFTRootComponent >> version [
100 Removed:
101 Removed: ^ MFTUtils version ifNil: [ '[DEVELOP]' ]
102 Removed: ]
src/MyFitnessTracker/MFTSandboxPage.class.st
index 04f7cb6a..00000000 100644..000000
@@ -1,22 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSandboxPage',
3 Removed: #superclass : 'MFTPage',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'initialization' }
10 Removed: MFTSandboxPage >> initialize [
11 Removed:
12 Removed: super initialize.
13 Removed: title := 'sandbox'
14 Removed: ]
15 Removed:
16 Removed: { #category : 'rendering' }
17 Removed: MFTSandboxPage >> renderContentOn: html [
18 Removed:
19 Removed: self renderPageOn: html with: [
20 Removed: html text: 'Welcome to the sandbox page.'.
21 Removed: MFTSQLite3Database allMuscleGroups do: [ :each | html render: each ] ]
22 Removed: ]
src/MyFitnessTracker/MFTScreenComponent.class.st
index 401c47e8..00000000 100644..000000
@@ -1,39 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTScreenComponent',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'pm'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'hooks' }
13 Removed: MFTScreenComponent >> children [
14 Removed:
15 Removed: ^ {
16 Removed: pm header.
17 Removed: pm mainNavigationBar.
18 Removed: pm activePage.
19 Removed: pm footer }
20 Removed: ]
21 Removed:
22 Removed: { #category : 'initialization' }
23 Removed: MFTScreenComponent >> initialize [
24 Removed:
25 Removed: super initialize.
26 Removed: pm := self session pageManager
27 Removed: ]
28 Removed:
29 Removed: { #category : 'rendering' }
30 Removed: MFTScreenComponent >> renderContentOn: html [
31 Removed:
32 Removed: (self session user isLoggedIn not and: [
33 Removed: MFTUtils isDevelopmentImage not ]) ifTrue: [
34 Removed: html render: pm header ].
35 Removed: html
36 Removed: render: pm mainNavigationBar;
37 Removed: render: pm activePage;
38 Removed: render: pm footer
39 Removed: ]
src/MyFitnessTracker/MFTSecondaryMuscleGroupsDialog.class.st
index 28155821..00000000 100644..000000
@@ -1,65 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSecondaryMuscleGroupsDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'secondaryMuscleGroups'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'initialization' }
13 Removed: MFTSecondaryMuscleGroupsDialog >> initialize [
14 Removed:
15 Removed: super initialize.
16 Removed: secondaryMuscleGroups := OrderedCollection new
17 Removed: ]
18 Removed:
19 Removed: { #category : 'rendering' }
20 Removed: MFTSecondaryMuscleGroupsDialog >> renderContentOn: html [
21 Removed:
22 Removed: | allMuscleGroups selectedMuscles |
23 Removed: allMuscleGroups := MFTSQLite3Database allMuscleGroups.
24 Removed: "selectedMuscles := allMuscles
25 Removed: detect: [ :each |
26 Removed: each englishName
27 Removed: = (secondaryMuscles collect: #englishName) ]
28 Removed: ifNone: [ nil ]."
29 Removed:
30 Removed: self renderDialogOn: html with: [
31 Removed: html multiSelect formControl
32 Removed: list: allMuscleGroups;
33 Removed: "selected: selectedMuscles;"labels: [ :muscleGroup |
34 Removed: muscleGroup englishName ];
35 Removed: callback: [ :groups |
36 Removed: groups ifNotEmpty: [ secondaryMuscleGroups := groups ] ] ]
37 Removed: ]
38 Removed:
39 Removed: { #category : 'rendering' }
40 Removed: MFTSecondaryMuscleGroupsDialog >> renderSubmitOn: html [
41 Removed:
42 Removed: html buttonGroup: [
43 Removed: html formButton
44 Removed: beSubmit;
45 Removed: bePrimary;
46 Removed: callback: [ self answer: secondaryMuscleGroups ];
47 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
48 Removed: html formButton
49 Removed: beSubmit;
50 Removed: beSecondary;
51 Removed: callback: [ self answer: OrderedCollection new ];
52 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
53 Removed: ]
54 Removed:
55 Removed: { #category : 'accessing' }
56 Removed: MFTSecondaryMuscleGroupsDialog >> secondaryMuscleGroups [
57 Removed:
58 Removed: ^ secondaryMuscleGroups
59 Removed: ]
60 Removed:
61 Removed: { #category : 'accessing' }
62 Removed: MFTSecondaryMuscleGroupsDialog >> secondaryMuscleGroups: anObject [
63 Removed:
64 Removed: secondaryMuscleGroups := anObject
65 Removed: ]
src/MyFitnessTracker/MFTSecondaryMuscleGroupsFormComponent.class.st
index 51d81612..00000000 100644..000000
@@ -1,40 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSecondaryMuscleGroupsFormComponent',
3 Removed: #superclass : 'MFTFormComponent',
4 Removed: #instVars : [
5 Removed: 'allMuscleGroups'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Forms',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Forms'
10 Removed: }
11 Removed:
12 Removed: { #category : 'as yet unclassified' }
13 Removed: MFTSecondaryMuscleGroupsFormComponent >> getSelectedMuscleGroups [
14 Removed:
15 Removed: | selectedMuscleGroups |
16 Removed: selectedMuscleGroups := allMuscleGroups select: [ :muscleGroup |
17 Removed: modelObject secondaryMuscleGroupIds
18 Removed: includes: muscleGroup id ].
19 Removed: ^ selectedMuscleGroups
20 Removed: ]
21 Removed:
22 Removed: { #category : 'initialization' }
23 Removed: MFTSecondaryMuscleGroupsFormComponent >> initialize [
24 Removed:
25 Removed: super initialize.
26 Removed: heading := 'Secondary Groups'.
27 Removed: allMuscleGroups := MFTSQLite3Database allMuscleGroups
28 Removed: ]
29 Removed:
30 Removed: { #category : 'rendering' }
31 Removed: MFTSecondaryMuscleGroupsFormComponent >> renderContentOn: html [
32 Removed:
33 Removed: self renderFormComponentOn: html with: [
34 Removed: html multiSelect formControl
35 Removed: list: allMuscleGroups;
36 Removed: selected: self getSelectedMuscleGroups;
37 Removed: labels: [ :muscleGroup | muscleGroup englishName ];
38 Removed: callback: [ :muscleGroups |
39 Removed: modelObject secondaryMuscleGroups: muscleGroups ] ]
40 Removed: ]
src/MyFitnessTracker/MFTSetDialog.class.st
index 1301a587..00000000 100644..000000
@@ -1,10 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'set'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
src/MyFitnessTracker/MFTSetGroupDialog.class.st
index 7af393d2..00000000 100644..000000
@@ -1,319 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetGroupDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'allExercises',
6 Removed: 'selectedExercises',
7 Removed: 'setGroup'
8 Removed: ],
9 Removed: #category : 'MyFitnessTracker-Dialogs',
10 Removed: #package : 'MyFitnessTracker',
11 Removed: #tag : 'Dialogs'
12 Removed: }
13 Removed:
14 Removed: { #category : 'as yet unclassified' }
15 Removed: MFTSetGroupDialog >> addSet [
16 Removed:
17 Removed: | set |
18 Removed: set := self call:
19 Removed: (MFTSetDialog newForExercise: selectedExercises first).
20 Removed: set ifNil: [ ^ self ].
21 Removed: setGroup sets ifEmpty: [ setGroup := MFTSetGroup new ].
22 Removed: setGroup addSet: (set exercise: selectedExercises first)
23 Removed: ]
24 Removed:
25 Removed: { #category : 'as yet unclassified' }
26 Removed: MFTSetGroupDialog >> addSets: aMFTExerciseCollection [
27 Removed:
28 Removed: | sets |
29 Removed: sets := self call:
30 Removed: ((MFTSetsDialog newForExercises:
31 Removed: aMFTExerciseCollection) subheading:
32 Removed: ((selectedExercises collect: #englishName) joinUsing: '/')).
33 Removed: sets ifNotEmpty: [ setGroup addSets: sets ]
34 Removed: ]
35 Removed:
36 Removed: { #category : 'as yet unclassified' }
37 Removed: MFTSetGroupDialog >> editSet: aMFTSet [
38 Removed:
39 Removed: | oldSet newSet |
40 Removed: oldSet := aMFTSet.
41 Removed: newSet := self call:
42 Removed: (MFTSetDialog
43 Removed: edit: oldSet copy
44 Removed: withExercise: selectedExercises first).
45 Removed: newSet ifNotNil: [ setGroup updateSet: oldSet with: newSet ]
46 Removed: ]
47 Removed:
48 Removed: { #category : 'as yet unclassified' }
49 Removed: MFTSetGroupDialog >> editSets: aMFTSetCollection [
50 Removed:
51 Removed: | oldSets newSets |
52 Removed: oldSets := aMFTSetCollection.
53 Removed: newSets := self call:
54 Removed: (MFTSetsDialog
55 Removed: edit: oldSets copy
56 Removed: withExercises: selectedExercises).
57 Removed: newSets ifNotEmpty: [ setGroup updateSets: oldSets with: newSets ]
58 Removed: ]
59 Removed:
60 Removed: { #category : 'initialization' }
61 Removed: MFTSetGroupDialog >> initialize [
62 Removed:
63 Removed: super initialize.
64 Removed: setGroup := MFTSetGroup new sets:
65 Removed: (OrderedCollection with: (MFTSet new reps: 8)).
66 Removed: allExercises := MFTSQLite3Database allExercises.
67 Removed: selectedExercises := OrderedCollection with: allExercises first
68 Removed: ]
69 Removed:
70 Removed: { #category : 'as yet unclassified' }
71 Removed: MFTSetGroupDialog >> makeGiantSet [
72 Removed:
73 Removed: self heading: 'Giant Sets'.
74 Removed: selectedExercises := OrderedCollection withAll:
75 Removed: (allExercises copyFrom: 1 to: 5).
76 Removed: self populateSetsForExercises: selectedExercises
77 Removed: ]
78 Removed:
79 Removed: { #category : 'as yet unclassified' }
80 Removed: MFTSetGroupDialog >> makeRegularExercise [
81 Removed:
82 Removed: self heading: 'Sets'.
83 Removed: selectedExercises := OrderedCollection with: allExercises first.
84 Removed: self populateSetsForExercises: selectedExercises
85 Removed: ]
86 Removed:
87 Removed: { #category : 'as yet unclassified' }
88 Removed: MFTSetGroupDialog >> makeSuperset [
89 Removed:
90 Removed: self heading: 'Supersets'.
91 Removed: selectedExercises := OrderedCollection
92 Removed: with: allExercises first
93 Removed: with: allExercises second.
94 Removed: self populateSetsForExercises: selectedExercises
95 Removed: ]
96 Removed:
97 Removed: { #category : 'as yet unclassified' }
98 Removed: MFTSetGroupDialog >> makeTriset [
99 Removed:
100 Removed: self heading: 'Tri-sets'.
101 Removed: selectedExercises := OrderedCollection
102 Removed: with: allExercises first
103 Removed: with: allExercises second
104 Removed: with: allExercises third.
105 Removed: self populateSetsForExercises: selectedExercises
106 Removed: ]
107 Removed:
108 Removed: { #category : 'as yet unclassified' }
109 Removed: MFTSetGroupDialog >> populateSetsForExercises: aMFTExerciseCollection [
110 Removed:
111 Removed: setGroup := MFTSetGroup new sets:
112 Removed: (aMFTExerciseCollection collect: [ :exercise |
113 Removed: MFTSet new
114 Removed: reps: 8;
115 Removed: exercise: exercise ])
116 Removed: ]
117 Removed:
118 Removed: { #category : 'as yet unclassified' }
119 Removed: MFTSetGroupDialog >> renderConfigureSetGroupButtonsOn: html [
120 Removed:
121 Removed: selectedExercises size = 1
122 Removed: ifTrue: [
123 Removed: html outlineButton bePrimary beSmall
124 Removed: class: 'me-2';
125 Removed: callback: [ self addSet ];
126 Removed: with: 'Add set' ]
127 Removed: ifFalse: [
128 Removed: html outlineButton bePrimary beSmall
129 Removed: class: 'me-2';
130 Removed: callback: [ self addSets: selectedExercises ];
131 Removed: with: 'Add set group' ].
132 Removed: html buttonGroup: [
133 Removed: selectedExercises size ~~ 1 ifTrue: [
134 Removed: html outlineButton beSecondary beSmall
135 Removed: callback: [ self makeRegularExercise ];
136 Removed: with: 'Regular exercise' ].
137 Removed: selectedExercises size ~~ 2 ifTrue: [
138 Removed: html outlineButton beSecondary beSmall
139 Removed: callback: [ self makeSuperset ];
140 Removed: with: 'Superset' ].
141 Removed: selectedExercises size ~~ 3 ifTrue: [
142 Removed: html outlineButton beSecondary beSmall
143 Removed: callback: [ self makeTriset ];
144 Removed: with: 'Tri-set' ].
145 Removed: selectedExercises size < 4 ifTrue: [
146 Removed: html outlineButton beSecondary beSmall
147 Removed: callback: [ self makeGiantSet ];
148 Removed: with: 'Giant set' ] ]
149 Removed: ]
150 Removed:
151 Removed: { #category : 'rendering' }
152 Removed: MFTSetGroupDialog >> renderContentOn: html [
153 Removed:
154 Removed: self renderDialogOn: html with: [
155 Removed: self renderSelectExercisesOn: html.
156 Removed: html horizontalRule.
157 Removed: setGroup sets ifNotEmpty: [ self renderSetGroupTableOn: html ].
158 Removed: self renderConfigureSetGroupButtonsOn: html ]
159 Removed: ]
160 Removed:
161 Removed: { #category : 'as yet unclassified' }
162 Removed: MFTSetGroupDialog >> renderSelectExercisesOn: html [
163 Removed:
164 Removed: | allSets |
165 Removed: allSets := setGroup sets.
166 Removed: selectedExercises doWithIndex: [ :selectedExercise :i |
167 Removed: html formGroup: [
168 Removed: html label: 'Exercise ' , (selectedExercises size > 1
169 Removed: ifTrue: [ i asString ]
170 Removed: ifFalse: [ '' ]).
171 Removed: html select formControl
172 Removed: list: allExercises;
173 Removed: selected: selectedExercise;
174 Removed: callback: [ :exercise |
175 Removed: selectedExercises at: i put: exercise.
176 Removed: self updateAllSelectedExercises ];
177 Removed: labels: [ :each | each englishName ] ] ]
178 Removed: ]
179 Removed:
180 Removed: { #category : 'rendering' }
181 Removed: MFTSetGroupDialog >> renderSetGroupRowsOn: html [
182 Removed:
183 Removed: setGroup sets doWithIndex: [ :set :i |
184 Removed: (i - 1 isDivisibleBy: selectedExercises size) ifTrue: [
185 Removed: | selectedSets |
186 Removed: selectedSets := setGroup sets atAll:
187 Removed: (i to: i + selectedExercises size - 1).
188 Removed: html tableRow with: [
189 Removed: html tableData
190 Removed: attributeAt: 'rowspan' put: selectedExercises size + 1;
191 Removed: style: 'vertical-align: middle';
192 Removed: with: [
193 Removed: html buttonGroup: [
194 Removed: html outlineButton
195 Removed: beDanger;
196 Removed: beSmall;
197 Removed: callback: [ setGroup removeSets: selectedSets ];
198 Removed: with: 'Remove'.
199 Removed: html outlineButton
200 Removed: beSecondary;
201 Removed: beSmall;
202 Removed: callback: [
203 Removed: selectedSets size = 1
204 Removed: ifTrue: [ self editSet: selectedSets first ]
205 Removed: ifFalse: [ self editSets: selectedSets ] ];
206 Removed: with: 'Edit'.
207 Removed: selectedExercises size = 1 ifTrue: [
208 Removed: html outlineButton
209 Removed: beSecondary;
210 Removed: beSmall;
211 Removed: callback: [ setGroup duplicateSet: selectedSets first ];
212 Removed: with: 'Duplicate' ] ] ] ] ].
213 Removed:
214 Removed: html tableRow: [ "This row spans the amount of sets for a given exercise."
215 Removed: setGroup isIrregularSetGroup ifTrue: [
216 Removed: html tableData with: set exercise englishName capitalized ].
217 Removed: html tableData
218 Removed: style: 'text-align: right';
219 Removed: with: set reps.
220 Removed: setGroup hasLoad ifTrue: [
221 Removed: html tableData
222 Removed: style: 'text-align: right';
223 Removed: with: set load ].
224 Removed: setGroup hasRpe ifTrue: [
225 Removed: html tableData
226 Removed: style: 'text-align: right';
227 Removed: with: set rpe ].
228 Removed: setGroup hasRestAfter ifTrue: [
229 Removed: html tableData
230 Removed: style: 'text-align: right';
231 Removed: with: set restAfter ] ] ]
232 Removed: ]
233 Removed:
234 Removed: { #category : 'rendering' }
235 Removed: MFTSetGroupDialog >> renderSetGroupTableHeaderOn: html [
236 Removed:
237 Removed: html tableHead: [
238 Removed: html tableHeading.
239 Removed: setGroup isIrregularSetGroup ifTrue: [
240 Removed: html tableHeading with: 'Exercise' ].
241 Removed: html tableHeading
242 Removed: style: 'text-align: right';
243 Removed: with: 'Reps'.
244 Removed: setGroup hasLoad ifTrue: [
245 Removed: html tableHeading
246 Removed: style: 'text-align: right';
247 Removed: with: 'Load' ].
248 Removed: setGroup hasRpe ifTrue: [
249 Removed: html tableHeading
250 Removed: style: 'text-align: right';
251 Removed: with: 'RPE' ].
252 Removed: setGroup hasRestAfter ifTrue: [
253 Removed: html tableHeading
254 Removed: style: 'text-align: right';
255 Removed: with: 'Rest After (s)' ] ]
256 Removed: ]
257 Removed:
258 Removed: { #category : 'rendering' }
259 Removed: MFTSetGroupDialog >> renderSetGroupTableOn: html [
260 Removed:
261 Removed: html table
262 Removed: class: 'table table-bordered';
263 Removed: with: [
264 Removed: self renderSetGroupTableHeaderOn: html.
265 Removed: self renderSetGroupRowsOn: html ]
266 Removed: ]
267 Removed:
268 Removed: { #category : 'as yet unclassified' }
269 Removed: MFTSetGroupDialog >> renderSubmitOn: html [
270 Removed:
271 Removed: html buttonGroup: [
272 Removed: html formButton
273 Removed: beSubmit;
274 Removed: bePrimary;
275 Removed: callback: [ self answer: setGroup ];
276 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
277 Removed: html formButton
278 Removed: beSubmit;
279 Removed: beSecondary;
280 Removed: callback: [ self answer: nil ];
281 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
282 Removed: ]
283 Removed:
284 Removed: { #category : 'as yet unclassified' }
285 Removed: MFTSetGroupDialog >> selectedExercises [
286 Removed:
287 Removed: ^ selectedExercises
288 Removed: ]
289 Removed:
290 Removed: { #category : 'as yet unclassified' }
291 Removed: MFTSetGroupDialog >> selectedExercises: aMFTExerciseCollection [
292 Removed:
293 Removed: selectedExercises := aMFTExerciseCollection
294 Removed: ]
295 Removed:
296 Removed: { #category : 'as yet unclassified' }
297 Removed: MFTSetGroupDialog >> setGroup [
298 Removed:
299 Removed: ^ setGroup
300 Removed: ]
301 Removed:
302 Removed: { #category : 'as yet unclassified' }
303 Removed: MFTSetGroupDialog >> setGroup: anObject [
304 Removed:
305 Removed: setGroup := anObject
306 Removed: ]
307 Removed:
308 Removed: { #category : 'as yet unclassified' }
309 Removed: MFTSetGroupDialog >> updateAllSelectedExercises [
310 Removed:
311 Removed: | allSets |
312 Removed: allSets := setGroup sets.
313 Removed: selectedExercises doWithIndex: [ :selectedExercise :i |
314 Removed: i to: allSets size by: selectedExercises size do: [ :j |
315 Removed: | set |
316 Removed: "Update every nth set to reflect the newly selected exercise selectedExercises at: i."
317 Removed: set := allSets at: j.
318 Removed: set exercise: selectedExercise ] ]
319 Removed: ]
src/MyFitnessTracker/MFTSetGroupForm.class.st
index 1002a9e8..00000000 100644..000000
@@ -1,144 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetGroupForm',
3 Removed: #superclass : 'MFTForm',
4 Removed: #instVars : [
5 Removed: 'exerciseCount',
6 Removed: 'renderRpe',
7 Removed: 'renderRestAfter'
8 Removed: ],
9 Removed: #category : 'MyFitnessTracker-Forms',
10 Removed: #package : 'MyFitnessTracker',
11 Removed: #tag : 'Forms'
12 Removed: }
13 Removed:
14 Removed: { #category : 'as yet unclassified' }
15 Removed: MFTSetGroupForm class >> forExercises: anMFTExerciseCollection [
16 Removed:
17 Removed: | setGroup |
18 Removed: setGroup := MFTSetGroup new addSets:
19 Removed: (anMFTExerciseCollection collect: [ :exercise |
20 Removed: MFTSet new
21 Removed: exercise: exercise;
22 Removed: reps: 8 ]).
23 Removed: ^ self new
24 Removed: modelObject: setGroup;
25 Removed: exerciseCount: anMFTExerciseCollection size;
26 Removed: yourself
27 Removed: ]
28 Removed:
29 Removed: { #category : 'accessing' }
30 Removed: MFTSetGroupForm >> exerciseCount: anInteger [
31 Removed:
32 Removed: exerciseCount := anInteger
33 Removed: ]
34 Removed:
35 Removed: { #category : 'initialization' }
36 Removed: MFTSetGroupForm >> initialize [
37 Removed:
38 Removed: super initialize.
39 Removed: modelObject := MFTSetGroup new addSet: (MFTSet new reps: 8).
40 Removed: heading := 'Sets'.
41 Removed: renderRpe := false.
42 Removed: renderRestAfter := false
43 Removed: ]
44 Removed:
45 Removed: { #category : 'rendering' }
46 Removed: MFTSetGroupForm >> renderContentOn: html [
47 Removed:
48 Removed: self renderFormOn: html with: [
49 Removed: self renderSetsButtonGroupOn: html.
50 Removed: self renderSetGroupTableOn: html ]
51 Removed: ]
52 Removed:
53 Removed: { #category : 'rendering' }
54 Removed: MFTSetGroupForm >> renderSetGroupRowsOn: html [
55 Removed:
56 Removed: | selectedExercises renderSetGroupExercisesName |
57 Removed: selectedExercises := modelObject sets collect: #exercise.
58 Removed: renderSetGroupExercisesName := modelObject isIrregularSetGroup.
59 Removed:
60 Removed: modelObject sets do: [ :set |
61 Removed: html tableRow: [
62 Removed: renderSetGroupExercisesName ifTrue: [
63 Removed: html tableData with: set exercise englishName capitalized ].
64 Removed: html tableData: [
65 Removed: html numberInput formControl
66 Removed: value: set reps;
67 Removed: callback: [ :value | set reps: value asInteger ] ].
68 Removed: html tableData: [
69 Removed: html numberInput formControl
70 Removed: value: set load;
71 Removed: callback: [ :value |
72 Removed: set load:
73 Removed: (value ifNotEmpty: [ value asNumber ] ifEmpty: [ nil ]) ] ].
74 Removed: renderRpe ifTrue: [
75 Removed: html tableData: [
76 Removed: html numberInput formControl
77 Removed: value: set rpe;
78 Removed: callback: [ :value |
79 Removed: set rpe:
80 Removed: (value ifNotEmpty: [ value asInteger ] ifEmpty: [ nil ]) ] ] ].
81 Removed: renderRestAfter ifTrue: [
82 Removed: html tableData: [
83 Removed: html numberInput formControl
84 Removed: value: set restAfter;
85 Removed: callback: [ :value |
86 Removed: set restAfter:
87 Removed: (value ifNotEmpty: [ value asNumber ] ifEmpty: [ nil ]) ] ] ] ] ]
88 Removed: ]
89 Removed:
90 Removed: { #category : 'rendering' }
91 Removed: MFTSetGroupForm >> renderSetGroupTableHeaderOn: html [
92 Removed:
93 Removed: html tableHead: [
94 Removed: modelObject isIrregularSetGroup ifTrue: [
95 Removed: html tableHeading with: 'Exercise' ].
96 Removed: html tableHeading with: 'Reps'.
97 Removed: html tableHeading with: 'Load'.
98 Removed: renderRpe ifTrue: [ html tableHeading with: 'RPE' ].
99 Removed: renderRestAfter ifTrue: [ html tableHeading with: 'Rest After (s)' ] ]
100 Removed: ]
101 Removed:
102 Removed: { #category : 'rendering' }
103 Removed: MFTSetGroupForm >> renderSetGroupTableOn: html [
104 Removed:
105 Removed: html table
106 Removed: class: 'table table-bordered';
107 Removed: with: [
108 Removed: self renderSetGroupTableHeaderOn: html.
109 Removed: self renderSetGroupRowsOn: html ]
110 Removed: ]
111 Removed:
112 Removed: { #category : 'rendering' }
113 Removed: MFTSetGroupForm >> renderSetsButtonGroupOn: html [
114 Removed:
115 Removed: html buttonGroup
116 Removed: class: 'my-3';
117 Removed: with: [
118 Removed: html outlineButton
119 Removed: bePrimary;
120 Removed: beSmall;
121 Removed: callback: [ modelObject addSets: modelObject sets ];
122 Removed: with: 'Add sets'.
123 Removed: renderRpe ifFalse: [
124 Removed: html outlineButton
125 Removed: beSecondary;
126 Removed: beSmall;
127 Removed: callback: [ renderRpe := true ];
128 Removed: with: 'Add RPE' ].
129 Removed: renderRestAfter ifFalse: [
130 Removed: html outlineButton
131 Removed: beSecondary;
132 Removed: beSmall;
133 Removed: callback: [ renderRestAfter := true ];
134 Removed: with: 'Add rest' ].
135 Removed: html outlineButton
136 Removed: beDanger;
137 Removed: beSmall;
138 Removed: callback: [
139 Removed: | firstSets |
140 Removed: firstSets := modelObject sets first: exerciseCount.
141 Removed: modelObject := MFTSetGroup new addSets: firstSets.
142 Removed: renderRpe := renderRestAfter := false ];
143 Removed: with: 'Reset' ]
144 Removed: ]
src/MyFitnessTracker/MFTSetGroupTask.class.st
index 05b6ff4c..00000000 100644..000000
@@ -1,63 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetGroupTask',
3 Removed: #superclass : 'WATask',
4 Removed: #instVars : [
5 Removed: 'exercises',
6 Removed: 'exerciseCount',
7 Removed: 'setGroup'
8 Removed: ],
9 Removed: #category : 'MyFitnessTracker-Tasks',
10 Removed: #package : 'MyFitnessTracker',
11 Removed: #tag : 'Tasks'
12 Removed: }
13 Removed:
14 Removed: { #category : 'as yet unclassified' }
15 Removed: MFTSetGroupTask class >> forExerciseCount: anInteger [
16 Removed:
17 Removed: ^ self new
18 Removed: exerciseCount: anInteger;
19 Removed: yourself
20 Removed: ]
21 Removed:
22 Removed: { #category : 'accessing' }
23 Removed: MFTSetGroupTask >> exerciseCount: anObject [
24 Removed:
25 Removed: exerciseCount := anObject
26 Removed: ]
27 Removed:
28 Removed: { #category : 'accessing' }
29 Removed: MFTSetGroupTask >> exercises [
30 Removed:
31 Removed: ^ exercises
32 Removed: ]
33 Removed:
34 Removed: { #category : 'accessing' }
35 Removed: MFTSetGroupTask >> exercises: anObject [
36 Removed:
37 Removed: exercises := anObject
38 Removed: ]
39 Removed:
40 Removed: { #category : 'running' }
41 Removed: MFTSetGroupTask >> go [
42 Removed:
43 Removed: exercises := self call:
44 Removed: (MFTExercisesForm forExerciseCount: exerciseCount).
45 Removed: exercises ifNil: [ self answer: nil ].
46 Removed:
47 Removed: setGroup := self call: (MFTSetGroupForm forExercises: exercises).
48 Removed: setGroup ifNil: [ self answer: nil ].
49 Removed:
50 Removed: self answer: setGroup
51 Removed: ]
52 Removed:
53 Removed: { #category : 'accessing' }
54 Removed: MFTSetGroupTask >> setGroups [
55 Removed:
56 Removed: ^ setGroups
57 Removed: ]
58 Removed:
59 Removed: { #category : 'accessing' }
60 Removed: MFTSetGroupTask >> setGroups: anObject [
61 Removed:
62 Removed: setGroups := anObject
63 Removed: ]
src/MyFitnessTracker/MFTSetGroupsDialog.class.st
index 2a0ff58c..00000000 100644..000000
@@ -1,179 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetGroupsDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'setGroups'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'as yet unclassified' }
13 Removed: MFTSetGroupsDialog >> addExercise [
14 Removed:
15 Removed: | setGroup |
16 Removed: setGroup := self call: (MFTSetGroupDialog new heading: 'Exercise').
17 Removed: setGroup ifNotNil: [ setGroups add: setGroup ]
18 Removed: ]
19 Removed:
20 Removed: { #category : 'as yet unclassified' }
21 Removed: MFTSetGroupsDialog >> editSetGroup: aMFTSetGroup [
22 Removed:
23 Removed: | oldSetGroup newSetGroup |
24 Removed: oldSetGroup := aMFTSetGroup.
25 Removed: newSetGroup := self call: (MFTSetGroupDialog edit: aMFTSetGroup copy).
26 Removed: newSetGroup ifNotNil: [
27 Removed: setGroups at: (setGroups indexOf: oldSetGroup) put: newSetGroup ]
28 Removed: ]
29 Removed:
30 Removed: { #category : 'as yet unclassified' }
31 Removed: MFTSetGroupsDialog >> initialize [
32 Removed:
33 Removed: super initialize.
34 Removed: setGroups := OrderedCollection new
35 Removed: ]
36 Removed:
37 Removed: { #category : 'as yet unclassified' }
38 Removed: MFTSetGroupsDialog >> renderAddSetGroupButtonsOn: html [
39 Removed:
40 Removed: html outlineButton
41 Removed: bePrimary;
42 Removed: beSmall;
43 Removed: callback: [ self addExercise ];
44 Removed: with: 'Add exercise'
45 Removed: ]
46 Removed:
47 Removed: { #category : 'as yet unclassified' }
48 Removed: MFTSetGroupsDialog >> renderContentOn: html [
49 Removed:
50 Removed: self renderDialogOn: html with: [
51 Removed: setGroups ifNotEmpty: [ self renderSetsTableOn: html ].
52 Removed: self renderAddSetGroupButtonsOn: html ]
53 Removed: ]
54 Removed:
55 Removed: { #category : 'as yet unclassified' }
56 Removed: MFTSetGroupsDialog >> renderLoad [
57 Removed:
58 Removed: ^ (setGroups flatCollect: #sets) anySatisfy: #hasLoad
59 Removed: ]
60 Removed:
61 Removed: { #category : 'as yet unclassified' }
62 Removed: MFTSetGroupsDialog >> renderRestAfter [
63 Removed:
64 Removed: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRestAfter
65 Removed: ]
66 Removed:
67 Removed: { #category : 'as yet unclassified' }
68 Removed: MFTSetGroupsDialog >> renderRpe [
69 Removed:
70 Removed: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRpe
71 Removed: ]
72 Removed:
73 Removed: { #category : 'as yet unclassified' }
74 Removed: MFTSetGroupsDialog >> renderSetGroupButtonsOn: html For: setGroup [
75 Removed:
76 Removed: html buttonGroup: [
77 Removed: html outlineButton
78 Removed: beDanger;
79 Removed: beSmall;
80 Removed: callback: [ setGroups remove: setGroup ];
81 Removed: with: 'Remove'.
82 Removed: html outlineButton
83 Removed: beSecondary;
84 Removed: beSmall;
85 Removed: callback: [ self editSetGroup: setGroup ];
86 Removed: with: 'Edit'.
87 Removed: html outlineButton
88 Removed: beSecondary;
89 Removed: beSmall;
90 Removed: callback: [
91 Removed: setGroups add: setGroup afterIndex: (setGroups indexOf: setGroup) ];
92 Removed: with: 'Duplicate' ]
93 Removed: ]
94 Removed:
95 Removed: { #category : 'as yet unclassified' }
96 Removed: MFTSetGroupsDialog >> renderSetGroupsRowsOn: html [
97 Removed:
98 Removed: | renderLoad renderRpe renderRestAfter |
99 Removed: renderLoad := self renderLoad.
100 Removed: renderRpe := self renderRpe.
101 Removed: renderRestAfter := self renderRestAfter.
102 Removed: setGroups do: [ :setGroup |
103 Removed: html tableRow with: [
104 Removed: html tableData
105 Removed: attributeAt: 'rowspan' put: setGroup sets size + 1;
106 Removed: style: 'vertical-align: middle';
107 Removed: with: [ self renderSetGroupButtonsOn: html For: setGroup ] ].
108 Removed: setGroup sets do: [ :set |
109 Removed: html tableRow: [
110 Removed: html tableData: set exercise englishName.
111 Removed: html tableData: set reps.
112 Removed: setGroup hasLoad ifTrue: [ html tableData: set load ].
113 Removed: setGroup hasRpe ifTrue: [ html tableData: set rpe ].
114 Removed: setGroup hasRestAfter ifTrue: [ html tableData: set restAfter ] ] ] ]
115 Removed: ]
116 Removed:
117 Removed: { #category : 'as yet unclassified' }
118 Removed: MFTSetGroupsDialog >> renderSetGroupsTableHeaderOn: html [
119 Removed:
120 Removed: html tableHead: [
121 Removed: html
122 Removed: tableHeading;
123 Removed: tableHeading: 'Exercise';
124 Removed: tableHeading: 'Reps'.
125 Removed: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
126 Removed: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
127 Removed: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
128 Removed: ]
129 Removed:
130 Removed: { #category : 'as yet unclassified' }
131 Removed: MFTSetGroupsDialog >> renderSetsTableHeaderOn: html [
132 Removed:
133 Removed: html tableHead: [
134 Removed: html
135 Removed: tableHeading;
136 Removed: tableHeading: 'Exercise';
137 Removed: tableHeading: 'Reps'.
138 Removed: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
139 Removed: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
140 Removed: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
141 Removed: ]
142 Removed:
143 Removed: { #category : 'as yet unclassified' }
144 Removed: MFTSetGroupsDialog >> renderSetsTableOn: html [
145 Removed:
146 Removed: html table
147 Removed: class: 'table table-bordered';
148 Removed: with: [
149 Removed: self renderSetGroupsTableHeaderOn: html.
150 Removed: self renderSetGroupsRowsOn: html ]
151 Removed: ]
152 Removed:
153 Removed: { #category : 'as yet unclassified' }
154 Removed: MFTSetGroupsDialog >> renderSubmitOn: html [
155 Removed:
156 Removed: html buttonGroup: [
157 Removed: html formButton
158 Removed: beSubmit;
159 Removed: bePrimary;
160 Removed: callback: [ self answer: setGroups ];
161 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
162 Removed: html formButton
163 Removed: beSubmit;
164 Removed: beSecondary;
165 Removed: callback: [ self answer: OrderedCollection new ];
166 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
167 Removed: ]
168 Removed:
169 Removed: { #category : 'as yet unclassified' }
170 Removed: MFTSetGroupsDialog >> setGroups [
171 Removed:
172 Removed: ^ setGroups
173 Removed: ]
174 Removed:
175 Removed: { #category : 'as yet unclassified' }
176 Removed: MFTSetGroupsDialog >> setGroups: anObject [
177 Removed:
178 Removed: setGroups := anObject
179 Removed: ]
src/MyFitnessTracker/MFTSetGroupsDialogOld.class.st
index cb18e1eb..00000000 100644..000000
@@ -1,179 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetGroupsDialogOld',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'setGroups'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'adding' }
13 Removed: MFTSetGroupsDialogOld >> addExercise [
14 Removed:
15 Removed: | setGroup |
16 Removed: setGroup := self call: (MFTSetGroupDialog new heading: 'Exercise').
17 Removed: setGroup ifNotNil: [ setGroups add: setGroup ]
18 Removed: ]
19 Removed:
20 Removed: { #category : 'rendering' }
21 Removed: MFTSetGroupsDialogOld >> editSetGroup: aMFTSetGroup [
22 Removed:
23 Removed: | oldSetGroup newSetGroup |
24 Removed: oldSetGroup := aMFTSetGroup.
25 Removed: newSetGroup := self call: (MFTSetGroupDialog edit: aMFTSetGroup copy).
26 Removed: newSetGroup ifNotNil: [
27 Removed: setGroups at: (setGroups indexOf: oldSetGroup) put: newSetGroup ]
28 Removed: ]
29 Removed:
30 Removed: { #category : 'initialization' }
31 Removed: MFTSetGroupsDialogOld >> initialize [
32 Removed:
33 Removed: super initialize.
34 Removed: setGroups := OrderedCollection new
35 Removed: ]
36 Removed:
37 Removed: { #category : 'rendering' }
38 Removed: MFTSetGroupsDialogOld >> renderAddSetGroupButtonsOn: html [
39 Removed:
40 Removed: html outlineButton
41 Removed: bePrimary;
42 Removed: beSmall;
43 Removed: callback: [ self addExercise ];
44 Removed: with: 'Add exercise'
45 Removed: ]
46 Removed:
47 Removed: { #category : 'rendering' }
48 Removed: MFTSetGroupsDialogOld >> renderContentOn: html [
49 Removed:
50 Removed: self renderDialogOn: html with: [
51 Removed: setGroups ifNotEmpty: [ self renderSetsTableOn: html ].
52 Removed: self renderAddSetGroupButtonsOn: html ]
53 Removed: ]
54 Removed:
55 Removed: { #category : 'as yet unclassified' }
56 Removed: MFTSetGroupsDialogOld >> renderLoad [
57 Removed:
58 Removed: ^ (setGroups flatCollect: #sets) anySatisfy: #hasLoad
59 Removed: ]
60 Removed:
61 Removed: { #category : 'as yet unclassified' }
62 Removed: MFTSetGroupsDialogOld >> renderRestAfter [
63 Removed:
64 Removed: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRestAfter
65 Removed: ]
66 Removed:
67 Removed: { #category : 'as yet unclassified' }
68 Removed: MFTSetGroupsDialogOld >> renderRpe [
69 Removed:
70 Removed: ^ (setGroups flatCollect: #sets) anySatisfy: #hasRpe
71 Removed: ]
72 Removed:
73 Removed: { #category : 'as yet unclassified' }
74 Removed: MFTSetGroupsDialogOld >> renderSetGroupButtonsOn: html For: setGroup [
75 Removed:
76 Removed: html buttonGroup: [
77 Removed: html outlineButton
78 Removed: beDanger;
79 Removed: beSmall;
80 Removed: callback: [ setGroups remove: setGroup ];
81 Removed: with: 'Remove'.
82 Removed: html outlineButton
83 Removed: beSecondary;
84 Removed: beSmall;
85 Removed: callback: [ self editSetGroup: setGroup ];
86 Removed: with: 'Edit'.
87 Removed: html outlineButton
88 Removed: beSecondary;
89 Removed: beSmall;
90 Removed: callback: [
91 Removed: setGroups add: setGroup afterIndex: (setGroups indexOf: setGroup) ];
92 Removed: with: 'Duplicate' ]
93 Removed: ]
94 Removed:
95 Removed: { #category : 'as yet unclassified' }
96 Removed: MFTSetGroupsDialogOld >> renderSetGroupsRowsOn: html [
97 Removed:
98 Removed: | renderLoad renderRpe renderRestAfter |
99 Removed: renderLoad := self renderLoad.
100 Removed: renderRpe := self renderRpe.
101 Removed: renderRestAfter := self renderRestAfter.
102 Removed: setGroups do: [ :setGroup |
103 Removed: html tableRow with: [
104 Removed: html tableData
105 Removed: attributeAt: 'rowspan' put: setGroup sets size + 1;
106 Removed: style: 'vertical-align: middle';
107 Removed: with: [ self renderSetGroupButtonsOn: html For: setGroup ] ].
108 Removed: setGroup sets do: [ :set |
109 Removed: html tableRow: [
110 Removed: html tableData: set exercise englishName.
111 Removed: html tableData: set reps.
112 Removed: setGroup hasLoad ifTrue: [ html tableData: set load ].
113 Removed: setGroup hasRpe ifTrue: [ html tableData: set rpe ].
114 Removed: setGroup hasRestAfter ifTrue: [ html tableData: set restAfter ] ] ] ]
115 Removed: ]
116 Removed:
117 Removed: { #category : 'as yet unclassified' }
118 Removed: MFTSetGroupsDialogOld >> renderSetGroupsTableHeaderOn: html [
119 Removed:
120 Removed: html tableHead: [
121 Removed: html
122 Removed: tableHeading;
123 Removed: tableHeading: 'Exercise';
124 Removed: tableHeading: 'Reps'.
125 Removed: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
126 Removed: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
127 Removed: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
128 Removed: ]
129 Removed:
130 Removed: { #category : 'as yet unclassified' }
131 Removed: MFTSetGroupsDialogOld >> renderSetsTableHeaderOn: html [
132 Removed:
133 Removed: html tableHead: [
134 Removed: html
135 Removed: tableHeading;
136 Removed: tableHeading: 'Exercise';
137 Removed: tableHeading: 'Reps'.
138 Removed: self renderLoad ifTrue: [ html tableHeading: 'Load' ].
139 Removed: self renderRpe ifTrue: [ html tableHeading: 'RPE' ].
140 Removed: self renderRestAfter ifTrue: [ html tableHeading: 'Rest after (s) ' ] ]
141 Removed: ]
142 Removed:
143 Removed: { #category : 'as yet unclassified' }
144 Removed: MFTSetGroupsDialogOld >> renderSetsTableOn: html [
145 Removed:
146 Removed: html table
147 Removed: class: 'table table-bordered';
148 Removed: with: [
149 Removed: self renderSetGroupsTableHeaderOn: html.
150 Removed: self renderSetGroupsRowsOn: html ]
151 Removed: ]
152 Removed:
153 Removed: { #category : 'rendering' }
154 Removed: MFTSetGroupsDialogOld >> renderSubmitOn: html [
155 Removed:
156 Removed: html buttonGroup: [
157 Removed: html formButton
158 Removed: beSubmit;
159 Removed: bePrimary;
160 Removed: callback: [ self answer: setGroups ];
161 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
162 Removed: html formButton
163 Removed: beSubmit;
164 Removed: beSecondary;
165 Removed: callback: [ self answer: OrderedCollection new ];
166 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
167 Removed: ]
168 Removed:
169 Removed: { #category : 'accessing' }
170 Removed: MFTSetGroupsDialogOld >> setGroups [
171 Removed:
172 Removed: ^ setGroups
173 Removed: ]
174 Removed:
175 Removed: { #category : 'accessing' }
176 Removed: MFTSetGroupsDialogOld >> setGroups: anObject [
177 Removed:
178 Removed: setGroups := anObject
179 Removed: ]
src/MyFitnessTracker/MFTSetGroupsFormComponent.class.st
index 1197d4f4..00000000 100644..000000
@@ -1,62 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetGroupsFormComponent',
3 Removed: #superclass : 'MFTFormComponent',
4 Removed: #category : 'MyFitnessTracker-Forms',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Forms'
7 Removed: }
8 Removed:
9 Removed: { #category : 'adding' }
10 Removed: MFTSetGroupsFormComponent >> addSetGroupsForExerciseCount: anInteger [
11 Removed:
12 Removed: | setGroup |
13 Removed: setGroup := self session pageManager activePage call:
14 Removed: (MFTSetGroupTask forExerciseCount: anInteger).
15 Removed: setGroup ifNotNil: [ modelObject addSetGroup: setGroup ]
16 Removed: ]
17 Removed:
18 Removed: { #category : 'initialization' }
19 Removed: MFTSetGroupsFormComponent >> initialize [
20 Removed:
21 Removed: super initialize.
22 Removed: heading := 'Exercises'
23 Removed: ]
24 Removed:
25 Removed: { #category : 'rendering' }
26 Removed: MFTSetGroupsFormComponent >> renderContentOn: html [
27 Removed:
28 Removed: self renderFormComponentOn: html with: [
29 Removed: modelObject renderSetGroupsTableOn: html.
30 Removed: self renderSetGroupButtonsOn: html ]
31 Removed: ]
32 Removed:
33 Removed: { #category : 'rendering' }
34 Removed: MFTSetGroupsFormComponent >> renderSetGroupButtonsOn: html [
35 Removed:
36 Removed: html buttonGroup: [
37 Removed: html outlineButton
38 Removed: bePrimary;
39 Removed: beSmall;
40 Removed: callback: [ self addSetGroupsForExerciseCount: 1 ];
41 Removed: with: 'Add exercise'.
42 Removed: html outlineButton
43 Removed: beSecondary;
44 Removed: beSmall;
45 Removed: callback: [ self addSetGroupsForExerciseCount: 2 ];
46 Removed: with: 'Add superset'.
47 Removed: html outlineButton
48 Removed: beSecondary;
49 Removed: beSmall;
50 Removed: callback: [ self addSetGroupsForExerciseCount: 3 ];
51 Removed: with: 'Add tri-set'.
52 Removed: html outlineButton
53 Removed: beSecondary;
54 Removed: beSmall;
55 Removed: callback: [ self addSetGroupsForExerciseCount: 4 ];
56 Removed: with: 'Add giant set'.
57 Removed: html outlineButton
58 Removed: beDanger;
59 Removed: beSmall;
60 Removed: callback: [ modelObject setGroups removeAll ];
61 Removed: with: 'Remove all' ]
62 Removed: ]
src/MyFitnessTracker/MFTSetsDialog.class.st
index 2aff4f3d..00000000 100644..000000
@@ -1,10 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTSetsDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'sets'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
src/MyFitnessTracker/MFTStringDialog.class.st
index 6087f3b4..00000000 100644..000000
@@ -1,58 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTStringDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'string'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'as yet unclassified' }
13 Removed: MFTStringDialog class >> edit: aString [
14 Removed:
15 Removed: ^ self new
16 Removed: action: #edit;
17 Removed: string: aString;
18 Removed: yourself
19 Removed: ]
20 Removed:
21 Removed: { #category : 'as yet unclassified' }
22 Removed: MFTStringDialog >> initialize [
23 Removed:
24 Removed: super initialize.
25 Removed: string := String new
26 Removed: ]
27 Removed:
28 Removed: { #category : 'as yet unclassified' }
29 Removed: MFTStringDialog >> renderContentOn: html [
30 Removed:
31 Removed: self renderDialogOn: html with: [
32 Removed: html textInput formControl
33 Removed: value: string;
34 Removed: callback: [ :value | string := value ] ]
35 Removed: ]
36 Removed:
37 Removed: { #category : 'as yet unclassified' }
38 Removed: MFTStringDialog >> renderSubmitOn: html [
39 Removed:
40 Removed: html buttonGroup: [
41 Removed: html formButton
42 Removed: beSubmit;
43 Removed: bePrimary;
44 Removed: callback: [ self answer: string ];
45 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]) ]
46 Removed: ]
47 Removed:
48 Removed: { #category : 'as yet unclassified' }
49 Removed: MFTStringDialog >> string [
50 Removed:
51 Removed: ^ string
52 Removed: ]
53 Removed:
54 Removed: { #category : 'as yet unclassified' }
55 Removed: MFTStringDialog >> string: anObject [
56 Removed:
57 Removed: string := anObject
58 Removed: ]
src/MyFitnessTracker/MFTUserLandingPage.class.st
index 56a9079f..00000000 100644..000000
@@ -1,15 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTUserLandingPage',
3 Removed: #superclass : 'MFTLandingPage',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTUserLandingPage >> defaultCards [
11 Removed:
12 Removed: ^ {
13 Removed: MFTMainUserCard new.
14 Removed: MFTWorkoutsCard new }
15 Removed: ]
src/MyFitnessTracker/MFTUserTask.class.st
index 14c1f287..00000000 100644..000000
@@ -1,85 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTUserTask',
3 Removed: #superclass : 'WATask',
4 Removed: #instVars : [
5 Removed: 'user',
6 Removed: 'action'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Tasks',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Tasks'
11 Removed: }
12 Removed:
13 Removed: { #category : 'actions' }
14 Removed: MFTUserTask class >> edit: aMFTUser [
15 Removed:
16 Removed: ^ self new
17 Removed: user: aMFTUser;
18 Removed: action: #edit;
19 Removed: yourself
20 Removed: ]
21 Removed:
22 Removed: { #category : 'accessing' }
23 Removed: MFTUserTask >> action [
24 Removed:
25 Removed: ^ action
26 Removed: ]
27 Removed:
28 Removed: { #category : 'accessing' }
29 Removed: MFTUserTask >> action: anObject [
30 Removed:
31 Removed: action := anObject
32 Removed: ]
33 Removed:
34 Removed: { #category : 'running' }
35 Removed: MFTUserTask >> go [
36 Removed:
37 Removed: user username: (self call: (MFTStringDialog new
38 Removed: action: action;
39 Removed: heading: 'username';
40 Removed: string: user username;
41 Removed: completion: 20)).
42 Removed: user passwordHashFromString: (self call: (MFTStringDialog new
43 Removed: action: action;
44 Removed: heading: 'password';
45 Removed: completion: 40)).
46 Removed: user dateOfBirth: (self call: (MFTDateDialog new
47 Removed: action: action;
48 Removed: heading: 'date of birth';
49 Removed: date: user dateOfBirth;
50 Removed: completion: 60)).
51 Removed: user realFirstName: (self call: (MFTStringDialog new
52 Removed: action: action;
53 Removed: heading: 'real first name';
54 Removed: string: user realFirstName;
55 Removed: completion: 80)).
56 Removed: user realLastName: (self call: (MFTStringDialog new
57 Removed: heading: 'real last name';
58 Removed: string: user realLastName;
59 Removed: completion: 100)).
60 Removed:
61 Removed: (self call: (MFTConfirmDialog new
62 Removed: action: action;
63 Removed: component: user))
64 Removed: ifTrue: [ self answer: user ]
65 Removed: ifFalse: [ self answer: nil ]
66 Removed: ]
67 Removed:
68 Removed: { #category : 'initialization' }
69 Removed: MFTUserTask >> initialize [
70 Removed:
71 Removed: super initialize.
72 Removed: user := MFTUser new
73 Removed: ]
74 Removed:
75 Removed: { #category : 'accessing' }
76 Removed: MFTUserTask >> user [
77 Removed:
78 Removed: ^ user
79 Removed: ]
80 Removed:
81 Removed: { #category : 'accessing' }
82 Removed: MFTUserTask >> user: anObject [
83 Removed:
84 Removed: user := anObject
85 Removed: ]
src/MyFitnessTracker/MFTWeightDialog.class.st
index 01f2521b..00000000 100644..000000
@@ -1,76 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWeightDialog',
3 Removed: #superclass : 'MFTDialog',
4 Removed: #instVars : [
5 Removed: 'weight'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Dialogs',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Dialogs'
10 Removed: }
11 Removed:
12 Removed: { #category : 'actions' }
13 Removed: MFTWeightDialog class >> edit: aMFTWeight [
14 Removed:
15 Removed: ^ self new
16 Removed: action: #edit;
17 Removed: weight: aMFTWeight;
18 Removed: yourself
19 Removed: ]
20 Removed:
21 Removed: { #category : 'initialization' }
22 Removed: MFTWeightDialog >> initialize [
23 Removed:
24 Removed: super initialize.
25 Removed: weight := MFTWeight new
26 Removed: ]
27 Removed:
28 Removed: { #category : 'rendering' }
29 Removed: MFTWeightDialog >> renderContentOn: html [
30 Removed:
31 Removed: self renderDialogOn: html with: [
32 Removed: html formGroup: [
33 Removed: html label: 'Date'.
34 Removed: html dateInput5 formControl
35 Removed: value: weight date yyyymmdd;
36 Removed: callback: [ :value |
37 Removed: weight date: (Date readFrom: value pattern: 'yyyy-mm-dd') ] ].
38 Removed: html formGroup: [
39 Removed: html label: 'Weight'.
40 Removed: html numberInput formControl
41 Removed: value: (weight value = 0
42 Removed: ifTrue: [ nil ]
43 Removed: ifFalse: [ weight value ]);
44 Removed: placeholder: weight value;
45 Removed: callback: [ :value |
46 Removed: value ifNotEmpty: [ weight value: value asNumber ] ] ] ]
47 Removed: ]
48 Removed:
49 Removed: { #category : 'rendering' }
50 Removed: MFTWeightDialog >> renderSubmitOn: html [
51 Removed:
52 Removed: html buttonGroup: [
53 Removed: html formButton
54 Removed: beSubmit;
55 Removed: bePrimary;
56 Removed: callback: [
57 Removed: self answer: (weight value ifNotNil: [ weight ] ifNil: [ nil ]) ];
58 Removed: with: (completion ifNil: [ 'Submit' ] ifNotNil: [ 'Next' ]).
59 Removed: html formButton
60 Removed: beSubmit;
61 Removed: beSecondary;
62 Removed: callback: [ self answer: nil ];
63 Removed: with: (completion ifNil: [ 'Cancel' ] ifNotNil: [ 'Skip' ]) ]
64 Removed: ]
65 Removed:
66 Removed: { #category : 'accessing' }
67 Removed: MFTWeightDialog >> weight [
68 Removed:
69 Removed: ^ weight
70 Removed: ]
71 Removed:
72 Removed: { #category : 'accessing' }
73 Removed: MFTWeightDialog >> weight: aMFTWeight [
74 Removed:
75 Removed: weight := aMFTWeight
76 Removed: ]
src/MyFitnessTracker/MFTWeightVsTimeGraph.class.st
index 41a5aa2d..00000000 100644..000000
@@ -1,29 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWeightVsTimeGraph',
3 Removed: #superclass : 'MFTGraph',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTWeightVsTimeGraph >> renderContentOn: html [
11 Removed:
12 Removed: labels := self session user weights collect: [ :weight |
13 Removed: weight date yyyymmdd ].
14 Removed: data := self session user weights collect: #value.
15 Removed:
16 Removed: html canvas id: 'weightVsTimeChart'.
17 Removed: html script:
18 Removed: 'var ctx = document.getElementById("weightVsTimeChart").getContext("2d");
19 Removed: var weightChart = new Chart(ctx, {
20 Removed: type: "line",
21 Removed: data: {
22 Removed: labels: ' , labels asJavascript , ',
23 Removed: datasets: [{
24 Removed: label: "weight",
25 Removed: data: ' , data asJavascript , ',
26 Removed: }]
27 Removed: },
28 Removed: });'
29 Removed: ]
src/MyFitnessTracker/MFTWeightsCard.class.st
index edbff5b6..00000000 100644..000000
@@ -1,54 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWeightsCard',
3 Removed: #superclass : 'MFTCard',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'adding' }
10 Removed: MFTWeightsCard >> addWeight [
11 Removed:
12 Removed: | newWeight |
13 Removed: newWeight := self session pageManager activePage call:
14 Removed: MFTWeightDialog new.
15 Removed: (self session user weights anySatisfy: [ :existingWeight |
16 Removed: newWeight date = existingWeight date and: [
17 Removed: newWeight value = existingWeight value ] ]) ifTrue: [ ^ self ].
18 Removed:
19 Removed: self session user isLoggedIn
20 Removed: ifTrue: [ self session db insert: newWeight ]
21 Removed: ifFalse: [ self session user weights add: newWeight ]
22 Removed: ]
23 Removed:
24 Removed: { #category : 'rendering' }
25 Removed: MFTWeightsCard >> renderContentOn: html [
26 Removed:
27 Removed: self renderCardOn: html with: [
28 Removed: html cardHeader: 'Weights'.
29 Removed: html cardBody: [
30 Removed: html paragraph: 'Great job logging your weight '
31 Removed: , self session user weights size asString , ' times!'.
32 Removed: html form
33 Removed: class: 'mb-3';
34 Removed: with: [
35 Removed: html buttonGroup
36 Removed: beSmall;
37 Removed: with: [
38 Removed: html outlineButton
39 Removed: bePrimary;
40 Removed: callback: [ self addWeight ];
41 Removed: with: 'Log weight'.
42 Removed: html outlineButton
43 Removed: beSecondary;
44 Removed: callback: [ self viewAnalytics ];
45 Removed: with: 'View progress' ] ].
46 Removed: html render: MFTWeightVsTimeGraph new ] ]
47 Removed: ]
48 Removed:
49 Removed: { #category : 'as yet unclassified' }
50 Removed: MFTWeightsCard >> viewAnalytics [
51 Removed:
52 Removed: self session pageManager activePage call:
53 Removed: (MFTAnalyticsPage for: #weights)
54 Removed: ]
src/MyFitnessTracker/MFTWeightsLog.class.st
index 2a358c66..00000000 100644..000000
@@ -1,141 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWeightsLog',
3 Removed: #superclass : 'MFTLog',
4 Removed: #instVars : [
5 Removed: 'weights'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'adding' }
13 Removed: MFTWeightsLog >> addWeight [
14 Removed:
15 Removed: | newWeight |
16 Removed: newWeight := self call: MFTWeightDialog new.
17 Removed: newWeight ifNil: [ ^ self ].
18 Removed: (weights anySatisfy: [ :existingWeight |
19 Removed: existingWeight date = newWeight date and: [
20 Removed: existingWeight value = newWeight value ] ]) ifTrue: [ ^ self ].
21 Removed:
22 Removed: self session user isLoggedIn
23 Removed: ifTrue: [ self session db insert: newWeight ]
24 Removed: ifFalse: [ weights add: newWeight ]
25 Removed: ]
26 Removed:
27 Removed: { #category : 'accessing' }
28 Removed: MFTWeightsLog >> editWeight: oldWeight [
29 Removed:
30 Removed: | newWeight |
31 Removed: newWeight := self call: (MFTWeightDialog edit: oldWeight copy).
32 Removed: (oldWeight value = newWeight value and: [
33 Removed: oldWeight date = newWeight date ]) ifTrue: [ ^ self ].
34 Removed:
35 Removed: self session user isLoggedIn
36 Removed: ifTrue: [ self session db update: oldWeight with: newWeight ]
37 Removed: ifFalse: [
38 Removed: weights
39 Removed: remove: oldWeight;
40 Removed: add: newWeight ]
41 Removed: ]
42 Removed:
43 Removed: { #category : 'initialization' }
44 Removed: MFTWeightsLog >> initialize [
45 Removed:
46 Removed: super initialize.
47 Removed: title := 'weights'.
48 Removed: weights := OrderedCollection new
49 Removed: ]
50 Removed:
51 Removed: { #category : 'as yet unclassified' }
52 Removed: MFTWeightsLog >> randomWittyCTA [
53 Removed:
54 Removed: | listOfStrings randomString |
55 Removed: listOfStrings := #( 'First time?' 'Get your sweat on!'
56 Removed: 'Go go go!' 'Go get ''em, Tiger!' ).
57 Removed: randomString := listOfStrings atRandom.
58 Removed: ^ randomString
59 Removed: ]
60 Removed:
61 Removed: { #category : 'accessing' }
62 Removed: MFTWeightsLog >> removeWeight: aMFTWeight [
63 Removed:
64 Removed: self session user isLoggedIn
65 Removed: ifTrue: [ self session db delete: aMFTWeight ]
66 Removed: ifFalse: [ weights remove: aMFTWeight ]
67 Removed: ]
68 Removed:
69 Removed: { #category : 'rendering' }
70 Removed: MFTWeightsLog >> renderActionsButtonGroupOn: html [
71 Removed:
72 Removed: html form: [
73 Removed: html buttonGroup: [
74 Removed: html formButton
75 Removed: bePrimary;
76 Removed: callback: [ self addWeight ];
77 Removed: with: 'Log weight'.
78 Removed: html formButton
79 Removed: beSecondary;
80 Removed: callback: [ self viewAnalytics ];
81 Removed: with: 'View progress' ] ]
82 Removed: ]
83 Removed:
84 Removed: { #category : 'rendering' }
85 Removed: MFTWeightsLog >> renderContentOn: html [
86 Removed:
87 Removed: weights := self session user weights sort: [ :a :b | a date > b date ].
88 Removed: self renderLogOn: html with: [
89 Removed: weights ifEmpty: [
90 Removed: html jumbotron: [ html heading: self randomWittyCTA ] ].
91 Removed: self renderActionsButtonGroupOn: html.
92 Removed: weights ifNotEmpty: [ self renderWeightsAsTableOn: html ] ]
93 Removed: ]
94 Removed:
95 Removed: { #category : 'rendering' }
96 Removed: MFTWeightsLog >> renderWeightActionsButtonGroupOn: html for: aMFTWeight [
97 Removed:
98 Removed: html form: [
99 Removed: html buttonGroup
100 Removed: beSmall;
101 Removed: with: [
102 Removed: html formButton
103 Removed: beSecondary;
104 Removed: formControl;
105 Removed: callback: [ self editWeight: aMFTWeight ];
106 Removed: with: 'Edit'.
107 Removed: html formButton
108 Removed: beDanger;
109 Removed: formControl;
110 Removed: callback: [ self removeWeight: aMFTWeight ];
111 Removed: with: 'Delete' ] ]
112 Removed: ]
113 Removed:
114 Removed: { #category : 'rendering' }
115 Removed: MFTWeightsLog >> renderWeightsAsTableOn: html [
116 Removed:
117 Removed: html table
118 Removed: class: 'table table-striped';
119 Removed: with: [
120 Removed: html tableHead: [
121 Removed: html
122 Removed: tableHeading;
123 Removed: tableHeading: 'Date'.
124 Removed: html tableHeading
125 Removed: style: 'text-align: right';
126 Removed: with: 'Value' ].
127 Removed: weights do: [ :weight |
128 Removed: html tableRow: [
129 Removed: html tableData: [
130 Removed: self renderWeightActionsButtonGroupOn: html for: weight ].
131 Removed: html tableData: weight date yyyymmdd.
132 Removed: html tableData
133 Removed: style: 'text-align: right';
134 Removed: with: weight value ] ] ]
135 Removed: ]
136 Removed:
137 Removed: { #category : 'adding' }
138 Removed: MFTWeightsLog >> viewAnalytics [
139 Removed:
140 Removed: self call: (MFTAnalyticsPage for: #weights)
141 Removed: ]
src/MyFitnessTracker/MFTWidget.class.st
index 5ea873b0..00000000 100644..000000
@@ -1,46 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWidget',
3 Removed: #superclass : 'SBSComponent',
4 Removed: #instVars : [
5 Removed: 'title'
6 Removed: ],
7 Removed: #category : 'MyFitnessTracker-Components',
8 Removed: #package : 'MyFitnessTracker',
9 Removed: #tag : 'Components'
10 Removed: }
11 Removed:
12 Removed: { #category : 'accessing' }
13 Removed: MFTWidget >> defaultDescription [
14 Removed:
15 Removed: ^ 'I am a ' , self class name
16 Removed: ]
17 Removed:
18 Removed: { #category : 'initialization' }
19 Removed: MFTWidget >> initialize [
20 Removed:
21 Removed: super initialize.
22 Removed: title := String new
23 Removed: ]
24 Removed:
25 Removed: { #category : 'rendering' }
26 Removed: MFTWidget >> renderContentOn: html [
27 Removed:
28 Removed: html div: [
29 Removed: title ifNotEmpty: [
30 Removed: html heading
31 Removed: level5;
32 Removed: with: self title ].
33 Removed: html paragraph: self defaultDescription ]
34 Removed: ]
35 Removed:
36 Removed: { #category : 'accessing' }
37 Removed: MFTWidget >> title [
38 Removed:
39 Removed: ^ title
40 Removed: ]
41 Removed:
42 Removed: { #category : 'accessing' }
43 Removed: MFTWidget >> title: aString [
44 Removed:
45 Removed: title := aString
46 Removed: ]
src/MyFitnessTracker/MFTWorkoutForm.class.st
index df7c09db..00000000 100644..000000
@@ -1,45 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWorkoutForm',
3 Removed: #superclass : 'MFTForm',
4 Removed: #category : 'MyFitnessTracker-Forms',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Forms'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTWorkoutForm class >> edit: aMFTWorkout [
11 Removed:
12 Removed: ^ self new
13 Removed: modelObject: aMFTWorkout;
14 Removed: yourself
15 Removed: ]
16 Removed:
17 Removed: { #category : 'initialization' }
18 Removed: MFTWorkoutForm >> initialize [
19 Removed:
20 Removed: super initialize.
21 Removed: modelObject := MFTWorkout new.
22 Removed: heading := 'Workout'
23 Removed: ]
24 Removed:
25 Removed: { #category : 'rendering' }
26 Removed: MFTWorkoutForm >> renderContentOn: html [
27 Removed:
28 Removed: self renderFormOn: html with: [
29 Removed: html
30 Removed: render: (MFTFormComponent set: #date);
31 Removed: render: (MFTFormComponent set: #setGroups);
32 Removed: render: (MFTFormComponent set: #primaryMuscleGroup);
33 Removed: render: (MFTFormComponent set: #secondaryMuscleGroups) ]
34 Removed: ]
35 Removed:
36 Removed: { #category : 'as yet unclassified' }
37 Removed: MFTWorkoutForm >> submitForm [
38 Removed:
39 Removed: modelObject setGroups ifEmpty: [
40 Removed: (self call:
41 Removed: (MFTConfirmForm new modelObject: 'No exercises were specified.'))
42 Removed: ifFalse: [ self answer: nil ] ].
43 Removed:
44 Removed: self answer: modelObject
45 Removed: ]
src/MyFitnessTracker/MFTWorkoutTask.class.st
index a081da58..00000000 100644..000000
@@ -1,101 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWorkoutTask',
3 Removed: #superclass : 'WATask',
4 Removed: #instVars : [
5 Removed: 'workout',
6 Removed: 'action'
7 Removed: ],
8 Removed: #category : 'MyFitnessTracker-Tasks',
9 Removed: #package : 'MyFitnessTracker',
10 Removed: #tag : 'Tasks'
11 Removed: }
12 Removed:
13 Removed: { #category : 'actions' }
14 Removed: MFTWorkoutTask class >> edit: aMFTWorkout [
15 Removed:
16 Removed: ^ self new
17 Removed: workout: aMFTWorkout;
18 Removed: action: #edit;
19 Removed: yourself
20 Removed: ]
21 Removed:
22 Removed: { #category : 'accessing' }
23 Removed: MFTWorkoutTask >> action [
24 Removed:
25 Removed: ^ action
26 Removed: ]
27 Removed:
28 Removed: { #category : 'accessing' }
29 Removed: MFTWorkoutTask >> action: anObject [
30 Removed:
31 Removed: action := anObject
32 Removed: ]
33 Removed:
34 Removed: { #category : 'running' }
35 Removed: MFTWorkoutTask >> go [
36 Removed:
37 Removed: | primaryMuscleGroup secondaryMuscleGroups |
38 Removed: workout userId: self session user id.
39 Removed: workout date: (self call: (MFTDateDialog new
40 Removed: action: action;
41 Removed: date: workout date;
42 Removed: completion: 20)).
43 Removed: workout setGroups: (self call: (MFTSetGroupsDialog new
44 Removed: action: action;
45 Removed: heading: 'Exercises';
46 Removed: setGroups: workout setGroups;
47 Removed: completion: 40)).
48 Removed: primaryMuscleGroup := self call: (MFTPrimaryMuscleGroupDialog new
49 Removed: action: action;
50 Removed: primaryMuscleGroup:
51 Removed: workout primaryMuscleGroup;
52 Removed: completion: 60).
53 Removed: primaryMuscleGroup ifNotNil: [
54 Removed: workout primaryMuscleGroupId: primaryMuscleGroup id.
55 Removed: secondaryMuscleGroups := self call:
56 Removed: (MFTSecondaryMuscleGroupsDialog new
57 Removed: action: action;
58 Removed: secondaryMuscleGroups:
59 Removed: workout secondaryMuscleGroups;
60 Removed: completion: 80).
61 Removed: workout secondaryMuscleGroupIds:
62 Removed: (secondaryMuscleGroups collect: #id) ].
63 Removed:
64 Removed: (self call: (MFTConfirmDialog new
65 Removed: action: action;
66 Removed: component: workout))
67 Removed: ifTrue: [
68 Removed: self updateSetsAttributes.
69 Removed: self answer: workout ]
70 Removed: ifFalse: [ self answer: nil ]
71 Removed: ]
72 Removed:
73 Removed: { #category : 'initialization' }
74 Removed: MFTWorkoutTask >> initialize [
75 Removed:
76 Removed: super initialize.
77 Removed: workout := MFTWorkout new.
78 Removed: action := #add
79 Removed: ]
80 Removed:
81 Removed: { #category : 'as yet unclassified' }
82 Removed: MFTWorkoutTask >> updateSetsAttributes [
83 Removed:
84 Removed: workout setGroups doWithIndex: [ :setGroup :i |
85 Removed: setGroup sets doWithIndex: [ :set :j |
86 Removed: set
87 Removed: groupId: i;
88 Removed: number: j ] ]
89 Removed: ]
90 Removed:
91 Removed: { #category : 'accessing' }
92 Removed: MFTWorkoutTask >> workout [
93 Removed:
94 Removed: ^ workout
95 Removed: ]
96 Removed:
97 Removed: { #category : 'accessing' }
98 Removed: MFTWorkoutTask >> workout: anObject [
99 Removed:
100 Removed: workout := anObject
101 Removed: ]
src/MyFitnessTracker/MFTWorkoutVolumePerWeekGraph.class.st
index 3f0cf3ad..00000000 100644..000000
@@ -1,46 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWorkoutVolumePerWeekGraph',
3 Removed: #superclass : 'MFTGraph',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'as yet unclassified' }
10 Removed: MFTWorkoutVolumePerWeekGraph >> crunchTheNumbers [
11 Removed: "TODO: not working at all!"
12 Removed:
13 Removed: | datasets datasetsAsJs |
14 Removed: labels := Week dayNames.
15 Removed: data := self session user workouts groupedBy: [ :each |
16 Removed: each date dayOfYear // 7 ].
17 Removed: "datasets := {
18 Removed: { 1. 2. 0. 0. 3. 5. 3 }.
19 Removed: { 3. 4. 3. 0. 0. 0. 6 } }."
20 Removed: datasetsAsJs := data keysAndValuesDo: [ :k :v |
21 Removed: '{ label: ' , (#w , k asString) asJavascript
22 Removed: , ', data: ' , (v collect: #volume) asJavascript
23 Removed: , '},' ]
24 Removed: ]
25 Removed:
26 Removed: { #category : 'initialization' }
27 Removed: MFTWorkoutVolumePerWeekGraph >> initialize [
28 Removed:
29 Removed: super initialize.
30 Removed: self crunchTheNumbers
31 Removed: ]
32 Removed:
33 Removed: { #category : 'rendering' }
34 Removed: MFTWorkoutVolumePerWeekGraph >> renderContentOn: html [
35 Removed:
36 Removed: html canvas id: 'workoutVolumePerWeekChart'.
37 Removed: html script:
38 Removed: 'var ctx = document.getElementById("workoutVolumePerWeekChart").getContext("2d");
39 Removed: var weightChart = new Chart(ctx, {
40 Removed: type: "line",
41 Removed: data: {
42 Removed: labels: ' , labels asJavascript , ',
43 Removed: datasets: [ ' , data asJavascript , ' ]
44 Removed: },
45 Removed: });'
46 Removed: ]
src/MyFitnessTracker/MFTWorkoutVolumeVsTimeGraph.class.st
index 78f6f573..00000000 100644..000000
@@ -1,31 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWorkoutVolumeVsTimeGraph',
3 Removed: #superclass : 'MFTGraph',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'rendering' }
10 Removed: MFTWorkoutVolumeVsTimeGraph >> renderContentOn: html [
11 Removed:
12 Removed: | workouts |
13 Removed: workouts := self session user workouts sort: [ :a :b |
14 Removed: a date < b date ].
15 Removed: labels := workouts collect: [ :workout | workout date yyyymmdd ].
16 Removed: data := workouts collect: #volume.
17 Removed:
18 Removed: html canvas id: 'workoutVolumeVsTimeChart'.
19 Removed: html script:
20 Removed: 'var ctx = document.getElementById("workoutVolumeVsTimeChart").getContext("2d");
21 Removed: var weightChart = new Chart(ctx, {
22 Removed: type: "line",
23 Removed: data: {
24 Removed: labels: ' , labels asJavascript , ',
25 Removed: datasets: [{
26 Removed: label: "total workout volume",
27 Removed: data: ' , data asJavascript , ',
28 Removed: }]
29 Removed: },
30 Removed: });'
31 Removed: ]
src/MyFitnessTracker/MFTWorkoutsCard.class.st
index e4722050..00000000 100644..000000
@@ -1,53 +0,0 @@
1 Removed: Class {
2 Removed: #name : 'MFTWorkoutsCard',
3 Removed: #superclass : 'MFTCard',
4 Removed: #category : 'MyFitnessTracker-Components',
5 Removed: #package : 'MyFitnessTracker',
6 Removed: #tag : 'Components'
7 Removed: }
8 Removed:
9 Removed: { #category : 'adding' }
10 Removed: MFTWorkoutsCard >> addWorkout [
11 Removed:
12 Removed: | newWorkout |
13 Removed: newWorkout := self session pageManager activePage call:
14 Removed: MFTWorkoutTask new.
15 Removed: newWorkout ifNil: [ ^ self ].
16 Removed:
17 Removed: self session user isLoggedIn
18 Removed: ifTrue: [ self session db insert: newWorkout ]
19 Removed: ifFalse: [ self session user workouts add: newWorkout ]
20 Removed: ]
21 Removed:
22 Removed: { #category : 'rendering' }
23 Removed: MFTWorkoutsCard >> renderContentOn: html [
24 Removed:
25 Removed: self renderCardOn: html with: [
26 Removed: html cardHeader: 'Workouts'.
27 Removed: html cardBody: [
28 Removed: html paragraph:
29 Removed: 'Great job logging ' , self session user workouts size asString
30 Removed: , ' workouts!'.
31 Removed: html form
32 Removed: class: 'my-3';
33 Removed: with: [
34 Removed: html buttonGroup
35 Removed: beSmall;
36 Removed: with: [
37 Removed: html outlineButton
38 Removed: bePrimary;
39 Removed: callback: [ self addWorkout ];
40 Removed: with: 'Log workout'.
41 Removed: html outlineButton
42 Removed: beSecondary;
43 Removed: callback: [ self viewAnalytics ];
44 Removed: with: 'View progress' ] ].
45 Removed: html render: MFTRepsDistributionGraph new ] ]
46 Removed: ]
47 Removed:
48 Removed: { #category : 'adding' }
49 Removed: MFTWorkoutsCard >> viewAnalytics [
50 Removed:
51 Removed: self session pageManager activePage call:
52 Removed: (MFTAnalyticsPage for: #workouts)
53 Removed: ]
src/MyFitnessTracker/MFTWorkoutsLog.class.st
index 766e3844..00000000 100644..000000
@@ -1,172 +0,0 @@
1 Removed: "
2 Removed: I represent the list of user workouts retrieved from the database.
3 Removed:
4 Removed: I am rendered by `MFTRootComponent` when the user views their workouts. I know about user workouts retrieved from the database.
5 Removed:
6 Removed: * Collaborators
7 Removed:
8 Removed: - I work with lists of `MFTWorkout`s.
9 Removed: - I might work with `MFTExercise class`canonical exercises once the variable is implemented.
10 Removed:
11 Removed: Public API and Key Messages
12 Removed:
13 Removed: - message one
14 Removed: - message two
15 Removed: - (for bonus points) how to create instances.
16 Removed:
17 Removed: One simple example is simply gorgeous.
18 Removed:
19 Removed: Internal Representation and Key Implementation Points.
20 Removed:
21 Removed:
22 Removed: Implementation Points
23 Removed: "
24 Removed: Class {
25 Removed: #name : 'MFTWorkoutsLog',
26 Removed: #superclass : 'MFTLog',
27 Removed: #instVars : [
28 Removed: 'workouts'
29 Removed: ],
30 Removed: #category : 'MyFitnessTracker-Components',
31 Removed: #package : 'MyFitnessTracker',
32 Removed: #tag : 'Components'
33 Removed: }
34 Removed:
35 Removed: { #category : 'adding' }
36 Removed: MFTWorkoutsLog >> addWorkout [
37 Removed:
38 Removed: | newWorkout |
39 Removed: newWorkout := self call: MFTWorkoutForm new.
40 Removed: newWorkout ifNil: [ ^ self ].
41 Removed:
42 Removed: self session user isLoggedIn
43 Removed: ifTrue: [ self session db insert: newWorkout ]
44 Removed: ifFalse: [ workouts add: newWorkout ]
45 Removed: ]
46 Removed:
47 Removed: { #category : 'hooks' }
48 Removed: MFTWorkoutsLog >> children [
49 Removed:
50 Removed: ^ self session user workouts
51 Removed: ]
52 Removed:
53 Removed: { #category : 'accessing' }
54 Removed: MFTWorkoutsLog >> confirmDelete: workout [
55 Removed:
56 Removed: (self call: (MFTConfirmForm delete)) ifFalse: [ ^ self ].
57 Removed: self session user isLoggedIn
58 Removed: ifTrue: [ self session db delete: workout ]
59 Removed: ifFalse: [ workouts remove: workout ]
60 Removed: ]
61 Removed:
62 Removed: { #category : 'as yet unclassified' }
63 Removed: MFTWorkoutsLog >> editWorkout: oldWorkout [
64 Removed:
65 Removed: | newWorkout |
66 Removed: newWorkout := self call: (MFTWorkoutForm edit: oldWorkout copy).
67 Removed: newWorkout ifNil: [ ^ self ].
68 Removed:
69 Removed: self session user isLoggedIn
70 Removed: ifTrue: [ self session db update: oldWorkout with: newWorkout ]
71 Removed: ifFalse: [
72 Removed: workouts
73 Removed: remove: oldWorkout;
74 Removed: add: newWorkout ]
75 Removed: ]
76 Removed:
77 Removed: { #category : 'initialization' }
78 Removed: MFTWorkoutsLog >> initialize [
79 Removed:
80 Removed: super initialize.
81 Removed: title := 'workouts'.
82 Removed: workouts := OrderedCollection new
83 Removed: ]
84 Removed:
85 Removed: { #category : 'as yet unclassified' }
86 Removed: MFTWorkoutsLog >> randomWittyCTA [
87 Removed:
88 Removed: | listOfStrings randomString |
89 Removed: listOfStrings := #( 'First time?' 'Get your sweat on!'
90 Removed: 'Go go go!' 'Go get ''em, Tiger!' ).
91 Removed: randomString := listOfStrings atRandom.
92 Removed: ^ randomString
93 Removed: ]
94 Removed:
95 Removed: { #category : 'rendering' }
96 Removed: MFTWorkoutsLog >> renderActionsButtonGroupOn: html [
97 Removed:
98 Removed: html form: [
99 Removed: html buttonGroup: [
100 Removed: html formButton
101 Removed: bePrimary;
102 Removed: callback: [ self addWorkout ];
103 Removed: with: 'Log workout'.
104 Removed: html formButton
105 Removed: beSecondary;
106 Removed: callback: [ self viewAnalytics ];
107 Removed: with: 'View progress' ] ]
108 Removed: ]
109 Removed:
110 Removed: { #category : 'rendering' }
111 Removed: MFTWorkoutsLog >> renderContentOn: html [
112 Removed:
113 Removed: workouts := self session user workouts sort: [ :a :b |
114 Removed: a date > b date ].
115 Removed: self renderLogOn: html with: [
116 Removed: workouts ifEmpty: [
117 Removed: html jumbotron: [ html heading: self randomWittyCTA ] ].
118 Removed: self renderActionsButtonGroupOn: html.
119 Removed: workouts ifNotEmpty: [ self renderWorkoutsAsAccordionOn: html ] ]
120 Removed: ]
121 Removed:
122 Removed: { #category : 'rendering' }
123 Removed: MFTWorkoutsLog >> renderWorkoutActionsButtonGroup: html for: workout [
124 Removed:
125 Removed: html form: [
126 Removed: html buttonGroup: [
127 Removed: html formButton
128 Removed: bePrimary;
129 Removed: callback: [ self editWorkout: workout ];
130 Removed: with: 'Edit'.
131 Removed: html formButton
132 Removed: beDanger;
133 Removed: callback: [ self confirmDelete: workout ];
134 Removed: with: 'Delete' ] ]
135 Removed: ]
136 Removed:
137 Removed: { #category : 'rendering' }
138 Removed: MFTWorkoutsLog >> renderWorkoutsAsAccordionOn: html [
139 Removed:
140 Removed: html accordion
141 Removed: id: 'accordion';
142 Removed: class: 'my-3';
143 Removed: with: [
144 Removed: workouts doWithIndex: [ :workout :i |
145 Removed: html accordionItem: [
146 Removed: html accordionHeading: [
147 Removed: html accordionButton
148 Removed: dataToggle: 'collapse';
149 Removed: dataTarget: '#collapse' , i asString;
150 Removed: with: [
151 Removed: html text:
152 Removed: workout date yyyymmdd , ', ' , workout date dayOfWeekName.
153 Removed: workout primaryMuscleGroup ifNotNil: [
154 Removed: html
155 Removed: text: ':';
156 Removed: space;
157 Removed: emphasis: workout primaryMuscleGroup englishName ] ] ].
158 Removed: html accordionCollapse
159 Removed: id: 'collapse' , i asString;
160 Removed: class: 'collapse';
161 Removed: dataAttributeAt: 'bs-parent' put: '#accordion';
162 Removed: with: [
163 Removed: html accordionBody with: [
164 Removed: html render: workout.
165 Removed: self renderWorkoutActionsButtonGroup: html for: workout ] ] ] ] ]
166 Removed: ]
167 Removed:
168 Removed: { #category : 'adding' }
169 Removed: MFTWorkoutsLog >> viewAnalytics [
170 Removed:
171 Removed: self call: (MFTAnalyticsPage for: #workouts)
172 Removed: ]