Skip to content

Commit 89b1e06

Browse files
Merge pull request #209 from richardthe3rd/claude/prioritize-impact-improvements-gqqLR
Fix 3 critical bugs: parallel API fetching, dart:io web breakage, festival URL sync
2 parents a0e5c47 + 1461020 commit 89b1e06

5 files changed

Lines changed: 326 additions & 18 deletions

File tree

lib/providers/beer_provider.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'dart:async';
2-
import 'dart:io';
32
import 'package:flutter/material.dart';
3+
import 'package:http/http.dart' as http;
44
import 'package:shared_preferences/shared_preferences.dart';
55
import '../models/models.dart';
66
import '../services/services.dart';
@@ -361,7 +361,7 @@ class BeerProvider extends ChangeNotifier {
361361
} else {
362362
return 'Could not load festivals. Please check your connection.';
363363
}
364-
} else if (error is SocketException) {
364+
} else if (error is http.ClientException) {
365365
return 'No internet connection. Please check your network.';
366366
} else if (error is TimeoutException) {
367367
return 'Request timed out. Please check your connection and try again.';

lib/services/beer_api_service.dart

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,30 @@ class BeerApiService {
3737
}
3838

3939
/// Fetches all available drinks from a festival (all beverage types)
40-
///
40+
///
41+
/// Fetches all beverage types in parallel for faster loading.
4142
/// Throws [BeerApiException] if ALL beverage types fail to load or return
4243
/// no drinks. Individual failures are tracked and reported in the exception
4344
/// message to help diagnose issues like CORS or network problems.
4445
Future<List<Drink>> fetchAllDrinks(Festival festival) async {
4546
final allDrinks = <Drink>[];
4647
final errors = <String, String>{};
4748

48-
for (final beverageType in festival.availableBeverageTypes) {
49-
try {
50-
final drinks = await fetchDrinks(festival, beverageType);
51-
allDrinks.addAll(drinks);
52-
} catch (e) {
53-
// Track the error for this beverage type
54-
errors[beverageType] = e.toString();
55-
}
49+
// Fetch all beverage types in parallel for faster loading
50+
final results = await Future.wait(
51+
festival.availableBeverageTypes.map((beverageType) async {
52+
try {
53+
return await fetchDrinks(festival, beverageType);
54+
} catch (e) {
55+
// Track the error for this beverage type
56+
errors[beverageType] = e.toString();
57+
return <Drink>[];
58+
}
59+
}),
60+
);
61+
62+
for (final drinks in results) {
63+
allDrinks.addAll(drinks);
5664
}
5765

5866
// If we got no drinks at all and there were errors, throw with details

lib/widgets/festival_menu_sheets.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,24 @@ class FestivalSelectorSheet extends StatelessWidget {
185185
sortedFestivals: festivals,
186186
isSelected: isSelected,
187187
onTap: () {
188+
// Capture current path first, before any state changes
189+
// Default to festival home; override if currently on favorites
190+
String targetPath = buildFestivalHome(festival.id);
191+
try {
192+
final currentPath = GoRouterState.of(context).uri.path;
193+
// Preserve user's tab: if on favorites, stay on favorites
194+
if (currentPath.endsWith('/favorites')) {
195+
targetPath = buildFavoritesPath(festival.id);
196+
}
197+
} catch (e) {
198+
// GoRouterState unavailable (e.g., in tests), keep default path
199+
debugPrint('Festival selector: Unable to get current route, using default: $e');
200+
}
201+
202+
final router = GoRouter.maybeOf(context);
188203
provider.setFestival(festival);
189204
Navigator.pop(context);
205+
router?.go(targetPath);
190206
},
191207
onInfoTap: () {
192208
Navigator.pop(context);

test/provider_test.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import 'dart:async';
2-
import 'dart:io';
32
import 'package:flutter_test/flutter_test.dart';
43
import 'package:cambridge_beer_festival/providers/beer_provider.dart';
54
import 'package:cambridge_beer_festival/services/services.dart';
5+
import 'package:http/http.dart' as http;
66
import 'package:cambridge_beer_festival/models/models.dart';
77
import 'package:cambridge_beer_festival/domain/models/models.dart';
88
import 'package:cambridge_beer_festival/domain/repositories/repositories.dart';
@@ -153,16 +153,16 @@ void main() {
153153
);
154154
await provider.initialize();
155155

156-
// Mock SocketException (no internet)
156+
// http.ClientException is thrown on network failures across all platforms
157157
when(mockDrinkRepository.getDrinks(any))
158-
.thenThrow(const SocketException('Failed host lookup'));
158+
.thenThrow(http.ClientException('Failed host lookup'));
159159

160160
await provider.loadDrinks();
161161

162162
expect(provider.error, isNotNull);
163163
expect(provider.error, contains('No internet connection'));
164164
expect(provider.error, contains('check your network'));
165-
expect(provider.error, isNot(contains('SocketException')));
165+
expect(provider.error, isNot(contains('ClientException')));
166166
expect(provider.error, isNot(contains('Failed host lookup')));
167167
});
168168

@@ -315,15 +315,15 @@ void main() {
315315
analyticsService: mockAnalyticsService,
316316
);
317317

318-
// Mock SocketException
318+
// http.ClientException is thrown on network failures across all platforms
319319
when(mockFestivalRepository.getFestivals())
320-
.thenThrow(const SocketException('Network unreachable'));
320+
.thenThrow(http.ClientException('Network unreachable'));
321321

322322
await provider.loadFestivals();
323323

324324
expect(provider.festivalsError, isNotNull);
325325
expect(provider.festivalsError, contains('No internet connection'));
326-
expect(provider.festivalsError, isNot(contains('SocketException')));
326+
expect(provider.festivalsError, isNot(contains('ClientException')));
327327
});
328328

329329
test('shows connection message for FestivalServiceException without status',

0 commit comments

Comments
 (0)