Files
food-ai/client/lib/features/profile/profile_service.dart
dbastrikin 87ef2097fc feat: meal tracking, dish recognition UX improvements, English AI prompts
Backend:
- Translate all recognition prompts (receipt, products, dish) from Russian to English
- Add lang parameter to Recognizer interface and pass locale.FromContext in handlers
- DishResult type uses candidates array for multi-candidate responses

Client:
- Add meal tracking: diary provider, date selector, meal type model
- DishResult parser: backward-compatible with legacy flat format and new candidates format
- DishResultScreen: sticky bottom button, full-width portion/meal-type inputs,
  КБЖУ disclaimer moved under nutrition card, add date field to diary POST body
- Recognition prompts now return dish/product names in user's preferred language
- Onboarding, profile, home screen visual updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 14:29:36 +02:00

69 lines
2.0 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/api/api_client.dart';
import '../../core/auth/auth_provider.dart';
import '../../shared/models/user.dart';
final profileServiceProvider = Provider<ProfileService>((ref) {
return ProfileService(ref.read(apiClientProvider));
});
class UpdateProfileRequest {
final String? name;
final int? heightCm;
final double? weightKg;
final String? dateOfBirth;
final String? gender;
final String? activity;
final String? goal;
final String? language;
final List<String>? mealTypes;
final int? dailyCalories;
const UpdateProfileRequest({
this.name,
this.heightCm,
this.weightKg,
this.dateOfBirth,
this.gender,
this.activity,
this.goal,
this.language,
this.mealTypes,
this.dailyCalories,
});
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
if (name != null) map['name'] = name;
if (heightCm != null) map['height_cm'] = heightCm;
if (weightKg != null) map['weight_kg'] = weightKg;
if (dateOfBirth != null) map['date_of_birth'] = dateOfBirth;
if (gender != null) map['gender'] = gender;
if (activity != null) map['activity'] = activity;
if (goal != null) map['goal'] = goal;
if (dailyCalories != null) map['daily_calories'] = dailyCalories;
// Build preferences patch — backend merges into existing JSONB.
final prefPatch = <String, dynamic>{};
if (language != null) prefPatch['language'] = language;
if (mealTypes != null) prefPatch['meal_types'] = mealTypes;
if (prefPatch.isNotEmpty) map['preferences'] = prefPatch;
return map;
}
}
class ProfileService {
final ApiClient _client;
ProfileService(this._client);
Future<User> getProfile() async {
final json = await _client.get('/profile');
return User.fromJson(json);
}
Future<User> updateProfile(UpdateProfileRequest req) async {
final json = await _client.put('/profile', data: req.toJson());
return User.fromJson(json);
}
}