forked from eatvio/eatvio_app
plan creation screen added
This commit is contained in:
@@ -2,19 +2,21 @@ import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/day_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/duration_drop_down_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/image_picker_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/diet_preview_screen.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_duration_drop_down_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_image_picker_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/status_drop_down_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/type_choice_widget.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_type_choice_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class CreateDietScreen extends StatelessWidget {
|
||||
static const name = 'createDietScreen';
|
||||
@@ -78,13 +80,13 @@ class CreateDietScreenContent extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
DurationDropDownWidget(),
|
||||
DietDurationDropDownWidget(),
|
||||
SizedBox(height: 12),
|
||||
StatusDropDownWidget(),
|
||||
SizedBox(height: 16),
|
||||
TypeChoiceWidget(),
|
||||
DietTypeChoiceWidget(),
|
||||
SizedBox(height: 16),
|
||||
ImagePickerWidget(),
|
||||
DietImagePickerWidget(),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
@@ -108,9 +110,66 @@ class CreateDietScreenContent extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
DayWidget(
|
||||
index: 0,
|
||||
),
|
||||
BlocBuilder<CreateDietCubit, CreateDietState>(
|
||||
builder: (context, state) {
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.all(0),
|
||||
itemBuilder: (context, index) => DayWidget(index: index),
|
||||
itemCount: state.dietData.dailySchedule?.length ?? 0,
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
context.read<CreateDietCubit>().setDietState(2);
|
||||
},
|
||||
text: s.to_draft,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
final diet = await context.read<CreateDietCubit>().getDietForPreview();
|
||||
GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: diet);
|
||||
},
|
||||
text: s.preview,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
context.read<CreateDietCubit>().publishDiet();
|
||||
},
|
||||
text: s.publish,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import 'dart:convert';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
|
||||
class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
final CreateDietRepository createDietRepository;
|
||||
final ProfileRepository profileRepository;
|
||||
final GlossaryRepository glossaryRepository;
|
||||
static const _dietStateValues = ['active', 'draft', 'personal'];
|
||||
CreateDietCubit({required this.createDietRepository, required this.glossaryRepository}) : super(CreateDietState.initial());
|
||||
static const _dietStateValues = ['active', 'personal', 'draft'];
|
||||
CreateDietCubit({required this.profileRepository, required this.createDietRepository, required this.glossaryRepository}) : super(CreateDietState.initial());
|
||||
|
||||
void setDetails(String text) {
|
||||
emit(state.copyWith(dietData: state.dietData.copyWith(details: text)));
|
||||
@@ -22,6 +25,44 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
}
|
||||
|
||||
void setDuration(int index) {
|
||||
final selectedDaysValue = durationValues[index];
|
||||
final currentDaysValue = state.dietData.dailySchedule?.length;
|
||||
final dailySchedule = state.dietData.dailySchedule;
|
||||
|
||||
if (currentDaysValue != null && dailySchedule != null) {
|
||||
final deepCopyOfDailySchedule = dailySchedule
|
||||
.map(
|
||||
(day) => day.map((meal) => [...meal]).toList(),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (currentDaysValue > selectedDaysValue) {
|
||||
final difference = currentDaysValue - selectedDaysValue;
|
||||
for (int i = 0; i < difference; i++) {
|
||||
deepCopyOfDailySchedule.removeLast();
|
||||
}
|
||||
} else if (selectedDaysValue > currentDaysValue) {
|
||||
final difference = selectedDaysValue - currentDaysValue;
|
||||
for (int i = 0; i < difference; i++) {
|
||||
deepCopyOfDailySchedule.add([[], [], [], [], []]);
|
||||
}
|
||||
}
|
||||
emit(
|
||||
state.copyWith(
|
||||
dietData: state.dietData.copyWith(
|
||||
dailySchedule: deepCopyOfDailySchedule,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final List<List<List<DailySchedule>>> dailySchedule = List.generate(selectedDaysValue, (index) => [[], [], [], [], []]);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
dietData: state.dietData.copyWith(dailySchedule: dailySchedule),
|
||||
),
|
||||
);
|
||||
}
|
||||
emit(
|
||||
state.copyWith(
|
||||
durationIndex: index,
|
||||
@@ -52,15 +93,174 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
emit(state.copyWith(dietData: state.dietData.copyWith(type: type)));
|
||||
}
|
||||
|
||||
void addPortion({required int dayIndex,required int mealIndex, required DailySchedule portion}) {
|
||||
final currentSchedule = state.dietData.dailySchedule;
|
||||
if (currentSchedule != null) {
|
||||
|
||||
void addPortion({required int dayIndex, required int mealIndex, required DailySchedule portion}) {
|
||||
final dailySchedule = state.dietData.dailySchedule;
|
||||
if (dailySchedule != null) {
|
||||
final deepCopyOfDailySchedule = dailySchedule
|
||||
.map(
|
||||
(day) => day.map((meal) => [...meal]).toList(),
|
||||
)
|
||||
.toList();
|
||||
deepCopyOfDailySchedule[dayIndex][mealIndex].add(portion);
|
||||
|
||||
final newDietData = state.dietData.copyWith(dailySchedule: deepCopyOfDailySchedule);
|
||||
emit(state.copyWith(dietData: newDietData));
|
||||
}
|
||||
}
|
||||
|
||||
void removePortion({required int day,required int meal,required int portionIndex, }) {}
|
||||
void removePortion({
|
||||
required int day,
|
||||
required int meal,
|
||||
required int portionIndex,
|
||||
}) {
|
||||
final dailySchedule = state.dietData.dailySchedule;
|
||||
if (dailySchedule != null) {
|
||||
final deepCopyOfDailySchedule = dailySchedule
|
||||
.map(
|
||||
(day) => day.map((meal) => [...meal]).toList(),
|
||||
)
|
||||
.toList();
|
||||
deepCopyOfDailySchedule[day][meal].removeAt(portionIndex);
|
||||
|
||||
void updatePortion({required int day,required int meal,required int portionIndex, required DailySchedule portion}) {}
|
||||
final newDietData = state.dietData.copyWith(dailySchedule: deepCopyOfDailySchedule);
|
||||
emit(state.copyWith(dietData: newDietData));
|
||||
}
|
||||
}
|
||||
|
||||
void updatePortion({required int dayIndex, required int mealIndex, required int portionIndex, required DailySchedule portion}) {
|
||||
final dailySchedule = state.dietData.dailySchedule;
|
||||
if (dailySchedule != null) {
|
||||
final deepCopyOfDailySchedule = dailySchedule
|
||||
.map(
|
||||
(day) => day.map((meal) => [...meal]).toList(),
|
||||
)
|
||||
.toList();
|
||||
deepCopyOfDailySchedule[dayIndex][mealIndex][portionIndex] = portion;
|
||||
|
||||
final newDietData = state.dietData.copyWith(dailySchedule: deepCopyOfDailySchedule);
|
||||
emit(state.copyWith(dietData: newDietData));
|
||||
}
|
||||
}
|
||||
|
||||
void copyDay(int dayIndex) {
|
||||
final dailySchedule = state.dietData.dailySchedule;
|
||||
if (dailySchedule != null) {
|
||||
final deepCopyOfDailySchedule = dailySchedule
|
||||
.map(
|
||||
(day) => day.map((meal) => [...meal]).toList(),
|
||||
)
|
||||
.toList();
|
||||
final copiedDay = deepCopyOfDailySchedule[dayIndex];
|
||||
emit(state.copyWith(copiedDay: copiedDay));
|
||||
}
|
||||
}
|
||||
|
||||
void pasteCopiedDay(int dayIndex) {
|
||||
final dailySchedule = state.dietData.dailySchedule;
|
||||
final copiedDay = state.copiedDay;
|
||||
if (dailySchedule != null && copiedDay != null) {
|
||||
final deepCopyOfDailySchedule = dailySchedule
|
||||
.map(
|
||||
(day) => day.map((meal) => [...meal]).toList(),
|
||||
)
|
||||
.toList();
|
||||
deepCopyOfDailySchedule[dayIndex] = copiedDay;
|
||||
final newDietData = state.dietData.copyWith(dailySchedule: deepCopyOfDailySchedule);
|
||||
emit(state.copyWith(dietData: newDietData));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Diet> getDietForPreview() async {
|
||||
final authorProfile = await profileRepository.getMyProfile();
|
||||
final imageBytes = (await state.dietData.image?.readAsBytes()) ?? <int>[];
|
||||
final imageInBase64 = base64.encode(imageBytes);
|
||||
final carbs = state.dietData.dailySchedule?.map((element) {
|
||||
return element.fold<double>(0, (prev, element) {
|
||||
return prev +
|
||||
element.fold<double>(0, (prev, element) {
|
||||
return prev + (element.dailyNutrition?.carbohydrates ?? 0);
|
||||
});
|
||||
});
|
||||
}).toList();
|
||||
|
||||
final calories = state.dietData.dailySchedule?.map((element) {
|
||||
return element.fold<double>(0, (prev, element) {
|
||||
return prev +
|
||||
element.fold<double>(0, (prev, element) {
|
||||
return prev + (element.dailyNutrition?.energy ?? 0);
|
||||
});
|
||||
});
|
||||
}).toList();
|
||||
|
||||
final fats = state.dietData.dailySchedule?.map((element) {
|
||||
return element.fold<double>(0, (prev, element) {
|
||||
return prev +
|
||||
element.fold<double>(0, (prev, element) {
|
||||
return prev + (element.dailyNutrition?.fats ?? 0);
|
||||
});
|
||||
});
|
||||
}).toList();
|
||||
|
||||
final proteins = state.dietData.dailySchedule?.map((element) {
|
||||
return element.fold<double>(0, (prev, element) {
|
||||
return prev +
|
||||
element.fold<double>(0, (prev, element) {
|
||||
return prev + (element.dailyNutrition?.proteins ?? 0);
|
||||
});
|
||||
});
|
||||
}).toList();
|
||||
final dailyNutrition = <DailyNutrition>[];
|
||||
if (carbs != null && calories != null && fats != null && proteins != null) {
|
||||
for (int i = 0; i < carbs.length; i++) {
|
||||
dailyNutrition.add(
|
||||
DailyNutrition(
|
||||
carbohydrates: carbs[i],
|
||||
energy: calories[i],
|
||||
fats: fats[i],
|
||||
proteins: proteins[i],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
final diet = Diet(
|
||||
id: 0,
|
||||
name: state.dietData.name ?? '',
|
||||
image: imageInBase64,
|
||||
duration: state.dietData.duration ?? 0,
|
||||
state: state.dietData.state ?? '',
|
||||
type: DietType(
|
||||
meat: state.dietData.type[0],
|
||||
veg: state.dietData.type[1],
|
||||
carb: state.dietData.type[2],
|
||||
light: state.dietData.type[3],
|
||||
),
|
||||
details: state.dietData.details ?? '',
|
||||
dailySchedule: state.dietData.dailySchedule ?? [],
|
||||
author: Author(authorSlug: authorProfile.slug, authorName: authorProfile.name, authorProfileIcon: authorProfile.profilePhotoUrl, authorIsMe: false),
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: dailyNutrition,
|
||||
);
|
||||
return diet;
|
||||
}
|
||||
|
||||
Future<void> publishDiet() async {
|
||||
// бек судя по всему с багом
|
||||
// try {
|
||||
// final model = await state.dietData.toCreationJson();
|
||||
// model.remove('image');
|
||||
// final dailySchedule = await state.dietData.toDailyScheduleCreationJson();
|
||||
// final dio = sl<Dio>();
|
||||
// final qwe = await dio.post('/api/diets/create', data: model);
|
||||
// // final diet = await createDietRepository.createDiet(model: model);
|
||||
// // final qwe2 = createDietRepository.createDietDailySchedule(id: diet.id, model: dailySchedule);
|
||||
// } catch (e, stackTrace) {
|
||||
// print(e);
|
||||
// print('---------------------------------');
|
||||
// print(stackTrace);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import 'package:eatvio_app/features/create_diet/models/create_diet_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'create_diet_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class CreateDietState with _$CreateDietState {
|
||||
const factory CreateDietState({
|
||||
const factory CreateDietState({
|
||||
required bool isLoading,
|
||||
required String? errorMessage,
|
||||
required CreateDietModel dietData,
|
||||
required CreateDietModel dietData,
|
||||
List<List<DailySchedule>>? copiedDay,
|
||||
int? durationIndex,
|
||||
int? dietStateIndex,
|
||||
}) = _CreateDietState;
|
||||
|
||||
@@ -19,6 +19,8 @@ mixin _$CreateDietState {
|
||||
bool get isLoading => throw _privateConstructorUsedError;
|
||||
String? get errorMessage => throw _privateConstructorUsedError;
|
||||
CreateDietModel get dietData => throw _privateConstructorUsedError;
|
||||
List<List<DailySchedule>>? get copiedDay =>
|
||||
throw _privateConstructorUsedError;
|
||||
int? get durationIndex => throw _privateConstructorUsedError;
|
||||
int? get dietStateIndex => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -39,6 +41,7 @@ abstract class $CreateDietStateCopyWith<$Res> {
|
||||
{bool isLoading,
|
||||
String? errorMessage,
|
||||
CreateDietModel dietData,
|
||||
List<List<DailySchedule>>? copiedDay,
|
||||
int? durationIndex,
|
||||
int? dietStateIndex});
|
||||
|
||||
@@ -63,6 +66,7 @@ class _$CreateDietStateCopyWithImpl<$Res, $Val extends CreateDietState>
|
||||
Object? isLoading = null,
|
||||
Object? errorMessage = freezed,
|
||||
Object? dietData = null,
|
||||
Object? copiedDay = freezed,
|
||||
Object? durationIndex = freezed,
|
||||
Object? dietStateIndex = freezed,
|
||||
}) {
|
||||
@@ -79,6 +83,10 @@ class _$CreateDietStateCopyWithImpl<$Res, $Val extends CreateDietState>
|
||||
? _value.dietData
|
||||
: dietData // ignore: cast_nullable_to_non_nullable
|
||||
as CreateDietModel,
|
||||
copiedDay: freezed == copiedDay
|
||||
? _value.copiedDay
|
||||
: copiedDay // ignore: cast_nullable_to_non_nullable
|
||||
as List<List<DailySchedule>>?,
|
||||
durationIndex: freezed == durationIndex
|
||||
? _value.durationIndex
|
||||
: durationIndex // ignore: cast_nullable_to_non_nullable
|
||||
@@ -113,6 +121,7 @@ abstract class _$$CreateDietStateImplCopyWith<$Res>
|
||||
{bool isLoading,
|
||||
String? errorMessage,
|
||||
CreateDietModel dietData,
|
||||
List<List<DailySchedule>>? copiedDay,
|
||||
int? durationIndex,
|
||||
int? dietStateIndex});
|
||||
|
||||
@@ -136,6 +145,7 @@ class __$$CreateDietStateImplCopyWithImpl<$Res>
|
||||
Object? isLoading = null,
|
||||
Object? errorMessage = freezed,
|
||||
Object? dietData = null,
|
||||
Object? copiedDay = freezed,
|
||||
Object? durationIndex = freezed,
|
||||
Object? dietStateIndex = freezed,
|
||||
}) {
|
||||
@@ -152,6 +162,10 @@ class __$$CreateDietStateImplCopyWithImpl<$Res>
|
||||
? _value.dietData
|
||||
: dietData // ignore: cast_nullable_to_non_nullable
|
||||
as CreateDietModel,
|
||||
copiedDay: freezed == copiedDay
|
||||
? _value._copiedDay
|
||||
: copiedDay // ignore: cast_nullable_to_non_nullable
|
||||
as List<List<DailySchedule>>?,
|
||||
durationIndex: freezed == durationIndex
|
||||
? _value.durationIndex
|
||||
: durationIndex // ignore: cast_nullable_to_non_nullable
|
||||
@@ -171,8 +185,10 @@ class _$CreateDietStateImpl implements _CreateDietState {
|
||||
{required this.isLoading,
|
||||
required this.errorMessage,
|
||||
required this.dietData,
|
||||
final List<List<DailySchedule>>? copiedDay,
|
||||
this.durationIndex,
|
||||
this.dietStateIndex});
|
||||
this.dietStateIndex})
|
||||
: _copiedDay = copiedDay;
|
||||
|
||||
@override
|
||||
final bool isLoading;
|
||||
@@ -180,6 +196,16 @@ class _$CreateDietStateImpl implements _CreateDietState {
|
||||
final String? errorMessage;
|
||||
@override
|
||||
final CreateDietModel dietData;
|
||||
final List<List<DailySchedule>>? _copiedDay;
|
||||
@override
|
||||
List<List<DailySchedule>>? get copiedDay {
|
||||
final value = _copiedDay;
|
||||
if (value == null) return null;
|
||||
if (_copiedDay is EqualUnmodifiableListView) return _copiedDay;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
final int? durationIndex;
|
||||
@override
|
||||
@@ -187,7 +213,7 @@ class _$CreateDietStateImpl implements _CreateDietState {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CreateDietState(isLoading: $isLoading, errorMessage: $errorMessage, dietData: $dietData, durationIndex: $durationIndex, dietStateIndex: $dietStateIndex)';
|
||||
return 'CreateDietState(isLoading: $isLoading, errorMessage: $errorMessage, dietData: $dietData, copiedDay: $copiedDay, durationIndex: $durationIndex, dietStateIndex: $dietStateIndex)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -201,6 +227,8 @@ class _$CreateDietStateImpl implements _CreateDietState {
|
||||
other.errorMessage == errorMessage) &&
|
||||
(identical(other.dietData, dietData) ||
|
||||
other.dietData == dietData) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._copiedDay, _copiedDay) &&
|
||||
(identical(other.durationIndex, durationIndex) ||
|
||||
other.durationIndex == durationIndex) &&
|
||||
(identical(other.dietStateIndex, dietStateIndex) ||
|
||||
@@ -208,8 +236,14 @@ class _$CreateDietStateImpl implements _CreateDietState {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, isLoading, errorMessage,
|
||||
dietData, durationIndex, dietStateIndex);
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
isLoading,
|
||||
errorMessage,
|
||||
dietData,
|
||||
const DeepCollectionEquality().hash(_copiedDay),
|
||||
durationIndex,
|
||||
dietStateIndex);
|
||||
|
||||
/// Create a copy of CreateDietState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -226,6 +260,7 @@ abstract class _CreateDietState implements CreateDietState {
|
||||
{required final bool isLoading,
|
||||
required final String? errorMessage,
|
||||
required final CreateDietModel dietData,
|
||||
final List<List<DailySchedule>>? copiedDay,
|
||||
final int? durationIndex,
|
||||
final int? dietStateIndex}) = _$CreateDietStateImpl;
|
||||
|
||||
@@ -236,6 +271,8 @@ abstract class _CreateDietState implements CreateDietState {
|
||||
@override
|
||||
CreateDietModel get dietData;
|
||||
@override
|
||||
List<List<DailySchedule>>? get copiedDay;
|
||||
@override
|
||||
int? get durationIndex;
|
||||
@override
|
||||
int? get dietStateIndex;
|
||||
|
||||
474
lib/features/create_diet/presentation/diet_preview_screen.dart
Normal file
474
lib/features/create_diet/presentation/diet_preview_screen.dart
Normal file
@@ -0,0 +1,474 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/string_extentions.dart';
|
||||
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/diet_info_row.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
|
||||
import 'package:eatvio_app/core/widgets/cpfc_container.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class DietPreviewScreen extends StatefulWidget {
|
||||
final Diet diet;
|
||||
late final List<int> selectedIndexes;
|
||||
static const name = 'createDietScreenPreview';
|
||||
static const path = '/create-diet-screen/preview';
|
||||
DietPreviewScreen({
|
||||
super.key,
|
||||
required this.diet,
|
||||
}) {
|
||||
selectedIndexes = List.generate(diet.dailySchedule.length, (_) => 0);
|
||||
}
|
||||
|
||||
@override
|
||||
State<DietPreviewScreen> createState() => _DietPreviewScreenState();
|
||||
}
|
||||
|
||||
class _DietPreviewScreenState extends State<DietPreviewScreen> {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
final textEditingController = TextEditingController();
|
||||
bool isMoreOptionsVisible = false;
|
||||
late final Uint8List imageData;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
imageData = base64.decode(widget.diet.image);
|
||||
scrollController.addListener(() {
|
||||
if (isMoreOptionsVisible) {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: appTheme.gray100,
|
||||
resizeToAvoidBottomInset: true,
|
||||
bottomSheet: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 12) + (Platform.isIOS ? const EdgeInsets.only(bottom: 16) : EdgeInsets.zero),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: FloatingActionButton.extended(
|
||||
heroTag: 'nextButtonRegistration',
|
||||
highlightElevation: 0,
|
||||
elevation: 0,
|
||||
focusElevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
backgroundColor: appTheme.greenA700,
|
||||
onPressed: () {},
|
||||
label: Text(
|
||||
s.startDiet,
|
||||
style: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
BookmarkButton(
|
||||
isFavorite: widget.diet.isFavorite,
|
||||
onTap: () {},
|
||||
width: 52,
|
||||
height: 52,
|
||||
size: 24,
|
||||
shape: BoxShape.circle,
|
||||
color: appTheme.gray50,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: TextFormField(
|
||||
onChanged: (_) {
|
||||
setState(() {});
|
||||
},
|
||||
controller: textEditingController,
|
||||
maxLines: 5,
|
||||
minLines: 1,
|
||||
keyboardType: TextInputType.multiline,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
hintText: s.comment.capitalize(),
|
||||
hintStyle: TextStyles.textMMedium.copyWith(color: appTheme.lightGray600),
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderSide: BorderSide(
|
||||
color: Color(0xFFD1D1D6),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderSide: BorderSide(
|
||||
color: Color(0xFFD1D1D6),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderSide: BorderSide(
|
||||
color: Color(0xFFD1D1D6),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: textEditingController.text.length > 2 ? appTheme.blueA400 : appTheme.gray50,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
height: 32,
|
||||
width: 32,
|
||||
child: Icon(
|
||||
Icons.send_rounded,
|
||||
size: 18,
|
||||
color: textEditingController.text.length > 2 ? appTheme.whiteA700 : appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
widget.diet.name,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
actions: [
|
||||
PortalTarget(
|
||||
visible: isMoreOptionsVisible,
|
||||
portalFollower: MoreOptions(disableActions: true, id: widget.diet.id),
|
||||
anchor: Aligned(
|
||||
shiftToWithinBound: AxisFlag(x: true, y: true),
|
||||
follower: Alignment.topRight,
|
||||
target: Alignment.bottomRight,
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isMoreOptionsVisible = !isMoreOptionsVisible;
|
||||
});
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/icons/more_button.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
padding: EdgeInsets.only(bottom: 160),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 8),
|
||||
MainBackgroundBouble(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
Image.memory(
|
||||
imageData,
|
||||
height: 300,
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
// CachedNetworkImage(
|
||||
// imageUrl: baseUrl + '/storage/' + widget.diet.image,
|
||||
// ),
|
||||
Positioned(
|
||||
bottom: 16,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
InfoBouble(
|
||||
children: [
|
||||
SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
widget.diet.totalViews.toString(),
|
||||
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
],
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: InfoBouble(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/icons/heart.svg',
|
||||
width: 14,
|
||||
height: 12,
|
||||
colorFilter: widget.diet.wasLikedByMe ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null,
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
widget.diet.totalLikes.toString(),
|
||||
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
],
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
InfoBouble(
|
||||
children: [
|
||||
SvgPicture.asset('assets/icons/comment2.svg', width: 13, height: 12),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
widget.diet.totalComments.toString(),
|
||||
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
],
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
s.about_diet,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
DietInfoRow(diet: widget.diet),
|
||||
ExpandableText(
|
||||
text: widget.diet.details,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: AuthorCard(
|
||||
author: widget.diet.author,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
MainBackgroundBouble(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
s.diet_plan + '(${widget.diet.duration.toString()} ' + getDayForm(widget.diet.duration, s) + ')',
|
||||
style: TextStyles.headingXLSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
ListView.builder(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
return _dayOfPlan(widget.diet.dailySchedule[index], index, s);
|
||||
},
|
||||
itemCount: widget.diet.dailySchedule.length,
|
||||
),
|
||||
MainBackgroundBouble(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'0' + ' ' + getCommentForm(widget.diet.totalComments, s),
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
color: appTheme.gray500,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_dayOfPlan(List<List<DailySchedule>> day, int dayNumber, S s) {
|
||||
_choiceChipWidget(int index) {
|
||||
return ChoiceChip(
|
||||
selectedColor: appTheme.blueA400,
|
||||
pressElevation: 0,
|
||||
showCheckmark: false,
|
||||
side: BorderSide.none,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
label: Text((index + 1).toString()),
|
||||
labelStyle: TextStyles.textXSSemibold.copyWith(
|
||||
color: index == widget.selectedIndexes[dayNumber] ? Colors.white : appTheme.gray600,
|
||||
),
|
||||
selected: widget.selectedIndexes[dayNumber] == index,
|
||||
backgroundColor: appTheme.gray100,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
widget.selectedIndexes[dayNumber] = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: MainBackgroundBouble(
|
||||
padding: EdgeInsets.only(
|
||||
top: 16,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.day + ' ' + (dayNumber + 1).toString(),
|
||||
style: TextStyles.headingXLSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: CustomDivider(),
|
||||
),
|
||||
Text(
|
||||
s.meal,
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_choiceChipWidget(0),
|
||||
_choiceChipWidget(1),
|
||||
_choiceChipWidget(2),
|
||||
_choiceChipWidget(3),
|
||||
_choiceChipWidget(4),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber]][index], s),
|
||||
itemCount: day[widget.selectedIndexes[dayNumber]].length,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
CpfcContainer(
|
||||
calories: widget.diet.dailyNutrition[dayNumber].energy,
|
||||
proteins: widget.diet.dailyNutrition[dayNumber].proteins,
|
||||
fats: widget.diet.dailyNutrition[dayNumber].fats,
|
||||
carbohydrates: widget.diet.dailyNutrition[dayNumber].carbohydrates,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_daily(DailySchedule daily, S s) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: MediaQuery.sizeOf(context).width * 0.6,
|
||||
child: Text(
|
||||
daily.name,
|
||||
style: TextStyles.textMMedium.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Text(
|
||||
daily.quantity.toString() + ' ' + getLocalizedMeasurementUnits(s, daily.portion),
|
||||
style: TextStyles.textMSemibold.copyWith(
|
||||
color: appTheme.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
@@ -34,6 +33,14 @@ class _AddMealWidgetState extends State<AddMealWidget> {
|
||||
GlossaryModel? selectedGlossary;
|
||||
final productNameController = TextEditingController();
|
||||
final quantityController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
productNameController.text = widget.productNameControllerText ?? '';
|
||||
quantityController.text = widget.quantityControllerText ?? '';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
@@ -128,6 +135,11 @@ class _AddMealWidgetState extends State<AddMealWidget> {
|
||||
if (widget.portionIndex != null)
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.createDietCubit.removePortion(
|
||||
day: widget.dayIndex,
|
||||
meal: widget.mealIndex,
|
||||
portionIndex: widget.portionIndex!,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
@@ -146,55 +158,7 @@ class _AddMealWidgetState extends State<AddMealWidget> {
|
||||
),
|
||||
if (widget.portionIndex != null) const SizedBox(width: 8),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if (widget.portionIndex == null) {
|
||||
// final glossary = selectedGlossary;
|
||||
// if (glossary != null) {
|
||||
// final measurementUnits = glossary.grInPortion != 0 ? Portion.PCS : Portion.GRAMS ;
|
||||
// final portion = DailySchedule(
|
||||
// quantity: int.parse(quantityController.text),
|
||||
// name: glossary.name,
|
||||
// uniq: glossary.id.toString(),
|
||||
// portion: measurementUnits,
|
||||
// );
|
||||
// widget.createDietCubit.addPortion(
|
||||
// dayIndex: widget.dayIndex,
|
||||
// mealIndex: widget.mealIndex,
|
||||
// portion: portion,
|
||||
// );
|
||||
// }
|
||||
} else {
|
||||
// final portion = DailySchedule(
|
||||
// quantity: int.parse(quantityController.text),
|
||||
// name: glossary.name,
|
||||
// uniq: glossary.id.toString(),
|
||||
// portion: measurementUnits,
|
||||
// );
|
||||
// widget.createDietCubit.updatePortion(
|
||||
// day: widget.dayIndex,
|
||||
// meal: widget.mealIndex,
|
||||
// portionIndex: widget.portionIndex!,
|
||||
// portion: portion,
|
||||
// );
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
if (selectedGlossary == null) {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: GlossaryModerationRequestModalWidget(
|
||||
productName: productNameController.text,
|
||||
diaryCubit: sl<DiaryCubit>(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
onTap: addPortion,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - (widget.portionIndex == null ? 32 : 92),
|
||||
@@ -222,6 +186,101 @@ class _AddMealWidgetState extends State<AddMealWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> addPortion() async {
|
||||
final portionIndex = widget.portionIndex;
|
||||
final measurementUnits = selectedGlossary?.grInPortion == null
|
||||
? Portion.PCS
|
||||
: selectedGlossary?.grInPortion == 0
|
||||
? Portion.GRAMS
|
||||
: Portion.PCS;
|
||||
final glossary = selectedGlossary;
|
||||
if (glossary != null) {
|
||||
final [calories, carbohydrates, proteins, fats] = _getCPFC(glossary, measurementUnits);
|
||||
final portion = DailySchedule(
|
||||
dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates),
|
||||
quantity: int.parse(quantityController.text),
|
||||
name: glossary.name,
|
||||
uniq: '',
|
||||
productNutritionalValueId: glossary.id.toString(),
|
||||
portion: measurementUnits,
|
||||
);
|
||||
if (portionIndex == null) {
|
||||
widget.createDietCubit.addPortion(
|
||||
dayIndex: widget.dayIndex,
|
||||
mealIndex: widget.mealIndex,
|
||||
portion: portion,
|
||||
);
|
||||
} else {
|
||||
widget.createDietCubit.updatePortion(
|
||||
dayIndex: widget.dayIndex,
|
||||
mealIndex: widget.mealIndex,
|
||||
portionIndex: portionIndex,
|
||||
portion: portion,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
final newGlossary = await showModalBottomSheet<GlossaryModel>(
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: GlossaryModerationRequestModalWidget(
|
||||
productName: productNameController.text,
|
||||
diaryCubit: sl<DiaryCubit>(),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (newGlossary != null) {
|
||||
final [calories, carbohydrates, proteins, fats] = _getCPFC(newGlossary, Portion.GRAMS);
|
||||
final portion = DailySchedule(
|
||||
dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates),
|
||||
quantity: int.parse(quantityController.text),
|
||||
name: newGlossary.name,
|
||||
uniq: '',
|
||||
productNutritionalValueId: newGlossary.id.toString(),
|
||||
portion: measurementUnits,
|
||||
);
|
||||
if (portionIndex == null) {
|
||||
widget.createDietCubit.addPortion(
|
||||
dayIndex: widget.dayIndex,
|
||||
mealIndex: widget.mealIndex,
|
||||
portion: portion,
|
||||
);
|
||||
} else {
|
||||
widget.createDietCubit.updatePortion(
|
||||
dayIndex: widget.dayIndex,
|
||||
mealIndex: widget.mealIndex,
|
||||
portion: portion,
|
||||
portionIndex: portionIndex,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<double> _getCPFC(GlossaryModel glossary, Portion measurementUnits) {
|
||||
final double calories;
|
||||
final double carbohydrates;
|
||||
final double proteins;
|
||||
final double fats;
|
||||
if (measurementUnits == Portion.GRAMS) {
|
||||
calories = (glossary.energyOn100Gr * int.parse(quantityController.text) / 100);
|
||||
carbohydrates = (glossary.carbohydratesOn100Gr * int.parse(quantityController.text) / 100);
|
||||
proteins = (glossary.proteinsOn100Gr * int.parse(quantityController.text) / 100);
|
||||
fats = (glossary.fatsOn100Gr * int.parse(quantityController.text) / 100);
|
||||
} else {
|
||||
calories = (glossary.energyOnPortion * int.parse(quantityController.text));
|
||||
carbohydrates = (glossary.carbohydratesOnPortion * int.parse(quantityController.text));
|
||||
proteins = (glossary.proteinsOnPortion * int.parse(quantityController.text));
|
||||
fats = (glossary.fatsOnPortion * int.parse(quantityController.text));
|
||||
}
|
||||
return [calories, carbohydrates, proteins, fats];
|
||||
}
|
||||
|
||||
_divider(BuildContext context) {
|
||||
return Container(
|
||||
height: 0.4,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/cpfc_container.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
@@ -13,10 +14,9 @@ import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
|
||||
class DayWidget extends StatefulWidget {
|
||||
const DayWidget({
|
||||
DayWidget({
|
||||
super.key,
|
||||
required this.index,
|
||||
});
|
||||
@@ -34,175 +34,250 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
return BlocBuilder<CreateDietCubit, CreateDietState>(
|
||||
builder: (context, state) {
|
||||
return MainBackgroundBouble(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: 16,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
s.day + ' ${widget.index + 1}',
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreateDietCubit>().copyDay(widget.index);
|
||||
showInfoToast('${s.day} ${widget.index + 1} ${s.copied}');
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
'assets/icons/copy2.svg',
|
||||
width: 20,
|
||||
height: 24,
|
||||
colorFilter: ColorFilter.mode(appTheme.black, BlendMode.srcIn),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
CustomDivider(),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
s.day + ' ${widget.index + 1}',
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
s.meal,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
Spacer(),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/copy2.svg',
|
||||
width: 20,
|
||||
height: 24,
|
||||
colorFilter: ColorFilter.mode(appTheme.black, BlendMode.srcIn),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
CustomDivider(),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
s.meal,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 0,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 1,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 2,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 2;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 3,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 3;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 4,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 4;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
ListView.builder(
|
||||
itemBuilder: (context, index) {
|
||||
final product = state.dietData.dailySchedule?[widget.index][_selectedMealIndex][index];
|
||||
if (product != null) {
|
||||
return _product(
|
||||
index,
|
||||
product.name,
|
||||
product.quantity,
|
||||
getLocalizedMeasurementUnits(
|
||||
s,
|
||||
product.portion,
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 0,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
widget.index,
|
||||
_selectedMealIndex,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
itemCount: state.dietData.dailySchedule?[widget.index][_selectedMealIndex].length ?? 0,
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
|
||||
decoration: BoxDecoration(color: appTheme.gray50, borderRadius: BorderRadius.all(Radius.circular(12))),
|
||||
child: SvgPicture.asset(
|
||||
'assets/icons/paste2.svg',
|
||||
width: 28,
|
||||
height: 24,
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 1,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 2,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 2;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 3,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 3;
|
||||
});
|
||||
},
|
||||
),
|
||||
Spacer(),
|
||||
ChoiceChipWidget(
|
||||
chipsLabelList: chipsLabelList,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
fontSize: TextStyles.textMMedium.fontSize,
|
||||
fontWeight: TextStyles.textMMedium.fontWeight,
|
||||
index: 4,
|
||||
selectedChipIndex: _selectedMealIndex,
|
||||
onSelected: (selectedValue) {
|
||||
setState(() {
|
||||
_selectedMealIndex = 4;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
_modalBottomSheet(
|
||||
dayIndex: widget.index,
|
||||
mealIndex: _selectedMealIndex,
|
||||
createDietCubit: context.read<CreateDietCubit>(),
|
||||
ListView.separated(
|
||||
separatorBuilder: (context, index) => SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
padding: EdgeInsets.all(0),
|
||||
itemBuilder: (context, index) {
|
||||
final product = state.dietData.dailySchedule?[widget.index][_selectedMealIndex][index];
|
||||
if (product != null) {
|
||||
return _product(
|
||||
index,
|
||||
product.name,
|
||||
product.quantity,
|
||||
getLocalizedMeasurementUnits(
|
||||
s,
|
||||
product.portion,
|
||||
),
|
||||
widget.index,
|
||||
_selectedMealIndex,
|
||||
);
|
||||
},
|
||||
text: s.add,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
}
|
||||
return null;
|
||||
},
|
||||
itemCount: state.dietData.dailySchedule?[widget.index][_selectedMealIndex].length ?? 0,
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreateDietCubit>().pasteCopiedDay(widget.index);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
|
||||
decoration: BoxDecoration(color: appTheme.gray50, borderRadius: BorderRadius.all(Radius.circular(12))),
|
||||
child: SvgPicture.asset(
|
||||
'assets/icons/paste2.svg',
|
||||
width: 28,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
_modalBottomSheet(
|
||||
dayIndex: widget.index,
|
||||
mealIndex: _selectedMealIndex,
|
||||
createDietCubit: context.read<CreateDietCubit>(),
|
||||
);
|
||||
},
|
||||
text: s.add,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
BlocBuilder<CreateDietCubit, CreateDietState>(
|
||||
buildWhen: (previous, current) => previous.dietData.dailySchedule != current.dietData.dailySchedule,
|
||||
builder: (context, state) {
|
||||
if (state.dietData.dailySchedule != null) {
|
||||
final day = state.dietData.dailySchedule?[widget.index];
|
||||
final double calories = day!.fold(
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
element.fold(
|
||||
0,
|
||||
(previousValue, element) => previousValue + (element.dailyNutrition?.energy ?? 0),
|
||||
),
|
||||
);
|
||||
|
||||
final double proteins = day.fold(
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
element.fold(
|
||||
0,
|
||||
(previousValue, element) => previousValue + (element.dailyNutrition?.proteins ?? 0),
|
||||
),
|
||||
);
|
||||
|
||||
final double fats = day.fold(
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
element.fold(
|
||||
0,
|
||||
(previousValue, element) => previousValue + (element.dailyNutrition?.fats ?? 0),
|
||||
),
|
||||
);
|
||||
|
||||
final double carbohydrates = day.fold(
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue +
|
||||
element.fold(
|
||||
0,
|
||||
(previousValue, element) => previousValue + (element.dailyNutrition?.carbohydrates ?? 0),
|
||||
),
|
||||
);
|
||||
return CpfcContainer(
|
||||
calories: calories,
|
||||
proteins: proteins,
|
||||
fats: fats,
|
||||
carbohydrates: carbohydrates,
|
||||
);
|
||||
}
|
||||
return CpfcContainer(
|
||||
calories: 0,
|
||||
proteins: 0,
|
||||
fats: 0,
|
||||
carbohydrates: 0,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -210,24 +285,26 @@ class _DayWidgetState extends State<DayWidget> {
|
||||
}
|
||||
|
||||
_product(int index, String product, int quantity, String portion, int dayIndex, int mealIndex) {
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
_modalBottomSheet(
|
||||
mealIndex: mealIndex,
|
||||
dayIndex: dayIndex,
|
||||
createDietCubit: context.read<CreateDietCubit>(),
|
||||
portionIndex: index,
|
||||
productNameControllerText: product,
|
||||
quantityControllerText: quantity.toString(),
|
||||
);
|
||||
},
|
||||
trailing: Icon(Icons.more_vert_rounded),
|
||||
title: Text(product),
|
||||
subtitle: Text('$quantity $portion'),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
return Material(
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
_modalBottomSheet(
|
||||
mealIndex: mealIndex,
|
||||
dayIndex: dayIndex,
|
||||
createDietCubit: context.read<CreateDietCubit>(),
|
||||
portionIndex: index,
|
||||
productNameControllerText: product,
|
||||
quantityControllerText: quantity.toString(),
|
||||
);
|
||||
},
|
||||
trailing: Icon(Icons.more_vert_rounded),
|
||||
title: Text(product),
|
||||
subtitle: Text('$quantity $portion'),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
tileColor: appTheme.gray50,
|
||||
),
|
||||
tileColor: Color(0xFFF6FAFF),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DurationDropDownWidget extends StatefulWidget {
|
||||
const DurationDropDownWidget({super.key});
|
||||
class DietDurationDropDownWidget extends StatefulWidget {
|
||||
const DietDurationDropDownWidget({super.key});
|
||||
|
||||
@override
|
||||
State<DurationDropDownWidget> createState() => _DurationDropDownWidgetState();
|
||||
State<DietDurationDropDownWidget> createState() => _DietDurationDropDownWidgetState();
|
||||
}
|
||||
|
||||
class _DurationDropDownWidgetState extends State<DurationDropDownWidget> {
|
||||
class _DietDurationDropDownWidgetState extends State<DietDurationDropDownWidget> {
|
||||
final List<String> durationDropDownTitles = [];
|
||||
|
||||
@override
|
||||
@@ -38,9 +38,9 @@ class _DurationDropDownWidgetState extends State<DurationDropDownWidget> {
|
||||
builder: (context, state) {
|
||||
return CustomDropDownButton(
|
||||
hint: Text(
|
||||
s.choose_diet_duration,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
s.choose_diet_duration,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
context.read<CreateDietCubit>().setDuration(durationDropDownTitles.indexOf(value));
|
||||
@@ -12,14 +12,14 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class ImagePickerWidget extends StatefulWidget {
|
||||
const ImagePickerWidget({super.key});
|
||||
class DietImagePickerWidget extends StatefulWidget {
|
||||
const DietImagePickerWidget({super.key});
|
||||
|
||||
@override
|
||||
State<ImagePickerWidget> createState() => _ImagePickerWidgetState();
|
||||
State<DietImagePickerWidget> createState() => _DietImagePickerWidgetState();
|
||||
}
|
||||
|
||||
class _ImagePickerWidgetState extends State<ImagePickerWidget> {
|
||||
class _DietImagePickerWidgetState extends State<DietImagePickerWidget> {
|
||||
void _showImagePickerOptions(S s, CreateDietCubit cubit) {
|
||||
showCupertinoModalPopup<void>(
|
||||
context: context,
|
||||
@@ -84,7 +84,30 @@ class _ImagePickerWidgetState extends State<ImagePickerWidget> {
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
padding: state.dietData.image != null ? null : EdgeInsets.all(8),
|
||||
child: state.dietData.image != null
|
||||
? null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(top: 6, right: 6),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CreateDietCubit>().setImage(null);
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.dividerColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.close_rounded,
|
||||
color: Colors.grey,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Stack(
|
||||
children: [
|
||||
DottedBorder(
|
||||
@@ -7,14 +7,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class TypeChoiceWidget extends StatefulWidget {
|
||||
TypeChoiceWidget({super.key});
|
||||
class DietTypeChoiceWidget extends StatefulWidget {
|
||||
DietTypeChoiceWidget({super.key});
|
||||
|
||||
@override
|
||||
State<TypeChoiceWidget> createState() => _TypeChoiceWidgetState();
|
||||
State<DietTypeChoiceWidget> createState() => _DietTypeChoiceWidgetState();
|
||||
}
|
||||
|
||||
class _TypeChoiceWidgetState extends State<TypeChoiceWidget> {
|
||||
class _DietTypeChoiceWidgetState extends State<DietTypeChoiceWidget> {
|
||||
final List<(String, String)> choiceContent = [];
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
@@ -24,7 +24,6 @@ class _StatusDropDownWidgetState extends State<StatusDropDownWidget> {
|
||||
final s = S.of(context);
|
||||
if (dietStateTitles.isEmpty) {
|
||||
dietStateTitles.add(s.active_diet_state);
|
||||
dietStateTitles.add(s.inactive_diet_state);
|
||||
dietStateTitles.add(s.personal_diet_state);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user