Skip to content

Commit ee263cf

Browse files
ISSUE-219: Average heart rate for activity splits
1 parent 969a215 commit ee263cf

File tree

9 files changed

+74
-19
lines changed

9 files changed

+74
-19
lines changed

src/Domain/Strava/Activity/Split/ActivitySplit.php

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,35 @@
1313

1414
#[ORM\Entity]
1515
#[ORM\Index(name: 'ActivitySplit_activityIdUnitSystemIndex', columns: ['activityId', 'unitSystem'])]
16-
final readonly class ActivitySplit
16+
final class ActivitySplit
1717
{
1818
use ProvideTimeFormats;
1919

20+
private ?int $averageHeartRate = null;
21+
2022
private function __construct(
2123
#[ORM\Id, ORM\Column(type: 'string')]
22-
private ActivityId $activityId,
24+
private readonly ActivityId $activityId,
2325
#[ORM\Id, ORM\Column(type: 'string')]
24-
private UnitSystem $unitSystem,
26+
private readonly UnitSystem $unitSystem,
2527
#[ORM\Id, ORM\Column(type: 'integer')]
26-
private int $splitNumber,
28+
private readonly int $splitNumber,
2729
#[ORM\Column(type: 'integer')]
28-
private Meter $distance,
30+
private readonly Meter $distance,
2931
#[ORM\Column(type: 'integer')]
30-
private int $elapsedTimeInSeconds,
32+
private readonly int $elapsedTimeInSeconds,
3133
#[ORM\Column(type: 'integer')]
32-
private int $movingTimeInSeconds,
34+
private readonly int $movingTimeInSeconds,
3335
#[ORM\Column(type: 'integer')]
34-
private Meter $elevationDifference,
36+
private readonly Meter $elevationDifference,
3537
#[ORM\Column(type: 'float')]
36-
private MetersPerSecond $averageSpeed,
38+
private readonly MetersPerSecond $averageSpeed,
3739
#[ORM\Column(type: 'float')]
38-
private MetersPerSecond $minAverageSpeed,
40+
private readonly MetersPerSecond $minAverageSpeed,
3941
#[ORM\Column(type: 'integer')]
40-
private MetersPerSecond $maxAverageSpeed,
42+
private readonly MetersPerSecond $maxAverageSpeed,
4143
#[ORM\Column(type: 'integer')]
42-
private int $paceZone,
44+
private readonly int $paceZone,
4345
) {
4446
}
4547

@@ -182,4 +184,14 @@ public function getPaceZone(): int
182184
{
183185
return $this->paceZone;
184186
}
187+
188+
public function enrichWithAverageHeartRate(int $averageHeartRate): void
189+
{
190+
$this->averageHeartRate = $averageHeartRate;
191+
}
192+
193+
public function getAverageHeartRate(): ?int
194+
{
195+
return $this->averageHeartRate;
196+
}
185197
}

src/Domain/Strava/BuildHtmlVersion/BuildHtmlVersionCommandHandler.php

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,33 @@ public function handle(Command $command): void
534534
$timeInSecondsPerWattage = $this->activityPowerRepository->findTimeInSecondsPerWattageForActivity($activity->getId());
535535
}
536536

537-
$leafletMap = $activity->getLeafletMap();
537+
$activitySplits = $this->activitySplitRepository->findBy(
538+
activityId: $activity->getId(),
539+
unitSystem: $this->unitSystem
540+
);
541+
542+
if (!$activitySplits->isEmpty() && $heartRateStream) {
543+
/** @var \App\Domain\Strava\Activity\Split\ActivitySplit $activitySplit */
544+
$sumSplitMovingTimeInSeconds = 0;
545+
foreach ($activitySplits as $activitySplit) {
546+
$movingTimeInSeconds = $activitySplit->getMovingTimeInSeconds();
547+
// Enrich ActivitySplit with average heart rate.
548+
$heartRatesForCurrentSplit = array_slice(
549+
array: $heartRateStream->getData(),
550+
offset: $sumSplitMovingTimeInSeconds,
551+
length: $movingTimeInSeconds
552+
);
553+
if (0 === count($heartRatesForCurrentSplit)) {
554+
continue;
555+
}
556+
$averageHeartRate = (int) round(array_sum($heartRatesForCurrentSplit) / count($heartRatesForCurrentSplit));
557+
558+
$activitySplit->enrichWithAverageHeartRate($averageHeartRate);
559+
$sumSplitMovingTimeInSeconds += $movingTimeInSeconds;
560+
}
561+
}
538562

