forked from eatvio/eatvio_app
review: fixed review issues
This commit is contained in:
@@ -58,7 +58,7 @@ class InfoRow extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
SvgPicture.asset('assets/icons/calories.svg', width: 13.3, height: 13.3),
|
SvgPicture.asset('assets/icons/calories.svg', width: 13.3, height: 13.3),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text('${recipe?.calories.toStringAsFixed(0) ?? '0'} ккал', style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
|
Text('${(recipe?.calories ?? 0).toStringAsFixed(0)} ккал', style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
|
|||||||
@@ -199,11 +199,17 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int _maxImageBytesForBase64 = 5 * 1024 * 1024;
|
||||||
|
|
||||||
Future<Diet?> getDietForPreview() async {
|
Future<Diet?> getDietForPreview() async {
|
||||||
if (!_isFormValidForDraft()) return null;
|
if (!_isFormValidForDraft()) return null;
|
||||||
final authorProfile = await profileRepository.getMyProfile();
|
final authorProfile = await profileRepository.getMyProfile();
|
||||||
final imageBytes = (await state.dietData.image?.readAsBytes()) ?? <int>[];
|
final imageBytes = (await state.dietData.image?.readAsBytes()) ?? <int>[];
|
||||||
String image = base64.encode(imageBytes);
|
String image = '';
|
||||||
|
if (imageBytes.isNotEmpty && imageBytes.length <= _maxImageBytesForBase64) {
|
||||||
|
image = base64.encode(imageBytes);
|
||||||
|
}
|
||||||
if (image.isEmpty && state.dietData.imageUrl != null) {
|
if (image.isEmpty && state.dietData.imageUrl != null) {
|
||||||
image = state.dietData.imageUrl ?? '';
|
image = state.dietData.imageUrl ?? '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ class _DietPreviewScreenState extends State<DietPreviewScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final s = S.of(context);
|
final s = S.of(context);
|
||||||
|
|||||||
@@ -61,8 +61,10 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
|||||||
child: SuccessPublishedDietOrPlanBottomSheet(title: widget.diet.name),
|
child: SuccessPublishedDietOrPlanBottomSheet(title: widget.diet.name),
|
||||||
);
|
);
|
||||||
await context.read<MyDietsCubit>().loadAllDiets();
|
await context.read<MyDietsCubit>().loadAllDiets();
|
||||||
|
break;
|
||||||
case 422:
|
case 422:
|
||||||
showErrorToast('Пожалуйста, заполните все обязательные поля для публикации');
|
showErrorToast('Пожалуйста, заполните все обязательные поля для публикации');
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:eatvio_app/core/app_config.dart';
|
import 'package:eatvio_app/core/app_config.dart';
|
||||||
import 'package:eatvio_app/core/app_initializer.dart';
|
import 'package:eatvio_app/core/app_initializer.dart';
|
||||||
import 'package:eatvio_app/core/locator_service.dart';
|
import 'package:eatvio_app/core/locator_service.dart';
|
||||||
@@ -13,7 +15,6 @@ import 'package:flutter_image_compress/flutter_image_compress.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:mockito/annotations.dart';
|
import 'package:mockito/annotations.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
|
|
||||||
import 'create_diet_cubit_test.mocks.dart';
|
import 'create_diet_cubit_test.mocks.dart';
|
||||||
|
|
||||||
@GenerateNiceMocks([MockSpec<CreateDietRepository>(), MockSpec<ProfileRepository>(), MockSpec<GlossaryRepository>()])
|
@GenerateNiceMocks([MockSpec<CreateDietRepository>(), MockSpec<ProfileRepository>(), MockSpec<GlossaryRepository>()])
|
||||||
@@ -316,6 +317,88 @@ void main() {
|
|||||||
expect(result, 'error');
|
expect(result, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('updateDiet returns error and resets isDietBeingEdited when repository throws', () async {
|
||||||
|
cubit.setName('Test Diet');
|
||||||
|
cubit.setDetails('Test Description');
|
||||||
|
cubit.setDuration(0);
|
||||||
|
cubit.setDietState(DietState.active);
|
||||||
|
const portion = DailySchedule(
|
||||||
|
name: 'Apple',
|
||||||
|
portion: Portion.grams,
|
||||||
|
quantity: 100,
|
||||||
|
dailyNutrition: DailyNutrition(energy: 52.0, proteins: 0.3, fats: 0.2, carbohydrates: 14.0),
|
||||||
|
productNutritionalValueId: 1,
|
||||||
|
);
|
||||||
|
cubit.addPortion(dayIndex: 0, mealIndex: 0, portion: portion);
|
||||||
|
// No image so we reach repository.updateDiet without compression
|
||||||
|
|
||||||
|
when(dietRepository.updateDiet(
|
||||||
|
dietId: 1,
|
||||||
|
state: anyNamed('state'),
|
||||||
|
name: anyNamed('name'),
|
||||||
|
duration: anyNamed('duration'),
|
||||||
|
meatType: anyNamed('meatType'),
|
||||||
|
carbType: anyNamed('carbType'),
|
||||||
|
vegType: anyNamed('vegType'),
|
||||||
|
lightType: anyNamed('lightType'),
|
||||||
|
details: anyNamed('details'),
|
||||||
|
image: anyNamed('image'),
|
||||||
|
dailySchedule: anyNamed('dailySchedule'),
|
||||||
|
)).thenThrow(Exception('network error'));
|
||||||
|
|
||||||
|
final result = await cubit.updateDiet(1);
|
||||||
|
|
||||||
|
expect(result, 'error');
|
||||||
|
expect(cubit.state.isDietBeingEdited, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createDiet returns error when repository createDiet throws', () async {
|
||||||
|
cubit.setName('Test Diet');
|
||||||
|
cubit.setDetails('Test Description');
|
||||||
|
cubit.setDuration(0);
|
||||||
|
cubit.setDietState(DietState.active);
|
||||||
|
const portion = DailySchedule(
|
||||||
|
name: 'Apple',
|
||||||
|
portion: Portion.grams,
|
||||||
|
quantity: 100,
|
||||||
|
dailyNutrition: DailyNutrition(energy: 52.0, proteins: 0.3, fats: 0.2, carbohydrates: 14.0),
|
||||||
|
productNutritionalValueId: 1,
|
||||||
|
);
|
||||||
|
for (var day = 0; day < 7; day++) {
|
||||||
|
cubit.addPortion(dayIndex: day, mealIndex: 0, portion: portion);
|
||||||
|
}
|
||||||
|
final tempDir = Directory.systemTemp;
|
||||||
|
final tempFile = File('${tempDir.path}/create_diet_test_image_${DateTime.now().millisecondsSinceEpoch}.png');
|
||||||
|
final pngBytes = [
|
||||||
|
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
||||||
|
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
|
||||||
|
0xDE, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E,
|
||||||
|
0x44, 0xAE, 0x42, 0x60, 0x82,
|
||||||
|
];
|
||||||
|
await tempFile.writeAsBytes(pngBytes);
|
||||||
|
cubit.setImage(XFile(tempFile.path));
|
||||||
|
when(dietRepository.createDiet(
|
||||||
|
name: anyNamed('name'),
|
||||||
|
duration: anyNamed('duration'),
|
||||||
|
state: anyNamed('state'),
|
||||||
|
meatType: anyNamed('meatType'),
|
||||||
|
carbType: anyNamed('carbType'),
|
||||||
|
vegType: anyNamed('vegType'),
|
||||||
|
lightType: anyNamed('lightType'),
|
||||||
|
details: anyNamed('details'),
|
||||||
|
image: anyNamed('image'),
|
||||||
|
dailySchedule: anyNamed('dailySchedule'),
|
||||||
|
)).thenThrow(Exception('server error'));
|
||||||
|
|
||||||
|
final result = await cubit.createDiet();
|
||||||
|
|
||||||
|
expect(result, 'error');
|
||||||
|
expect(cubit.state.isDietPublishing, false);
|
||||||
|
if (await tempFile.exists()) await tempFile.delete();
|
||||||
|
});
|
||||||
|
|
||||||
test('createDiet validates name length', () async {
|
test('createDiet validates name length', () async {
|
||||||
cubit.setName('Te'); // Less than 3 characters
|
cubit.setName('Te'); // Less than 3 characters
|
||||||
cubit.setDetails('Test Description');
|
cubit.setDetails('Test Description');
|
||||||
|
|||||||
@@ -139,5 +139,34 @@ void main() {
|
|||||||
expect(find.text('10'), findsOneWidget); // totalLikes
|
expect(find.text('10'), findsOneWidget); // totalLikes
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('renders diet preview with isImageInBase64 false (URL image)', (tester) async {
|
||||||
|
await mockNetworkImagesFor(() async {
|
||||||
|
final testDiet = Diet(
|
||||||
|
id: 1,
|
||||||
|
slug: 'test-diet',
|
||||||
|
name: 'Test Diet URL Image',
|
||||||
|
image: 'https://example.com/diet-cover.jpg',
|
||||||
|
duration: 7,
|
||||||
|
state: DietState.active,
|
||||||
|
type: const DietType(veg: true, light: false, carb: false, meat: false),
|
||||||
|
details: 'Test diet details',
|
||||||
|
dailySchedule: {},
|
||||||
|
author: const Author(authorSlug: 'test-author', authorName: 'Test Author', authorProfileIcon: 'https://example.com/photo.jpg', authorIsMe: false),
|
||||||
|
totalLikes: 10,
|
||||||
|
totalViews: 100,
|
||||||
|
totalComments: 5,
|
||||||
|
wasLikedByMe: false,
|
||||||
|
isFavorite: false,
|
||||||
|
dailyNutrition: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(wrap(DietPreviewScreen(diet: testDiet, isImageInBase64: false)));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(DietPreviewScreen), findsOneWidget);
|
||||||
|
expect(find.text('Test Diet URL Image'), findsOneWidget);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,11 +269,11 @@ void main() {
|
|||||||
when(mockCreateDietRepository.updateDiet(
|
when(mockCreateDietRepository.updateDiet(
|
||||||
dietId: 1,
|
dietId: 1,
|
||||||
state: DietState.active,
|
state: DietState.active,
|
||||||
)).thenAnswer((_) async => 200);
|
)).thenAnswer((_) async => 201);
|
||||||
|
|
||||||
final result = await myDietsCubit!.publishDiet(1);
|
final result = await myDietsCubit!.publishDiet(1);
|
||||||
|
|
||||||
expect(result, 200);
|
expect(result, 201);
|
||||||
verify(mockCreateDietRepository.updateDiet(dietId: 1, state: DietState.active)).called(1);
|
verify(mockCreateDietRepository.updateDiet(dietId: 1, state: DietState.active)).called(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user