Skip to content

Commit ddd5b81

Browse files
Merge pull request #198 from richardthe3rd/claude/fix-details-screen-layout-tqzdg
Redesign detail screens with unified layout pattern
2 parents 3f406d3 + f294808 commit ddd5b81

24 files changed

Lines changed: 1280 additions & 1033 deletions

lib/domain/repositories/api_drink_repository.dart

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,33 @@ import 'drink_repository.dart';
44

55
/// Implementation of DrinkRepository using API services
66
///
7-
/// Delegates to BeerApiService, FavoritesService, and RatingsService.
7+
/// Delegates to BeerApiService, FavoritesService, RatingsService, and TastingLogService.
88
class ApiDrinkRepository implements DrinkRepository {
99
final BeerApiService _apiService;
1010
final FavoritesService _favoritesService;
1111
final RatingsService _ratingsService;
12+
final TastingLogService _tastingLogService;
1213

1314
ApiDrinkRepository({
1415
required BeerApiService apiService,
1516
required FavoritesService favoritesService,
1617
required RatingsService ratingsService,
18+
required TastingLogService tastingLogService,
1719
}) : _apiService = apiService,
1820
_favoritesService = favoritesService,
19-
_ratingsService = ratingsService;
21+
_ratingsService = ratingsService,
22+
_tastingLogService = tastingLogService;
2023

2124
@override
2225
Future<List<Drink>> getDrinks(Festival festival) async {
2326
final drinks = await _apiService.fetchAllDrinks(festival);
2427

25-
// Populate favorite status and ratings in a single pass
28+
// Populate favorite status, ratings, and tasted status in a single pass
2629
final favorites = _favoritesService.getFavorites(festival.id);
2730
for (final drink in drinks) {
2831
drink.isFavorite = favorites.contains(drink.id);
2932
drink.rating = _ratingsService.getRating(festival.id, drink.id);
33+
drink.isTasted = _tastingLogService.hasTasted(festival.id, drink.id);
3034
}
3135

3236
return drinks;
@@ -56,4 +60,20 @@ class ApiDrinkRepository implements DrinkRepository {
5660
Future<void> removeRating(String festivalId, String drinkId) {
5761
return _ratingsService.removeRating(festivalId, drinkId);
5862
}
63+
64+
@override
65+
Future<bool> hasTasted(String festivalId, String drinkId) {
66+
return Future.value(_tastingLogService.hasTasted(festivalId, drinkId));
67+
}
68+
69+
@override
70+
Future<bool> toggleTasted(String festivalId, String drinkId) async {
71+
await _tastingLogService.toggleTasted(festivalId, drinkId);
72+
return _tastingLogService.hasTasted(festivalId, drinkId);
73+
}
74+
75+
@override
76+
Future<List<String>> getTastedDrinks(String festivalId) {
77+
return Future.value(_tastingLogService.getTastedDrinkIds(festivalId));
78+
}
5979
}

lib/domain/repositories/drink_repository.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import '../../models/models.dart';
22

33
/// Repository interface for drink data access
44
///
5-
/// Abstracts data access for drinks, favorites, and ratings.
5+
/// Abstracts data access for drinks, favorites, ratings, and tasting logs.
66
/// Implementations can use different data sources (API, local DB, cache).
77
abstract class DrinkRepository {
88
/// Fetch all drinks for a festival
99
///
10-
/// Returns drinks with favorite and rating status already populated.
10+
/// Returns drinks with favorite, rating, and tasting status already populated.
1111
Future<List<Drink>> getDrinks(Festival festival);
1212

1313
/// Get list of favorited drink IDs for a festival
@@ -26,4 +26,15 @@ abstract class DrinkRepository {
2626

2727
/// Remove rating for a drink
2828
Future<void> removeRating(String festivalId, String drinkId);
29+
30+
/// Check if a drink has been tasted at a festival
31+
Future<bool> hasTasted(String festivalId, String drinkId);
32+
33+
/// Toggle tasted status for a drink
34+
///
35+
/// Returns the new tasted status (true if now tasted, false if untasted).
36+
Future<bool> toggleTasted(String festivalId, String drinkId);
37+
38+
/// Get list of tasted drink IDs for a festival
39+
Future<List<String>> getTastedDrinks(String festivalId);
2940
}

lib/models/drink.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,15 @@ class Drink {
210210
final String festivalId;
211211
bool isFavorite;
212212
int? rating;
213+
bool isTasted;
213214

214215
Drink({
215216
required this.product,
216217
required this.producer,
217218
required this.festivalId,
218219
this.isFavorite = false,
219220
this.rating,
221+
this.isTasted = false,
220222
});
221223

222224
String get id => product.id;

lib/providers/beer_provider.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,13 @@ class BeerProvider extends ChangeNotifier {
167167
if (_drinkRepository == null) {
168168
final favoritesService = FavoritesService(prefs);
169169
final ratingsService = RatingsService(prefs);
170+
final tastingLogService = TastingLogService(prefs);
170171
final apiService = BeerApiService();
171172
_drinkRepository = ApiDrinkRepository(
172173
apiService: apiService,
173174
favoritesService: favoritesService,
174175
ratingsService: ratingsService,
176+
tastingLogService: tastingLogService,
175177
);
176178
}
177179

@@ -496,6 +498,26 @@ class BeerProvider extends ChangeNotifier {
496498
notifyListeners();
497499
}
498500

501+
/// Toggle tasted status for a drink
502+
Future<void> toggleTasted(Drink drink) async {
503+
if (_drinkRepository == null) return;
504+
505+
final newStatus = await _drinkRepository!.toggleTasted(
506+
currentFestival.id,
507+
drink.id,
508+
);
509+
drink.isTasted = newStatus;
510+
511+
notifyListeners();
512+
513+
// Log analytics event
514+
if (newStatus) {
515+
unawaited(analyticsService.logTastedAdded(drink));
516+
} else {
517+
unawaited(analyticsService.logTastedRemoved(drink));
518+
}
519+
}
520+
499521
/// Get a drink by ID
500522
Drink? getDrinkById(String id) {
501523
try {

0 commit comments

Comments
 (0)