563+
$leafletMap = $activity->getLeafletMap();
539564
$this->filesystem->write(
540565
'build/html/activity/'.$activity->getId().'.html',
541566
$this->twig->load('html/activity/activity.html.twig')->render([
@@ -558,10 +583,7 @@ public function handle(Command $command): void
558583
)->build(),
559584
) : null,
560585
'segmentEfforts' => $this->segmentEffortRepository->findByActivityId($activity->getId()),
561-
'splits' => $this->activitySplitRepository->findBy(
562-
activityId: $activity->getId(),
563-
unitSystem: $this->unitSystem
564-
),
586+
'splits' => $activitySplits,
565587
'heartRateChart' => $heartRateStream?->getData() ? Json::encode(
566588
HeartRateChartBuilder::create($heartRateStream)->build(),
567589
) : null,

templates/html/activity/activity--activity-type--run.html.twig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<div class="w-[5rem] px-2 py-2">{{ "Pace"|trans }}</div>
7777
<div class="flex-grow min-w-[10rem] px-2 py-2"></div>
7878
<div class="w-[5rem] px-2 py-2">{{ "Elev"|trans }}</div>
79+
<div class="w-[5rem] px-2 py-2">{{ "HR"|trans }}</div>
7980
</div>
8081
{% for split in splits %}
8182
<div class="flex items-center border-b last:border-b-0">
@@ -93,6 +94,15 @@
9394
<div class="w-[5rem] px-2 py-2">
9495
{{ renderComponent('measurement', {'measurement': split.getElevationDifference(), 'precision': 0}) }}
9596
</div>
97+
{% if split.getAverageHeartRate() %}
98+
<div class="w-[5rem] px-2 py-2">
99+
{{ split.getAverageHeartRate() }}
100+
</div>
101+
{% else %}
102+
<div class="w-[5rem] px-2 py-2">
103+
{{ "n/a"|trans }}
104+
</div>
105+
{% endif %}
96106
</div>
97107
{% endfor %}
98108
</div>

tests/Domain/Strava/BuildHtmlVersion/__snapshots__/BuildHtmlVersionCommandHandlerTest--testHandleForRunningActivitiesOnly--buildhtmlactivityactivity-9756441741.html.html

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ <h3 class="max-w-[30%] sm:max-w-[50%] md:max-w-[100%] truncate text-lg font-semi
109109
<div class="w-[5rem] px-2 py-2">Pace</div>
110110
<div class="flex-grow min-w-[10rem] px-2 py-2"></div>
111111
<div class="w-[5rem] px-2 py-2">Elev</div>
112+
<div class="w-[5rem] px-2 py-2">HR</div>
112113
</div>
113114
<div class="flex items-center border-b last:border-b-0">
114115
<div class="w-[2rem] px-2 py-2 font-bold">
@@ -126,7 +127,10 @@ <h3 class="max-w-[30%] sm:max-w-[50%] md:max-w-[100%] truncate text-lg font-semi
126127
2<span class="text-xs">m</span>
127128

128129
</div>
129-
</div>
130+
<div class="w-[5rem] px-2 py-2">
131+
n/a
132+
</div>
133+
</div>
130134
<div class="flex items-center border-b last:border-b-0">
131135
<div class="w-[2rem] px-2 py-2 font-bold">
132136
2
@@ -143,7 +147,10 @@ <h3 class="max-w-[30%] sm:max-w-[50%] md:max-w-[100%] truncate text-lg font-semi
143147
2<span class="text-xs">m</span>
144148

145149
</div>
146-
</div>
150+
<div class="w-[5rem] px-2 py-2">
151+
n/a
152+
</div>
153+
</div>
147154
</div>
148155
</div>
149156
<div class="h-[350px]" style="background-color:#bbbbb7" data-leaflet='{"routes":[null],"tileLayer":"https:\/\/tile.openstreetmap.org\/{z}\/{x}\/{y}.png","minZoom":1,"maxZoom":14,"imageOverlay":null,"bounds":[]}'></div>

tests/Infrastructure/Localisation/__snapshots__/TranslationsTest__testAllTranslationsHaveBeenExtracted__1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"Golf": "Golf",
6161
"Gravel Rides": "Gravel Rides",
6262
"HIIT": "HIIT",
63+
"HR": "HR",
6364
"Hand Cycle": "Hand Cycle",
6465
"Heart rate": "Heart rate",
6566
"Heart rate distribution": "Heart rate distribution",

tests/strava.db

0 Bytes
Binary file not shown.

translations/messages+intl-icu.en_US.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Gear: Gear
5959
Golf: Golf
6060
'Gravel Rides': 'Gravel Rides'
6161
HIIT: HIIT
62+
HR: HR
6263
'Hand Cycle': 'Hand Cycle'
6364
'Heart rate': 'Heart rate'
6465
'Heart rate distribution': 'Heart rate distribution'

translations/messages+intl-icu.fr_FR.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Gear: Matériel
5959
Golf: Golf
6060
'Gravel Rides': 'Sorties Gravel'
6161
HIIT: HIIT
62+
HR: HR
6263
'Hand Cycle': Handbike
6364
'Heart rate': 'Fréquence cardiaque'
6465
'Heart rate distribution': 'Répartition de la fréquence cardiaque'

translations/messages+intl-icu.nl_BE.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Gear: Uitrusting
5959
Golf: Golf
6060
'Gravel Rides': 'Gravel Ritten'
6161
HIIT: HIIT
62+
HR: HR
6263
'Hand Cycle': 'Hand Cycle'
6364
'Heart rate': Hartslag
6465
'Heart rate distribution': Hartslagverdeling

0 commit comments

Comments
 (0)