diff --git a/lib/health/health_export.dart b/lib/health/health_export.dart index 88c0eff0c..4b1a6df92 100644 --- a/lib/health/health_export.dart +++ b/lib/health/health_export.dart @@ -1761,6 +1761,12 @@ HealthWorkoutActivityType healthActivityForType( case 'padel': case 'badminton': return HealthWorkoutActivityType.TENNIS; + case 'pickleball': + // iOS has its own type; Health Connect has none, so it files with the + // other racquet sports. + return ios + ? HealthWorkoutActivityType.PICKLEBALL + : HealthWorkoutActivityType.TENNIS; case 'basketball': return HealthWorkoutActivityType.BASKETBALL; case 'soccer': diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index c2c980120..f09070a69 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -5800,7 +5800,7 @@ "tabNutrition": "Питание", "tabWorkout": "Тренировка", "tabWellness": "Самочувствие", - "activityCatalogueName": "{key, select, kcardio{Кардио} kstrength{Силовые} ksports{Спорт} kathletics{Лёгкая атлетика} koutdoor{На природе} kmindbody{Тело и внимание} keveryday{Повседневные дела} kother{Другое} krunning{Бег} ktrailrunning{Трейлраннинг} kwalking{Ходьба} khiking{Пеший поход} kcycling{Велоспорт} kindoorbike{Велотренажёр} krowing{Гребля} kswimming{Плавание} kelliptical{Эллиптический тренажёр} kstairclimber{Степпер} ktreadmill{Беговая дорожка} kjumprope{Прыжки со скакалкой} kweighttraining{Силовая тренировка} kpowerlifting{Пауэрлифтинг} kbodyweight{С собственным весом} kcalisthenics{Калистеника} kkettlebell{Гиря} kcrossfit{CrossFit} khiit{ВИИТ} kcircuittraining{Круговая тренировка} kfunctional{Функциональная тренировка} kfootball{Футбол} kbasketball{Баскетбол} kcricket{Крикет} ktennis{Теннис} kbadminton{Бадминтон} ktabletennis{Настольный теннис} ksquash{Сквош} kpadel{Падел} kvolleyball{Волейбол} khockey{Хоккей} kbaseball{Бейсбол} krugby{Регби} kgolf{Гольф} kbowling{Боулинг} kboxing{Бокс} kmartialarts{Боевые искусства} kwrestling{Борьба} kclimbing{Скалолазание} ksprinting{Спринт} ktrackintervals{Интервалы на стадионе} kcrosscountry{Кросс} khurdles{Бег с барьерами} klongjump{Прыжки в длину} kshotput{Толкание ядра} kjavelin{Метание копья} kpolevault{Прыжки с шестом} kmountainbiking{Горный велосипед} kkayaking{Каякинг} ksurfing{Сёрфинг} kpaddleboard{Сапбординг} kskiing{Лыжи} ksnowboarding{Сноуборд} kskating{Катание на коньках} kskateboarding{Скейтбординг} khorseriding{Верховая езда} kyoga{Йога} kpilates{Пилатес} kstretching{Растяжка} kmobility{Подвижность суставов} ktaichi{Тайцзи} kbreathwork{Дыхательная практика} kmeditation{Медитация} khousework{Домашние дела} kgardening{Садовые работы} kdogwalking{Прогулка с собакой} kchildcare{Уход за ребёнком} kdiy{Ремонт своими руками} kshopping{Покупки} kstairs{Подъём по лестнице} kgeneralworkout{Общая тренировка} kdancing{Танцы} kintimacy{Интимная близость} kphysiotherapy{Физиотерапия} ksauna{Сауна} kcoldplunge{Погружение в холодную воду} other{{name}}}", + "activityCatalogueName": "{key, select, kcardio{Кардио} kstrength{Силовые} ksports{Спорт} kathletics{Лёгкая атлетика} koutdoor{На природе} kmindbody{Тело и внимание} keveryday{Повседневные дела} kother{Другое} krunning{Бег} ktrailrunning{Трейлраннинг} kwalking{Ходьба} khiking{Пеший поход} kcycling{Велоспорт} kindoorbike{Велотренажёр} krowing{Гребля} kswimming{Плавание} kelliptical{Эллиптический тренажёр} kstairclimber{Степпер} ktreadmill{Беговая дорожка} kjumprope{Прыжки со скакалкой} kweighttraining{Силовая тренировка} kpowerlifting{Пауэрлифтинг} kbodyweight{С собственным весом} kcalisthenics{Калистеника} kkettlebell{Гиря} kcrossfit{CrossFit} khiit{ВИИТ} kcircuittraining{Круговая тренировка} kfunctional{Функциональная тренировка} kfootball{Футбол} kbasketball{Баскетбол} kcricket{Крикет} ktennis{Теннис} kbadminton{Бадминтон} ktabletennis{Настольный теннис} ksquash{Сквош} kpadel{Падел} kpickleball{Пиклбол} kvolleyball{Волейбол} khockey{Хоккей} kbaseball{Бейсбол} krugby{Регби} kgolf{Гольф} kbowling{Боулинг} kboxing{Бокс} kmartialarts{Боевые искусства} kwrestling{Борьба} kclimbing{Скалолазание} ksprinting{Спринт} ktrackintervals{Интервалы на стадионе} kcrosscountry{Кросс} khurdles{Бег с барьерами} klongjump{Прыжки в длину} kshotput{Толкание ядра} kjavelin{Метание копья} kpolevault{Прыжки с шестом} kmountainbiking{Горный велосипед} kkayaking{Каякинг} ksurfing{Сёрфинг} kpaddleboard{Сапбординг} kskiing{Лыжи} ksnowboarding{Сноуборд} kskating{Катание на коньках} kskateboarding{Скейтбординг} khorseriding{Верховая езда} kyoga{Йога} kpilates{Пилатес} kstretching{Растяжка} kmobility{Подвижность суставов} ktaichi{Тайцзи} kbreathwork{Дыхательная практика} kmeditation{Медитация} khousework{Домашние дела} kgardening{Садовые работы} kdogwalking{Прогулка с собакой} kchildcare{Уход за ребёнком} kdiy{Ремонт своими руками} kshopping{Покупки} kstairs{Подъём по лестнице} kgeneralworkout{Общая тренировка} kdancing{Танцы} kintimacy{Интимная близость} kphysiotherapy{Физиотерапия} ksauna{Сауна} kcoldplunge{Погружение в холодную воду} other{{name}}}", "@activityCatalogueName": { "placeholders": { "key": { diff --git a/lib/ui2/activity/catalogue.dart b/lib/ui2/activity/catalogue.dart index 3a6e00927..bc47dbe52 100644 --- a/lib/ui2/activity/catalogue.dart +++ b/lib/ui2/activity/catalogue.dart @@ -171,6 +171,10 @@ const activityLibrary = [ // are different games, and borrowing either would be a stand-in. The // post-session estimate still works from heart rate. Activity('Padel', LucideIcons.volleyball, C.yellow, Track.duration, null), + // No MET for the same reason: the 2011 compendium predates pickleball as + // a listed activity, and paddleball or tennis doubles would be a guess. + Activity( + 'Pickleball', LucideIcons.volleyball, C.green, Track.duration, null), Activity('Volleyball', LucideIcons.volleyball, C.orange, Track.duration, 6.0), Activity('Hockey', LucideIcons.target, C.blue, Track.duration, 8.0), Activity('Baseball', LucideIcons.target, C.red, Track.duration, 5.0), diff --git a/lib/ui2/activity/summary.dart b/lib/ui2/activity/summary.dart index 7fd6d6c1d..7caf098a9 100644 --- a/lib/ui2/activity/summary.dart +++ b/lib/ui2/activity/summary.dart @@ -64,8 +64,8 @@ enum Arch { route, strength, interval, flow, laps, journey, match, basic } const _sports = { 'Football', 'Basketball', 'Cricket', 'Tennis', 'Badminton', 'Table tennis', - 'Squash', 'Padel', 'Volleyball', 'Hockey', 'Baseball', 'Rugby', 'Boxing', - 'Martial arts', 'Wrestling', + 'Squash', 'Padel', 'Pickleball', 'Volleyball', 'Hockey', 'Baseball', + 'Rugby', 'Boxing', 'Martial arts', 'Wrestling', }; const _laps = {'Swimming', 'Rowing'}; const _journey = { diff --git a/test/ui2_activity_test.dart b/test/ui2_activity_test.dart index e1721108c..3e083adf2 100644 --- a/test/ui2_activity_test.dart +++ b/test/ui2_activity_test.dart @@ -183,7 +183,8 @@ void main() { // saying it was told nothing, or a named sport the compendium has no // row for. Pinned by name, or the exception quietly becomes a habit. final unpriced = allActivities.where((a) => a.met == null).toList(); - expect(unpriced.map((a) => a.name), ['Padel', 'General workout']); + expect(unpriced.map((a) => a.name), + ['Padel', 'Pickleball', 'General workout']); }); test('padel, skateboarding and push-ups resolve by their stored keys', () { diff --git a/test/whoop_activity_type_test.dart b/test/whoop_activity_type_test.dart index 21960dd37..63d39e1ab 100644 --- a/test/whoop_activity_type_test.dart +++ b/test/whoop_activity_type_test.dart @@ -44,6 +44,16 @@ void main() { } }); + test('an imported pickleball session is a catalogue sport', () { + final key = WhoopImporter.activityTypeKey('Pickleball'); + expect(activityByName(key)?.name, 'Pickleball'); + expect(healthActivityForType(key, ios: true), + HealthWorkoutActivityType.PICKLEBALL); + // Health Connect has no pickleball type. + expect(healthActivityForType(key, ios: false), + HealthWorkoutActivityType.TENNIS); + }); + test('rows stored with the raw WHOOP name still map', () { // The importer never rewrites a session it already holds, so rows from // an earlier import keep the old spelling.