forked from eatvio/eatvio_app
fix(diary): added proccesing of future dates and fixed deleted portions
This commit is contained in:
@@ -35,7 +35,6 @@ import 'package:eatvio_app/features/my_finance/presentation/pages/user_finance_s
|
||||
import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart';
|
||||
import 'package:eatvio_app/features/notifications/presentation/pages/notifications_screen.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:eatvio_app/features/plans/presentation/pages/about_plan_screen.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart';
|
||||
@@ -259,15 +258,27 @@ class AppRouter {
|
||||
GoRoute(
|
||||
path: InfoByOrderScreen.path,
|
||||
name: InfoByOrderScreen.name,
|
||||
builder: (context, state) => InfoByOrderScreen(
|
||||
plan: state.extra as ChosenPlanModel,
|
||||
)),
|
||||
builder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
final planId = data['planId'] as int;
|
||||
final successfulPayment = data['successfulPayment'] as bool?;
|
||||
return InfoByOrderScreen(
|
||||
planId: planId,
|
||||
successfulPayment: successfulPayment,
|
||||
);
|
||||
}),
|
||||
GoRoute(
|
||||
path: PaymentScreen.path,
|
||||
name: PaymentScreen.name,
|
||||
builder: (context, state) => PaymentScreen(
|
||||
url: state.extra as String,
|
||||
)),
|
||||
builder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
final planId = data['planId'] as int;
|
||||
final url = data['url'] as String;
|
||||
return PaymentScreen(
|
||||
url: url,
|
||||
planId: planId,
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
String baseUrl = 'https://eatvio.ru';
|
||||
// String baseUrl = 'https://dev2.eatvio.com';
|
||||
// String baseUrl = 'https://eatvio.ru';
|
||||
String baseUrl = 'https://dev2.eatvio.com';
|
||||
|
||||
const List<int> durationValues = [7, 14, 21];
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ import 'package:eatvio_app/features/my_finance/services/cards_service.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_plans/repositories/my_diets_repository.dart';
|
||||
import 'package:eatvio_app/features/my_plans/services/my_plans_service.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
|
||||
import 'package:eatvio_app/features/plans/repositories/plans_repository.dart';
|
||||
import 'package:eatvio_app/features/plans/services/plans_service.dart';
|
||||
import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_cubit.dart';
|
||||
@@ -121,6 +122,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<AuthCubit>(() => AuthCubit(authRepository: sl()));
|
||||
sl.registerFactory<ComplainingCubit>(() => ComplainingCubit(repository: sl()));
|
||||
sl.registerFactory<UserCardsCubit>(() => UserCardsCubit(cardsRepository: sl()));
|
||||
sl.registerFactory<OrderInfoCubit>(() => OrderInfoCubit(chatRepository: sl()));
|
||||
|
||||
// Repository
|
||||
sl.registerLazySingleton<ChatRepository>(() => ChatRepository(chatService: sl()));
|
||||
|
||||
@@ -350,7 +350,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
hintText: 'Сообщение',
|
||||
hintStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, height: 1, color: Color(0xFFAEAEB2)),
|
||||
filled: true,
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: const BorderSide(color: Color(0xFFD1D1D6), width: 1)),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(100), borderSide: const BorderSide(color: Color(0xFFD1D1D6), width: 1)),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
borderSide: const BorderSide(color: Color(0xFFD1D1D6), width: 1),
|
||||
@@ -394,7 +395,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
left: 16,
|
||||
child: AboutOrderButton(
|
||||
onTap: () {
|
||||
GoRouter.of(context).push(InfoByOrderScreen.path, extra: state.chatRoom.chosenPlan);
|
||||
GoRouter.of(context).push(InfoByOrderScreen.path, extra: {'planId': state.chatRoom.chosenPlan?.id});
|
||||
},
|
||||
)),
|
||||
],
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/features/order_info/presentation/info_by_order_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class PaymentScreen extends StatefulWidget {
|
||||
static const name = 'paymentScreen';
|
||||
static const path = '/payment-screen';
|
||||
final String url;
|
||||
const PaymentScreen({super.key, required this.url});
|
||||
final int planId;
|
||||
const PaymentScreen({super.key, required this.url, required this.planId});
|
||||
|
||||
@override
|
||||
State<PaymentScreen> createState() => _PaymentScreenState();
|
||||
@@ -23,13 +24,14 @@ class _PaymentScreenState extends State<PaymentScreen> {
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
onProgress: (int progress) {},
|
||||
onPageStarted: (String url) {},
|
||||
onPageFinished: (String url) {},
|
||||
onHttpError: (HttpResponseError error) {},
|
||||
onWebResourceError: (WebResourceError error) {},
|
||||
onNavigationRequest: (NavigationRequest request) {
|
||||
log(request.url);
|
||||
if (request.url.contains('tbank/checkout-success')) {
|
||||
if (request.url.contains('Success=true')) {
|
||||
GoRouter.of(context).pushReplacement(InfoByOrderScreen.path, extra: {'planId': widget.planId, 'successfulPayment': true});
|
||||
} else {
|
||||
GoRouter.of(context).pushReplacement(InfoByOrderScreen.path, extra: {'planId': widget.planId, 'successfulPayment': false});
|
||||
}
|
||||
}
|
||||
return NavigationDecision.navigate;
|
||||
},
|
||||
),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/pages/payment_screen.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chose_plan_date_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
@@ -9,9 +11,16 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class NotificationBanner extends StatelessWidget {
|
||||
class NotificationBanner extends StatefulWidget {
|
||||
const NotificationBanner({super.key, required this.bannerType});
|
||||
final BannerType bannerType;
|
||||
|
||||
@override
|
||||
State<NotificationBanner> createState() => _NotificationBannerState();
|
||||
}
|
||||
|
||||
class _NotificationBannerState extends State<NotificationBanner> {
|
||||
bool isLoading = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
@@ -28,65 +37,81 @@ class NotificationBanner extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(top: 12, right: 8, left: 12),
|
||||
child: SvgPicture.asset('assets/icons/reversed_exclamation_mark.svg', height: 68, width: 68),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: switch (bannerType) {
|
||||
BannerType.date => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.choose_plan_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final cubit = context.read<ChatRoomCubit>();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ChosePlanDateWidget(
|
||||
chatCubit: cubit,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(s.choose_date, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.card => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.payment => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.tap_on_link_to_pay, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final paymentLink = await context.read<ChatRoomCubit>().getPaymentLink();
|
||||
if (paymentLink != null) {
|
||||
if (!context.mounted) return;
|
||||
GoRouter.of(context).push(PaymentScreen.path, extra: paymentLink);
|
||||
}
|
||||
},
|
||||
child: Text(s.pay, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
},
|
||||
if (isLoading)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 40, top: 24),
|
||||
child: Loader(),
|
||||
)
|
||||
else
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: switch (widget.bannerType) {
|
||||
BannerType.date => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.choose_plan_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final cubit = context.read<ChatRoomCubit>();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ChosePlanDateWidget(
|
||||
chatCubit: cubit,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(s.choose_date, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.card => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
BannerType.payment => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.tap_on_link_to_pay, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final planId = (context.read<ChatRoomCubit>().state as ChatRoomStateLoaded).chatRoom.chosenPlan?.id;
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
final paymentLink = await context.read<ChatRoomCubit>().getPaymentLink();
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
if (paymentLink != null && planId != null) {
|
||||
if (!context.mounted) return;
|
||||
GoRouter.of(context).pushReplacement(
|
||||
PaymentScreen.path,
|
||||
extra: {'url': paymentLink, 'planId': planId},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(s.pay, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -5,14 +5,18 @@ part 'diary_day_model.freezed.dart';
|
||||
part 'diary_day_model.g.dart';
|
||||
|
||||
enum PortionState {
|
||||
active,
|
||||
@JsonValue('filled_diet')
|
||||
filledDiet,
|
||||
@JsonValue('eaten_from_diet')
|
||||
eatenFromDiet,
|
||||
eaten,
|
||||
@JsonValue('eaten_deleted')
|
||||
eatenDeleted,
|
||||
@JsonValue('eaten_edited')
|
||||
eatenEdited,
|
||||
commented,
|
||||
revieweByUser,
|
||||
@JsonValue('reviewed_by_user')
|
||||
reviewedByUser,
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -113,14 +113,13 @@ Map<String, dynamic> _$$PortionModelImplToJson(_$PortionModelImpl instance) =>
|
||||
};
|
||||
|
||||
const _$PortionStateEnumMap = {
|
||||
PortionState.active: 'active',
|
||||
PortionState.filledDiet: 'filledDiet',
|
||||
PortionState.eatenFromDiet: 'eatenFromDiet',
|
||||
PortionState.filledDiet: 'filled_diet',
|
||||
PortionState.eatenFromDiet: 'eaten_from_diet',
|
||||
PortionState.eaten: 'eaten',
|
||||
PortionState.eatenDeleted: 'eatenDeleted',
|
||||
PortionState.eatenEdited: 'eatenEdited',
|
||||
PortionState.eatenDeleted: 'eaten_deleted',
|
||||
PortionState.eatenEdited: 'eaten_edited',
|
||||
PortionState.commented: 'commented',
|
||||
PortionState.revieweByUser: 'revieweByUser',
|
||||
PortionState.reviewedByUser: 'reviewed_by_user',
|
||||
};
|
||||
|
||||
_$TypeOfDiaryModelImpl _$$TypeOfDiaryModelImplFromJson(
|
||||
|
||||
@@ -39,17 +39,19 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
}
|
||||
try {
|
||||
final diaryDay = await diaryRepository.getDiaryByDate('$selectedDay');
|
||||
|
||||
final nutrition = await getNutrition(diaryDay.id);
|
||||
emit(
|
||||
DiaryState.loaded(
|
||||
diary: diaryDay,
|
||||
nutrition: await getNutrition((await diaryRepository.getDiaryByDate('$selectedDay')).id),
|
||||
nutrition: nutrition,
|
||||
selectedDay: selectedDay,
|
||||
selectedMeal: selectedMeal,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
emit(DiaryState.error(errorMessage: e.toString()));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,10 +183,12 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
|
||||
fillSatiety({required int diaryId, required int satiety}) async {
|
||||
await diaryRepository.fillSatiety(diaryId: diaryId, mealId: selectedMeal, satiety: satiety);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
fillMood({required int diaryId, required int mood}) async {
|
||||
await diaryRepository.fillMood(diaryId: diaryId, mealId: selectedMeal, mood: mood);
|
||||
await fetchDiary();
|
||||
}
|
||||
|
||||
fillComment(String comment) {
|
||||
|
||||
@@ -19,5 +19,6 @@ class DiaryState with _$DiaryState {
|
||||
required NutritionDataModel nutrition,
|
||||
required DateTime selectedDay,
|
||||
required int selectedMeal,
|
||||
|
||||
}) = DiaryStateLoaded;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
}
|
||||
if (state is DiaryStateError) {
|
||||
return Scaffold(
|
||||
body: DataErrorWidget(onReload: context.read<DiaryCubit>().fetchDiary()),
|
||||
body: DataErrorWidget(onReload: () => context.read<DiaryCubit>().fetchDiary()),
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
@@ -48,12 +48,15 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
children: [
|
||||
const CalendarWidget(),
|
||||
if (state is DiaryStateLoading) const Loader(),
|
||||
if (state is DiaryStateLoaded) const WakeupAndRetireWidget(),
|
||||
if (state is DiaryStateLoaded) WakeupAndRetireWidget(showRetire: state.diary.typeOfDiary.hasChosenPlan),
|
||||
const SizedBox(height: 12),
|
||||
if (state is DiaryStateLoaded) const MealWidget(),
|
||||
if (state is DiaryStateLoaded)
|
||||
MealWidget(
|
||||
showMood: state.diary.typeOfDiary.hasChosenPlan,
|
||||
),
|
||||
if (state is DiaryStateLoaded) const CaloriesChartWidget(),
|
||||
const SizedBox(height: 12),
|
||||
if (state is DiaryStateLoaded) const CommentForConsultantWidget(),
|
||||
if (state is DiaryStateLoaded && state.diary.typeOfDiary.hasChosenPlan) const CommentForConsultantWidget(),
|
||||
if (state is DiaryStateLoaded && state.diary.closed == 0)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
@@ -19,6 +21,7 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return BlocConsumer<DiaryCubit, DiaryState>(
|
||||
listener: (BuildContext context, DiaryState state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
@@ -48,6 +51,11 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
),
|
||||
onDaySelected: (selectedDay, focusedDay) {
|
||||
if (!isSameDay(_selectedDay, selectedDay)) {
|
||||
final today = DateTime.now();
|
||||
if (selectedDay.isAfter(today)) {
|
||||
showErrorDialog(context, title: s.want_to_see_tomorrow, description: s.can_not_see_next_day);
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_selectedDay = selectedDay;
|
||||
_focusedDay = focusedDay;
|
||||
|
||||
@@ -8,8 +8,8 @@ import 'package:eatvio_app/features/diary/presentation/widgets/time_of_meal_pick
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MealWidget extends StatefulWidget {
|
||||
const MealWidget({super.key});
|
||||
|
||||
const MealWidget({super.key, required this.showMood});
|
||||
final bool showMood;
|
||||
@override
|
||||
State<MealWidget> createState() => _MealWidgetState();
|
||||
}
|
||||
@@ -20,12 +20,12 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
return Material(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Colors.white,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
const Text(
|
||||
'Прием пищи',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
@@ -33,8 +33,8 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
const SizedBox(height: 16),
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MealButtonWidget(mealNumber: 1),
|
||||
@@ -44,18 +44,20 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
MealButtonWidget(mealNumber: 5),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
TimeOfMealPickerWidget(),
|
||||
SizedBox(height: 12),
|
||||
ProductsListWidget(),
|
||||
SizedBox(height: 12),
|
||||
AddProductButtonWidget(),
|
||||
SizedBox(height: 12),
|
||||
PhotoGalleryWidget(),
|
||||
SizedBox(height: 12),
|
||||
SatietyRatingWidget(),
|
||||
SizedBox(height: 12),
|
||||
MoodRatingWidget(),
|
||||
const SizedBox(height: 12),
|
||||
const TimeOfMealPickerWidget(),
|
||||
const SizedBox(height: 12),
|
||||
const ProductsListWidget(),
|
||||
const SizedBox(height: 12),
|
||||
const AddProductButtonWidget(),
|
||||
const SizedBox(height: 12),
|
||||
const PhotoGalleryWidget(),
|
||||
const SizedBox(height: 12),
|
||||
const SatietyRatingWidget(),
|
||||
if (widget.showMood) ...[
|
||||
const SizedBox(height: 12),
|
||||
const MoodRatingWidget(),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -14,17 +14,18 @@ class MoodRatingWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MoodRatingWidgetState extends State<MoodRatingWidget> {
|
||||
late double currentSelectedRating;
|
||||
bool isFirstFetch = true;
|
||||
List<double> currentSelectedRating = [0, 0, 0, 0, 0];
|
||||
List<bool> isFirstFetch = [true, true, true, true, true];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (BuildContext context, DiaryState state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
if (isFirstFetch) {
|
||||
currentSelectedRating = state.diary.meals[state.selectedMeal - 1].mood.toDouble() + 1;
|
||||
isFirstFetch = false;
|
||||
final selectedIndex = state.selectedMeal - 1;
|
||||
if (isFirstFetch[selectedIndex]) {
|
||||
currentSelectedRating[selectedIndex] = state.diary.meals[selectedIndex].mood.toDouble() + 1;
|
||||
isFirstFetch[selectedIndex] = false;
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 24),
|
||||
@@ -46,7 +47,7 @@ class _MoodRatingWidgetState extends State<MoodRatingWidget> {
|
||||
width: 32,
|
||||
),
|
||||
RatingBar.builder(
|
||||
initialRating: state.diary.meals[state.selectedMeal - 1].mood.toDouble() + 1,
|
||||
initialRating: state.diary.meals[selectedIndex].mood.toDouble() + 1,
|
||||
itemCount: 6,
|
||||
itemSize: MediaQuery.of(context).size.width / 6 - (124 / 6),
|
||||
updateOnDrag: true,
|
||||
@@ -56,129 +57,129 @@ class _MoodRatingWidgetState extends State<MoodRatingWidget> {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 1 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 1 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFC82222),
|
||||
border: currentSelectedRating == 1
|
||||
border: currentSelectedRating[selectedIndex] == 1
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFFAA3333),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
width: 2,
|
||||
color: const Color(0xFFAA3333),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 1
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 1
|
||||
? const BorderRadius.horizontal(
|
||||
left: Radius.circular(8),
|
||||
right: Radius.circular(2),
|
||||
)
|
||||
left: Radius.circular(8),
|
||||
right: Radius.circular(2),
|
||||
)
|
||||
: const BorderRadius.horizontal(
|
||||
left: Radius.circular(8),
|
||||
),
|
||||
left: Radius.circular(8),
|
||||
),
|
||||
),
|
||||
);
|
||||
case 1:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 2 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 2 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFF3E3E),
|
||||
border: currentSelectedRating == 2
|
||||
border: currentSelectedRating[selectedIndex] == 2
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF550000),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
width: 2,
|
||||
color: const Color(0xFF550000),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 2 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 2 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 2:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 3 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 3 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF8C926),
|
||||
border: currentSelectedRating == 3
|
||||
border: currentSelectedRating[selectedIndex] == 3
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF8C5D00),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
width: 2,
|
||||
color: const Color(0xFF8C5D00),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 3 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 3 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 3:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 4 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 4 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFFF3BF),
|
||||
border: currentSelectedRating == 4
|
||||
border: currentSelectedRating[selectedIndex] == 4
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFFB5911B),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
width: 2,
|
||||
color: const Color(0xFFB5911B),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 4 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 4 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 4:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 5 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 5 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF62E833),
|
||||
border: currentSelectedRating == 5
|
||||
border: currentSelectedRating[selectedIndex] == 5
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF276918),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
width: 2,
|
||||
color: const Color(0xFF276918),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 5 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 5 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 6 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 6 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF4DCE20),
|
||||
border: currentSelectedRating == 6
|
||||
border: currentSelectedRating[selectedIndex] == 6
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF184D12),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
width: 2,
|
||||
color: const Color(0xFF184D12),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 6
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 6
|
||||
? const BorderRadius.horizontal(
|
||||
left: Radius.circular(2),
|
||||
right: Radius.circular(8),
|
||||
)
|
||||
left: Radius.circular(2),
|
||||
right: Radius.circular(8),
|
||||
)
|
||||
: const BorderRadius.horizontal(
|
||||
right: Radius.circular(8),
|
||||
),
|
||||
right: Radius.circular(8),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
onRatingUpdate: (value) {
|
||||
setState(() {
|
||||
currentSelectedRating = value;
|
||||
currentSelectedRating[selectedIndex] = value;
|
||||
});
|
||||
EasyDebounce.debounce(
|
||||
'change-satiety',
|
||||
const Duration(milliseconds: 250),
|
||||
() {
|
||||
context.read<DiaryCubit>().fillMood(diaryId: state.diary.id, mood: currentSelectedRating.toInt() - 1);
|
||||
() {
|
||||
context.read<DiaryCubit>().fillMood(diaryId: state.diary.id, mood: currentSelectedRating[selectedIndex].toInt() - 1);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -14,17 +14,18 @@ class SatietyRatingWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
late double currentSelectedRating;
|
||||
bool isFirstFetch = true;
|
||||
List<double> currentSelectedRating = [0, 0, 0, 0, 0];
|
||||
List<bool> isFirstFetch = [true, true, true, true, true];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(
|
||||
builder: (BuildContext context, DiaryState state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
if (isFirstFetch) {
|
||||
currentSelectedRating = state.diary.meals[state.selectedMeal - 1].satiety.toDouble() + 1;
|
||||
isFirstFetch = false;
|
||||
final selectedIndex = state.selectedMeal - 1;
|
||||
if (isFirstFetch[selectedIndex]) {
|
||||
currentSelectedRating[selectedIndex] = state.diary.meals[selectedIndex].satiety.toDouble() + 1;
|
||||
isFirstFetch[selectedIndex] = false;
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 24),
|
||||
@@ -46,7 +47,7 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
width: 32,
|
||||
),
|
||||
RatingBar.builder(
|
||||
initialRating: state.diary.meals[state.selectedMeal - 1].satiety.toDouble() + 1,
|
||||
initialRating: state.diary.meals[selectedIndex].satiety.toDouble() + 1,
|
||||
itemCount: 6,
|
||||
itemSize: MediaQuery.of(context).size.width / 6 - (124 / 6),
|
||||
updateOnDrag: true,
|
||||
@@ -56,17 +57,17 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 1 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 1 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFC82222),
|
||||
border: currentSelectedRating == 1
|
||||
border: currentSelectedRating[selectedIndex] == 1
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFFAA3333),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 1
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 1
|
||||
? const BorderRadius.horizontal(
|
||||
left: Radius.circular(8),
|
||||
right: Radius.circular(2),
|
||||
@@ -80,85 +81,85 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 2 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 2 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFF3E3E),
|
||||
border: currentSelectedRating == 2
|
||||
border: currentSelectedRating[selectedIndex] == 2
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF550000),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 2 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 2 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 2:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 3 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 3 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF8C926),
|
||||
border: currentSelectedRating == 3
|
||||
border: currentSelectedRating[selectedIndex] == 3
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF8C5D00),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 3 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 3 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 3:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 4 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 4 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFFF3BF),
|
||||
border: currentSelectedRating == 4
|
||||
border: currentSelectedRating[selectedIndex] == 4
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFFB5911B),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 4 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 4 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
case 4:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 5 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 5 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF62E833),
|
||||
border: currentSelectedRating == 5
|
||||
border: currentSelectedRating[selectedIndex] == 5
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF276918),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 5 ? BorderRadius.circular(2) : null,
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 5 ? BorderRadius.circular(2) : null,
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width / 6,
|
||||
height: 24,
|
||||
margin: currentSelectedRating == 6 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
margin: currentSelectedRating[selectedIndex] == 6 ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF4DCE20),
|
||||
border: currentSelectedRating == 6
|
||||
border: currentSelectedRating[selectedIndex] == 6
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: const Color(0xFF184D12),
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
)
|
||||
: null,
|
||||
borderRadius: currentSelectedRating == 6
|
||||
borderRadius: currentSelectedRating[selectedIndex] == 6
|
||||
? const BorderRadius.horizontal(
|
||||
left: Radius.circular(2),
|
||||
right: Radius.circular(8),
|
||||
@@ -172,13 +173,13 @@ class _SatietyRatingWidgetState extends State<SatietyRatingWidget> {
|
||||
},
|
||||
onRatingUpdate: (value) {
|
||||
setState(() {
|
||||
currentSelectedRating = value;
|
||||
currentSelectedRating[selectedIndex] = value;
|
||||
});
|
||||
EasyDebounce.debounce(
|
||||
'change-satiety',
|
||||
const Duration(milliseconds: 250),
|
||||
() {
|
||||
context.read<DiaryCubit>().fillSatiety(diaryId: state.diary.id, satiety: currentSelectedRating.toInt() - 1);
|
||||
context.read<DiaryCubit>().fillSatiety(diaryId: state.diary.id, satiety: currentSelectedRating[selectedIndex].toInt() - 1);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -8,8 +8,8 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
import '../../../../core/theme/theme_helper.dart';
|
||||
|
||||
class WakeupAndRetireWidget extends StatefulWidget {
|
||||
const WakeupAndRetireWidget({super.key});
|
||||
|
||||
const WakeupAndRetireWidget({super.key, required this.showRetire});
|
||||
final bool showRetire;
|
||||
@override
|
||||
State<WakeupAndRetireWidget> createState() => _WakeupAndRetireWidgetState();
|
||||
}
|
||||
@@ -29,65 +29,62 @@ class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
builder:
|
||||
(context) => SizedBox(
|
||||
height: MediaQuery.of(context).copyWith().size.height / 3,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.time,
|
||||
use24hFormat: true,
|
||||
initialDateTime: DateTime.now(),
|
||||
onDateTimeChanged: (newTime) {
|
||||
if (isWakeup) {
|
||||
wakeup = newTime;
|
||||
} else {
|
||||
retire = newTime;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
if (isWakeup) {
|
||||
diaryCubit.fillWakeup(
|
||||
diaryId: diaryId,
|
||||
time:
|
||||
'${wakeup.hour.toString().padLeft(2, '0')}:${wakeup.minute.toString().padLeft(2, '0')}:00',
|
||||
);
|
||||
} else {
|
||||
diaryCubit.fillRetire(
|
||||
diaryId: diaryId,
|
||||
time:
|
||||
'${retire.hour.toString().padLeft(2, '0')}:${retire.minute.toString().padLeft(2, '0')}:00',
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
builder: (context) => SizedBox(
|
||||
height: MediaQuery.of(context).copyWith().size.height / 3,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.time,
|
||||
use24hFormat: true,
|
||||
initialDateTime: DateTime.now(),
|
||||
onDateTimeChanged: (newTime) {
|
||||
if (isWakeup) {
|
||||
wakeup = newTime;
|
||||
} else {
|
||||
retire = newTime;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
if (isWakeup) {
|
||||
diaryCubit.fillWakeup(
|
||||
diaryId: diaryId,
|
||||
time: '${wakeup.hour.toString().padLeft(2, '0')}:${wakeup.minute.toString().padLeft(2, '0')}:00',
|
||||
);
|
||||
} else {
|
||||
diaryCubit.fillRetire(
|
||||
diaryId: diaryId,
|
||||
time: '${retire.hour.toString().padLeft(2, '0')}:${retire.minute.toString().padLeft(2, '0')}:00',
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -141,9 +138,9 @@ class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.wakeup.toString().substring(
|
||||
0,
|
||||
state.diary.wakeup.toString().length - 3,
|
||||
),
|
||||
0,
|
||||
state.diary.wakeup.toString().length - 3,
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
@@ -158,65 +155,67 @@ class _WakeupAndRetireWidgetState extends State<WakeupAndRetireWidget> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset('assets/icons/retire.svg'),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Уход ко сну',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () => showTimePicker(state.diary.id, false),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Ink(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
color: const Color(0xFFF1F2F6),
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.retire.toString().substring(
|
||||
0,
|
||||
state.diary.retire.toString().length - 3,
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
if (widget.showRetire) ...[
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset('assets/icons/retire.svg'),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Уход ко сну',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
onTap: () => showTimePicker(state.diary.id, false),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Ink(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
color: const Color(0xFFF1F2F6),
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
state.diary.retire.toString().substring(
|
||||
0,
|
||||
state.diary.retire.toString().length - 3,
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
32
lib/features/order_info/cubit/order_info_cubit.dart
Normal file
32
lib/features/order_info/cubit/order_info_cubit.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_state.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class OrderInfoCubit extends Cubit<OrderInfoState> {
|
||||
OrderInfoCubit({required this.chatRepository}) : super(OrderInfoState());
|
||||
final ChatRepository chatRepository;
|
||||
|
||||
Future<String?> getPaymentLink() async {
|
||||
try {
|
||||
final plan = state.chosenPlan;
|
||||
if (plan == null) return null;
|
||||
final paymentModel = await chatRepository.getPaymentLink(id: plan.id);
|
||||
return paymentModel.paymentUrl;
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getChosenPlan(int id) async{
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
emit(state.copyWith(isLoading: false));
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
emit(state.copyWith(isLoading: false));
|
||||
}
|
||||
}
|
||||
}
|
||||
14
lib/features/order_info/cubit/order_info_state.dart
Normal file
14
lib/features/order_info/cubit/order_info_state.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'order_info_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class OrderInfoState with _$OrderInfoState {
|
||||
|
||||
factory OrderInfoState({
|
||||
@Default(false) bool isLoading,
|
||||
@Default(null) ChosenPlanModel? chosenPlan,
|
||||
}) = _OrderInfoState;
|
||||
|
||||
}
|
||||
185
lib/features/order_info/cubit/order_info_state.freezed.dart
Normal file
185
lib/features/order_info/cubit/order_info_state.freezed.dart
Normal file
@@ -0,0 +1,185 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'order_info_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$OrderInfoState {
|
||||
bool get isLoading => throw _privateConstructorUsedError;
|
||||
ChosenPlanModel? get chosenPlan => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of OrderInfoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OrderInfoStateCopyWith<OrderInfoState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $OrderInfoStateCopyWith<$Res> {
|
||||
factory $OrderInfoStateCopyWith(
|
||||
OrderInfoState value, $Res Function(OrderInfoState) then) =
|
||||
_$OrderInfoStateCopyWithImpl<$Res, OrderInfoState>;
|
||||
@useResult
|
||||
$Res call({bool isLoading, ChosenPlanModel? chosenPlan});
|
||||
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$OrderInfoStateCopyWithImpl<$Res, $Val extends OrderInfoState>
|
||||
implements $OrderInfoStateCopyWith<$Res> {
|
||||
_$OrderInfoStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OrderInfoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? isLoading = null,
|
||||
Object? chosenPlan = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
isLoading: null == isLoading
|
||||
? _value.isLoading
|
||||
: isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
chosenPlan: freezed == chosenPlan
|
||||
? _value.chosenPlan
|
||||
: chosenPlan // ignore: cast_nullable_to_non_nullable
|
||||
as ChosenPlanModel?,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of OrderInfoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan {
|
||||
if (_value.chosenPlan == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ChosenPlanModelCopyWith<$Res>(_value.chosenPlan!, (value) {
|
||||
return _then(_value.copyWith(chosenPlan: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$OrderInfoStateImplCopyWith<$Res>
|
||||
implements $OrderInfoStateCopyWith<$Res> {
|
||||
factory _$$OrderInfoStateImplCopyWith(_$OrderInfoStateImpl value,
|
||||
$Res Function(_$OrderInfoStateImpl) then) =
|
||||
__$$OrderInfoStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({bool isLoading, ChosenPlanModel? chosenPlan});
|
||||
|
||||
@override
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$OrderInfoStateImplCopyWithImpl<$Res>
|
||||
extends _$OrderInfoStateCopyWithImpl<$Res, _$OrderInfoStateImpl>
|
||||
implements _$$OrderInfoStateImplCopyWith<$Res> {
|
||||
__$$OrderInfoStateImplCopyWithImpl(
|
||||
_$OrderInfoStateImpl _value, $Res Function(_$OrderInfoStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OrderInfoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? isLoading = null,
|
||||
Object? chosenPlan = freezed,
|
||||
}) {
|
||||
return _then(_$OrderInfoStateImpl(
|
||||
isLoading: null == isLoading
|
||||
? _value.isLoading
|
||||
: isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
chosenPlan: freezed == chosenPlan
|
||||
? _value.chosenPlan
|
||||
: chosenPlan // ignore: cast_nullable_to_non_nullable
|
||||
as ChosenPlanModel?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$OrderInfoStateImpl implements _OrderInfoState {
|
||||
_$OrderInfoStateImpl({this.isLoading = false, this.chosenPlan = null});
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isLoading;
|
||||
@override
|
||||
@JsonKey()
|
||||
final ChosenPlanModel? chosenPlan;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OrderInfoState(isLoading: $isLoading, chosenPlan: $chosenPlan)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$OrderInfoStateImpl &&
|
||||
(identical(other.isLoading, isLoading) ||
|
||||
other.isLoading == isLoading) &&
|
||||
(identical(other.chosenPlan, chosenPlan) ||
|
||||
other.chosenPlan == chosenPlan));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, isLoading, chosenPlan);
|
||||
|
||||
/// Create a copy of OrderInfoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OrderInfoStateImplCopyWith<_$OrderInfoStateImpl> get copyWith =>
|
||||
__$$OrderInfoStateImplCopyWithImpl<_$OrderInfoStateImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _OrderInfoState implements OrderInfoState {
|
||||
factory _OrderInfoState(
|
||||
{final bool isLoading,
|
||||
final ChosenPlanModel? chosenPlan}) = _$OrderInfoStateImpl;
|
||||
|
||||
@override
|
||||
bool get isLoading;
|
||||
@override
|
||||
ChosenPlanModel? get chosenPlan;
|
||||
|
||||
/// Create a copy of OrderInfoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OrderInfoStateImplCopyWith<_$OrderInfoStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,80 +1,172 @@
|
||||
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/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_state.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/payment_banner.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/plan_info.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/plan_props.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/plan_state.dart';
|
||||
import 'package:eatvio_app/features/order_info/presentation/widgets/plan_status_box.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:eatvio_app/core/widgets/option_widget.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class InfoByOrderScreen extends StatefulWidget {
|
||||
class InfoByOrderScreen extends StatelessWidget {
|
||||
static const name = 'infoByOrderScreen';
|
||||
static const path = '/info-by-order-screen';
|
||||
final ChosenPlanModel plan;
|
||||
const InfoByOrderScreen({
|
||||
super.key,
|
||||
required this.plan,
|
||||
});
|
||||
|
||||
const InfoByOrderScreen({super.key, this.successfulPayment, required this.planId});
|
||||
final bool? successfulPayment;
|
||||
final int planId;
|
||||
@override
|
||||
State<InfoByOrderScreen> createState() => _InfoByOrderScreenState();
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => sl<OrderInfoCubit>()..getChosenPlan(planId),
|
||||
child: InfoByOrderScreenContent(
|
||||
successfulPayment: successfulPayment,
|
||||
planId: planId,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _InfoByOrderScreenState extends State<InfoByOrderScreen> {
|
||||
class InfoByOrderScreenContent extends StatefulWidget {
|
||||
static const name = 'infoByOrderScreen';
|
||||
static const path = '/info-by-order-screen';
|
||||
const InfoByOrderScreenContent({
|
||||
super.key,
|
||||
required this.planId,
|
||||
required this.successfulPayment,
|
||||
});
|
||||
final int planId;
|
||||
final bool? successfulPayment;
|
||||
@override
|
||||
State<InfoByOrderScreenContent> createState() => _InfoByOrderScreenContentState();
|
||||
}
|
||||
|
||||
class _InfoByOrderScreenContentState extends State<InfoByOrderScreenContent> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
PacketOptions? chosenOption;
|
||||
if (widget.plan.optionType == 'options1') {
|
||||
chosenOption = widget.plan.plan.packet1Options;
|
||||
} else if (widget.plan.optionType == 'options2') {
|
||||
chosenOption = widget.plan.plan.packet2Options;
|
||||
} else {
|
||||
chosenOption = widget.plan.plan.packet3Options;
|
||||
}
|
||||
return Scaffold(
|
||||
backgroundColor: appTheme.gray100,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
s.infoAboutOrder,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
leading: IconButton(icon: const Icon(Icons.arrow_back), onPressed: () {}),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
AuthorCard(
|
||||
author: widget.plan.plan.author,
|
||||
title: s.plan_seller,
|
||||
titleStyle: TextStyles.textSSemibold.copyWith(color: appTheme.gray),
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
|
||||
return BlocBuilder<OrderInfoCubit, OrderInfoState>(
|
||||
builder: (context, state) {
|
||||
final plan = state.chosenPlan;
|
||||
if (state.isLoading) {
|
||||
Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
s.infoAboutOrder,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
PlanProps(planDuration: widget.plan.plan.duration, planPrice: chosenOption?.price.toDouble() ?? 0, planStatus: PlanStatusValues.paymentFailed),
|
||||
const SizedBox(height: 8),
|
||||
PlanInfo(
|
||||
title: widget.plan.plan.name,
|
||||
description: widget.plan.plan.details,
|
||||
imagePath: widget.plan.plan.image,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).pop();
|
||||
}),
|
||||
),
|
||||
body: const Center(
|
||||
child: Loader(),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (plan == null) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
s.infoAboutOrder,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
OptionWidget(
|
||||
option: chosenOption,
|
||||
disableDuration: true,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).pop();
|
||||
}),
|
||||
),
|
||||
body: Center(
|
||||
child: Text(
|
||||
s.sorry_we_did_not_find_the_plan,
|
||||
style: TextStyles.textSSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
PlanState(
|
||||
state: widget.plan.chosenPlanState,
|
||||
),
|
||||
);
|
||||
}
|
||||
PacketOptions? chosenOption;
|
||||
if (plan.optionType == 'options1') {
|
||||
chosenOption = plan.plan.packet1Options;
|
||||
} else if (plan.optionType == 'options2') {
|
||||
chosenOption = plan.plan.packet2Options;
|
||||
} else {
|
||||
chosenOption = plan.plan.packet3Options;
|
||||
}
|
||||
|
||||
PlanStatusValues planStatus;
|
||||
if (widget.successfulPayment == true) {
|
||||
planStatus = PlanStatusValues.paid;
|
||||
} else if (widget.successfulPayment == false) {
|
||||
planStatus = PlanStatusValues.paymentFailed;
|
||||
} else if (plan.chosenPlanState == ChosenPlanStateEnum.statePaid) {
|
||||
planStatus = PlanStatusValues.paid;
|
||||
} else {
|
||||
planStatus = PlanStatusValues.pendingPayment;
|
||||
}
|
||||
return Scaffold(
|
||||
backgroundColor: appTheme.gray100,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
s.infoAboutOrder,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
));
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).pop();
|
||||
}),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
if (widget.successfulPayment != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
PaymentBanner(
|
||||
successfulPayment: widget.successfulPayment ?? false,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
AuthorCard(
|
||||
author: plan.plan.author,
|
||||
title: s.plan_seller,
|
||||
titleStyle: TextStyles.textSSemibold.copyWith(color: appTheme.gray),
|
||||
backgroundColor: appTheme.whiteA700,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
PlanProps(planDuration: plan.plan.duration, planPrice: chosenOption?.price.toDouble() ?? 0, planStatus: planStatus),
|
||||
const SizedBox(height: 8),
|
||||
PlanInfo(
|
||||
title: plan.plan.name,
|
||||
description: plan.plan.details,
|
||||
imagePath: plan.plan.image,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
OptionWidget(
|
||||
option: chosenOption,
|
||||
disableDuration: true,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
PlanState(
|
||||
state: plan.chosenPlanState,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
161
lib/features/order_info/presentation/widgets/payment_banner.dart
Normal file
161
lib/features/order_info/presentation/widgets/payment_banner.dart
Normal file
@@ -0,0 +1,161 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/pages/payment_screen.dart';
|
||||
import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class PaymentBanner extends StatefulWidget {
|
||||
const PaymentBanner({
|
||||
super.key,
|
||||
required this.successfulPayment,
|
||||
});
|
||||
final bool successfulPayment;
|
||||
|
||||
@override
|
||||
State<PaymentBanner> createState() => _PaymentBannerState();
|
||||
}
|
||||
|
||||
class _PaymentBannerState extends State<PaymentBanner> {
|
||||
bool isLoading = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
return MainBackgroundBouble(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Stack(children: [
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.successfulPayment ? appTheme.blueA400 : appTheme.strongRed,
|
||||
borderRadius: const BorderRadius.only(topRight: Radius.circular(20), bottomRight: Radius.circular(20))),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: widget.successfulPayment
|
||||
? [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(
|
||||
s.cunsutation_was_paid_successfully,
|
||||
style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(
|
||||
s.wait_for_start_day,
|
||||
style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
isLoading
|
||||
? const Center(child: Loader())
|
||||
: CustomOutlinedButton(
|
||||
text: s.go_to_diary,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle:
|
||||
ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
GoRouter.of(context).pushReplacement('/diary-screen');
|
||||
},
|
||||
),
|
||||
isLoading
|
||||
? const Center(child: Loader())
|
||||
: CustomOutlinedButton(
|
||||
text: s.back_to_chat,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle:
|
||||
ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () {
|
||||
GoRouter.of(context).pop();
|
||||
},
|
||||
)
|
||||
]
|
||||
: [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(
|
||||
s.smth_went_wrong_payment_failed,
|
||||
style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(
|
||||
s.try_again_2,
|
||||
style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
isLoading
|
||||
? const Center(child: Loader())
|
||||
: CustomOutlinedButton(
|
||||
text: s.pay,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle:
|
||||
ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
|
||||
onPressed: () async {
|
||||
final planId = context.read<OrderInfoCubit>().state.chosenPlan?.id;
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
final paymentLink = await context.read<OrderInfoCubit>().getPaymentLink();
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
if (paymentLink != null && planId != null) {
|
||||
if (!context.mounted) return;
|
||||
GoRouter.of(context).pushReplacement(
|
||||
PaymentScreen.path,
|
||||
extra: {'url': paymentLink, 'planId': planId},
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
])
|
||||
// ? Column(children: [
|
||||
// SizedBox(
|
||||
// width: size.width * 0.6,
|
||||
// child: Text(
|
||||
// s.smth_went_wrong_payment_failed,
|
||||
// style: TextStyles.textLSemibold.copyWith(color: appTheme.black),
|
||||
// ),
|
||||
// ),
|
||||
// ])
|
||||
// : Padding(
|
||||
// padding: const EdgeInsets.only(right: 16),
|
||||
// child: ,
|
||||
// ),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"average_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Средние показатели давления:",
|
||||
),
|
||||
"back_to_chat": MessageLookupByLibrary.simpleMessage("Вернуться в чат"),
|
||||
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
||||
"by_default": MessageLookupByLibrary.simpleMessage("По умолчянию"),
|
||||
"calls_for_bullying": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -71,6 +72,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"can_not_load_data_please_try_again": MessageLookupByLibrary.simpleMessage(
|
||||
"Не удалось загрузить данные. Попробуйте обновить страницу",
|
||||
),
|
||||
"can_not_see_next_day": MessageLookupByLibrary.simpleMessage(
|
||||
"Просмотр последующего дня возможен только при прохождении диеты",
|
||||
),
|
||||
"cancel_diet": MessageLookupByLibrary.simpleMessage("Отменить диету?"),
|
||||
"cancel_order": MessageLookupByLibrary.simpleMessage("Отменить заказ"),
|
||||
"carb_type": MessageLookupByLibrary.simpleMessage("Мучное"),
|
||||
@@ -166,6 +170,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"country": MessageLookupByLibrary.simpleMessage("Страна"),
|
||||
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
|
||||
"cunsutation_was_paid_successfully": MessageLookupByLibrary.simpleMessage(
|
||||
"Поздравляем, консультация успешно оплачена",
|
||||
),
|
||||
"customer_price": MessageLookupByLibrary.simpleMessage(
|
||||
"Цена для покупателя",
|
||||
),
|
||||
@@ -285,6 +292,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"),
|
||||
"gallery": MessageLookupByLibrary.simpleMessage("Галерея"),
|
||||
"general_info": MessageLookupByLibrary.simpleMessage("Общая информация"),
|
||||
"go_to_diary": MessageLookupByLibrary.simpleMessage("Перейти в дневник"),
|
||||
"gr": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"grams": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"has_alergy": MessageLookupByLibrary.simpleMessage("Наличие аллергии"),
|
||||
@@ -508,6 +516,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"slim_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План питания для похудения должен быть разработан с учётом индивидуальных особенностей организма, возраста, пола, уровня физической активности и состояния здоровья. Общие принципы: \n● Снижение калорийности; \n● Сбалансированный рацион; \n● Разнообразие продуктов; \n● Питьевой режим; \n● Ограничение вредных продуктов;",
|
||||
),
|
||||
"smth_went_wrong_payment_failed": MessageLookupByLibrary.simpleMessage(
|
||||
"Что-то пошло не так, оплата не прошла",
|
||||
),
|
||||
"some_error_occurred": MessageLookupByLibrary.simpleMessage(
|
||||
"Упс! Произошла ошибка",
|
||||
),
|
||||
@@ -517,6 +528,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"something_went_wrong": MessageLookupByLibrary.simpleMessage(
|
||||
"Упс! Что-то пошло не так",
|
||||
),
|
||||
"sorry_we_did_not_find_the_plan": MessageLookupByLibrary.simpleMessage(
|
||||
"Извините, план где-то потерялся, мы уже ищем его",
|
||||
),
|
||||
"spam": MessageLookupByLibrary.simpleMessage("Спам"),
|
||||
"spam_description": MessageLookupByLibrary.simpleMessage(
|
||||
"Отправьте жалобу, если Вы заметили рекламу, размещенную в не предназначенном для этого месте.",
|
||||
@@ -557,6 +571,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"to_draft": MessageLookupByLibrary.simpleMessage("В черновик"),
|
||||
"to_order": MessageLookupByLibrary.simpleMessage("Заказать"),
|
||||
"try_again": MessageLookupByLibrary.simpleMessage("Попробовать снова"),
|
||||
"try_again_2": MessageLookupByLibrary.simpleMessage("Попробуйте ещё раз"),
|
||||
"type_here_your_complaint": MessageLookupByLibrary.simpleMessage(
|
||||
"Напишите здесь свою жалобу",
|
||||
),
|
||||
@@ -589,6 +604,12 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"waist": MessageLookupByLibrary.simpleMessage("Талия"),
|
||||
"waist_circumference": MessageLookupByLibrary.simpleMessage("Обхват талии"),
|
||||
"wait_for_start_day": MessageLookupByLibrary.simpleMessage(
|
||||
"Ожидайте начала плана питания",
|
||||
),
|
||||
"want_to_see_tomorrow": MessageLookupByLibrary.simpleMessage(
|
||||
"Хотите заглянуть в завтра?",
|
||||
),
|
||||
"weapon": MessageLookupByLibrary.simpleMessage("Оружие"),
|
||||
"weight": MessageLookupByLibrary.simpleMessage("Вес"),
|
||||
"weight_chart": MessageLookupByLibrary.simpleMessage("График веса"),
|
||||
|
||||
@@ -2754,6 +2754,96 @@ class S {
|
||||
String get done {
|
||||
return Intl.message('Завершен', name: 'done', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Поздравляем, консультация успешно оплачена`
|
||||
String get cunsutation_was_paid_successfully {
|
||||
return Intl.message(
|
||||
'Поздравляем, консультация успешно оплачена',
|
||||
name: 'cunsutation_was_paid_successfully',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Ожидайте начала плана питания`
|
||||
String get wait_for_start_day {
|
||||
return Intl.message(
|
||||
'Ожидайте начала плана питания',
|
||||
name: 'wait_for_start_day',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Перейти в дневник`
|
||||
String get go_to_diary {
|
||||
return Intl.message(
|
||||
'Перейти в дневник',
|
||||
name: 'go_to_diary',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Вернуться в чат`
|
||||
String get back_to_chat {
|
||||
return Intl.message(
|
||||
'Вернуться в чат',
|
||||
name: 'back_to_chat',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Что-то пошло не так, оплата не прошла`
|
||||
String get smth_went_wrong_payment_failed {
|
||||
return Intl.message(
|
||||
'Что-то пошло не так, оплата не прошла',
|
||||
name: 'smth_went_wrong_payment_failed',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Попробуйте ещё раз`
|
||||
String get try_again_2 {
|
||||
return Intl.message(
|
||||
'Попробуйте ещё раз',
|
||||
name: 'try_again_2',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Извините, план где-то потерялся, мы уже ищем его`
|
||||
String get sorry_we_did_not_find_the_plan {
|
||||
return Intl.message(
|
||||
'Извините, план где-то потерялся, мы уже ищем его',
|
||||
name: 'sorry_we_did_not_find_the_plan',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Просмотр последующего дня возможен только при прохождении диеты`
|
||||
String get can_not_see_next_day {
|
||||
return Intl.message(
|
||||
'Просмотр последующего дня возможен только при прохождении диеты',
|
||||
name: 'can_not_see_next_day',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Хотите заглянуть в завтра?`
|
||||
String get want_to_see_tomorrow {
|
||||
return Intl.message(
|
||||
'Хотите заглянуть в завтра?',
|
||||
name: 'want_to_see_tomorrow',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -337,7 +337,16 @@
|
||||
"time_to_complete_plan": "Время выполнения плана",
|
||||
"order_created": "Заказ создан",
|
||||
"startDateHasBeenSet": "Выбрана дата старта",
|
||||
"done": "Завершен"
|
||||
"done": "Завершен",
|
||||
"cunsutation_was_paid_successfully": "Поздравляем, консультация успешно оплачена",
|
||||
"wait_for_start_day": "Ожидайте начала плана питания",
|
||||
"go_to_diary": "Перейти в дневник",
|
||||
"back_to_chat": "Вернуться в чат",
|
||||
"smth_went_wrong_payment_failed": "Что-то пошло не так, оплата не прошла",
|
||||
"try_again_2": "Попробуйте ещё раз",
|
||||
"sorry_we_did_not_find_the_plan": "Извините, план где-то потерялся, мы уже ищем его",
|
||||
"can_not_see_next_day": "Просмотр последующего дня возможен только при прохождении диеты",
|
||||
"want_to_see_tomorrow": "Хотите заглянуть в завтра?"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
name: eatvio_app
|
||||
description: A new Flutter project.
|
||||
version: 1.0.50+5
|
||||
version: 1.0.50+6
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.0
|
||||
sdk: '>=3.3.4 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
||||
Reference in New Issue
Block a user