Skip to content

Commit 5dcaade

Browse files
authored
MoveTopia Update (#149)
# MoveTopia Update Changelog ## Bug fixes - Fixed wrong grouped workouts by date - Fixed health data history availablity check - Minor UX changes ## Fehlerbehebungen - Fehlerhafte Gruppierung von Aktivitäten nach Daten behoben - Fehlende Überprüfung, ob HealthData Historie verfügbar ist hinzugefügt - Kleine UX Verbesserungen
2 parents a776b7d + 97b6f59 commit 5dcaade

8 files changed

Lines changed: 99 additions & 57 deletions

File tree

lib/l10n/app_de.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@
338338
"permission_health_read_description": "Zum Lesen deiner Aktivitäten und Fitness-Daten",
339339
"permission_health_write_title": "Gesundheitsdaten Schreiben",
340340
"permission_health_write_description": "Zum Speichern deiner Aktivitäten in der Health-Datenbank",
341+
"permission_health_read_missing": "Bitte erteile zuerst die Leseberechtigung für Gesundheitsdaten",
341342
"permission_health_historical_title": "Historische Gesundheitsdaten",
342343
"permission_health_historical_description": "Für den Zugriff auf Gesundheitsdaten, die älter als 30 Tage sind, für Langzeitanalysen",
343344
"permission_allow": "Erlauben",

lib/l10n/app_en.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@
357357
"permission_health_read_description": "To read your activities and fitness data",
358358
"permission_health_write_title": "Health Data Write",
359359
"permission_health_write_description": "To save your activities to the health database",
360+
"permission_health_read_missing": "Please first allow access to read your health data",
360361
"permission_health_historical_title": "Historical Health Data",
361362
"permission_health_historical_description": "To access your health data older than 30 days for long-term analysis",
362363
"permission_allow": "Allow",

lib/presentation/activities/list/screen/activities_screen.dart

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:io' show Platform;
2+
23
import 'package:flutter/material.dart';
34
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
45
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -141,51 +142,67 @@ Widget _buildGroupedActivities(
141142
return seconds ~/ 60;
142143
}
143144

144-
return ListView.builder(
145-
controller: scrollController,
146-
physics: const ScrollPhysics(),
147-
itemCount: activities?.length ?? 0,
148-
itemBuilder: (context, index) {
149-
final date = activities?.keys.elementAt(index);
150-
final activityList = activities?[date]! ?? [];
151-
return Column(
152-
crossAxisAlignment: CrossAxisAlignment.start,
153-
children: [
154-
if (date != null && activityList.isNotEmpty)
155-
Padding(
156-
padding:
157-
const EdgeInsets.only(top: 16.0, left: 16.0, right: 16.0),
158-
child: Row(
159-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
160-
children: [
161-
Text(
162-
DateFormat("dd. MMMM yyyy").format(date),
163-
style: const TextStyle(fontWeight: FontWeight.bold),
164-
),
165-
Text(
166-
getDuration(getActivityMinutes(activityList), context),
167-
style: const TextStyle(fontWeight: FontWeight.bold),
145+
return LayoutBuilder(
146+
builder: (context, constraints) {
147+
return SingleChildScrollView(
148+
physics: const AlwaysScrollableScrollPhysics(),
149+
controller: scrollController,
150+
child: ConstrainedBox(
151+
constraints: BoxConstraints(
152+
minHeight: constraints.maxHeight,
153+
),
154+
child: ListView.builder(
155+
shrinkWrap: true,
156+
physics: const NeverScrollableScrollPhysics(),
157+
itemCount: activities?.length ?? 0,
158+
itemBuilder: (context, index) {
159+
final date = activities?.keys.elementAt(index);
160+
final activityList = activities?[date]! ?? [];
161+
return Column(
162+
crossAxisAlignment: CrossAxisAlignment.start,
163+
children: [
164+
if (date != null && activityList.isNotEmpty)
165+
Padding(
166+
padding: const EdgeInsets.only(
167+
top: 16.0, left: 16.0, right: 16.0),
168+
child: Row(
169+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
170+
children: [
171+
Text(
172+
DateFormat("dd. MMMM yyyy").format(date),
173+
style:
174+
const TextStyle(fontWeight: FontWeight.bold),
175+
),
176+
Text(
177+
getDuration(
178+
getActivityMinutes(activityList), context),
179+
style:
180+
const TextStyle(fontWeight: FontWeight.bold),
181+
),
182+
]),
168183
),
169-
]),
170-
),
171-
const Divider(),
172-
...activityList.map(
173-
(activity) => _buildActivityItem(context, activity),
184+
const Divider(),
185+
...activityList.map(
186+
(activity) => _buildActivityItem(context, activity),
187+
),
188+
// Add a loading indicator at the end of the list,
189+
if (index == activities!.length - 1 && isLoading)
190+
const Padding(
191+
padding: EdgeInsets.symmetric(vertical: 8.0),
192+
child: Center(child: CircularProgressIndicator()),
193+
) // Show loading
194+
// Show no more entries text if end is reached
195+
else if (index == activities.length - 1 && !isLoading)
196+
const Padding(
197+
padding: EdgeInsets.all(16.0),
198+
child: Center(
199+
child: Text("No more entries"),
200+
)),
201+
],
202+
);
203+
},
174204
),
175-
// Add a loading indicator at the end of the list,
176-
if (index == activities!.length - 1 && isLoading)
177-
const Padding(
178-
padding: EdgeInsets.symmetric(vertical: 8.0),
179-
child: Center(child: CircularProgressIndicator()),
180-
) // Show loading
181-
// Show no more entries text if end is reached
182-
else if (index == activities.length - 1 && !isLoading)
183-
const Padding(
184-
padding: EdgeInsets.all(16.0),
185-
child: Center(
186-
child: Text("No more entries"),
187-
)),
188-
],
205+
),
189206
);
190207
},
191208
);

lib/presentation/activities/list/view_model/activities_view_model.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class ActivitiesViewModel extends StateNotifier<ActivitiesState> {
5353

5454
for (int i = 0; i < workouts.length; i++) {
5555
ActivityPreview workout = workouts[i];
56+
5657
state.icons ??= {};
5758
if (state.icons!.containsKey(workout.sourceId)) {
5859
workouts[i].icon = state.icons?[workout.sourceId];
@@ -63,8 +64,10 @@ class ActivitiesViewModel extends StateNotifier<ActivitiesState> {
6364
state.icons![workout.sourceId] = workouts[i].icon;
6465
state = state.copyWith(newIcons: state.icons);
6566
}
67+
// Convert the start date to local time
68+
final startDateLocal = toLocal(workout.start);
6669
DateTime day = DateTime(
67-
workout.start.year, workout.start.month, workout.start.day);
70+
startDateLocal.year, startDateLocal.month, startDateLocal.day);
6871
if (workoutsByDay[day] == null) {
6972
workoutsByDay[day] = [];
7073
}

lib/presentation/challenges/badgeLists/screen/badge_lists_screen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class _BadgeTabsView extends StatelessWidget {
138138
children: [
139139
TabBar(
140140
isScrollable: true,
141+
tabAlignment: TabAlignment.center,
141142
tabs: categories
142143
.map((category) => Tab(text: _getCategoryName(category, l10n)))
143144
.toList(),

lib/presentation/onboarding/providers/permissions_provider.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ class PermissionsState {
1919
final bool healthWritePermissionStatus;
2020
final bool healthHistoricalPermissionStatus;
2121

22+
/*
23+
* Determine if historical health functionality is available
24+
* Only relevant for Android, on iOS this is always false
25+
* */
26+
final bool isHealthHistoricalAvailable;
27+
2228
bool get hasRequiredPermissions => healthPermissionStatus;
2329

2430
PermissionsState({
@@ -28,6 +34,7 @@ class PermissionsState {
2834
this.healthPermissionStatus = false,
2935
this.healthWritePermissionStatus = false,
3036
this.healthHistoricalPermissionStatus = false,
37+
this.isHealthHistoricalAvailable = false,
3138
});
3239

3340
PermissionsState copyWith({
@@ -37,6 +44,7 @@ class PermissionsState {
3744
bool? healthPermissionStatus,
3845
bool? healthWritePermissionStatus,
3946
bool? healthHistoricalPermissionStatus,
47+
bool? isHealthHistoricalAvailable,
4048
}) {
4149
return PermissionsState(
4250
locationPermissionStatus:
@@ -51,6 +59,8 @@ class PermissionsState {
5159
healthWritePermissionStatus ?? this.healthWritePermissionStatus,
5260
healthHistoricalPermissionStatus: healthHistoricalPermissionStatus ??
5361
this.healthHistoricalPermissionStatus,
62+
isHealthHistoricalAvailable:
63+
isHealthHistoricalAvailable ?? this.isHealthHistoricalAvailable,
5464
);
5565
}
5666

@@ -284,7 +294,20 @@ class PermissionsNotifier extends StateNotifier<PermissionsState> {
284294
}
285295

286296
try {
287-
// Verwende die direkte API-Methode, um zu prüfen, ob historische Berechtigungen gewährt wurden
297+
// Check the availability of historical permissions
298+
// This is only relevant for Android, on iOS this is not available
299+
300+
bool isHistoricalAvailable =
301+
await _health.isHealthDataHistoryAvailable();
302+
state =
303+
state.copyWith(isHealthHistoricalAvailable: isHistoricalAvailable);
304+
if (!isHistoricalAvailable) {
305+
log.warning("Historical Health feature is not available");
306+
return;
307+
}
308+
309+
// Verwende die direkte API-Methode, um zu prüfen, ob historische Berechtigungen gewährt wurde
310+
288311
bool hasHistoricalPermissions =
289312
await _health.isHealthDataHistoryAuthorized();
290313

lib/presentation/onboarding/widgets/permissions_page.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ class PermissionsPage extends ConsumerWidget {
144144
if (!permissionsState.healthPermissionStatus) {
145145
ScaffoldMessenger.of(context).showSnackBar(
146146
SnackBar(
147-
content: Text(
148-
'Bitte erteile zuerst die Leseberechtigung für Gesundheitsdaten'),
147+
content: Text(l10n.permission_health_read_missing),
149148
backgroundColor: theme.colorScheme.error,
150149
duration: const Duration(seconds: 2),
151150
),
@@ -200,8 +199,8 @@ class PermissionsPage extends ConsumerWidget {
200199

201200
const SizedBox(height: 16),
202201

203-
// Historical Health Data permission - only for Android
204-
if (Theme.of(context).platform == TargetPlatform.android)
202+
// Historical Health Data permission - only if available
203+
if (permissionsState.isHealthHistoricalAvailable)
205204
Column(
206205
children: [
207206
PermissionCard(
@@ -216,8 +215,7 @@ class PermissionsPage extends ConsumerWidget {
216215
if (!permissionsState.healthPermissionStatus) {
217216
ScaffoldMessenger.of(context).showSnackBar(
218217
SnackBar(
219-
content: const Text(
220-
'Bitte erteile zuerst die Leseberechtigung für Gesundheitsdaten'),
218+
content: Text(l10n.permission_health_read_missing),
221219
backgroundColor: theme.colorScheme.error,
222220
duration: const Duration(seconds: 2),
223221
),

lib/presentation/profile/screen/permissions_settings_screen.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ class PermissionsSettingsScreen extends HookConsumerWidget {
136136
if (!permissionsState.healthPermissionStatus) {
137137
ScaffoldMessenger.of(context).showSnackBar(
138138
SnackBar(
139-
content: Text(
140-
'Bitte erteile zuerst die Leseberechtigung für Gesundheitsdaten'),
139+
content: Text(l10n.permission_health_read_missing),
141140
backgroundColor: theme.colorScheme.error,
142141
duration: const Duration(seconds: 2),
143142
),
@@ -193,8 +192,8 @@ class PermissionsSettingsScreen extends HookConsumerWidget {
193192

194193
const SizedBox(height: 16),
195194

196-
// Historical Health Data permission - only for Android
197-
if (Theme.of(context).platform == TargetPlatform.android)
195+
// Historical Health Data permission - only if available
196+
if (permissionsState.isHealthHistoricalAvailable)
198197
PermissionCard(
199198
icon: Icons.history,
200199
title: l10n.permission_health_historical_title,
@@ -207,8 +206,7 @@ class PermissionsSettingsScreen extends HookConsumerWidget {
207206
if (!permissionsState.healthPermissionStatus) {
208207
ScaffoldMessenger.of(context).showSnackBar(
209208
SnackBar(
210-
content: Text(
211-
'Bitte erteile zuerst die Leseberechtigung für Gesundheitsdaten'),
209+
content: Text(l10n.permission_health_read_missing),
212210
backgroundColor: theme.colorScheme.error,
213211
duration: const Duration(seconds: 2),
214212
),

0 commit comments

Comments
 (0)