forked from eatvio/eatvio_app
294 lines
13 KiB
Dart
294 lines
13 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
import 'package:eatvio_app/core/app_config.dart';
|
|
import 'package:eatvio_app/core/enums/product_type.dart';
|
|
import 'package:eatvio_app/core/locator_service.dart';
|
|
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
|
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
|
import 'package:eatvio_app/core/widgets/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/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_svg/svg.dart';
|
|
|
|
class DietPreviewScreen extends StatefulWidget {
|
|
final Diet diet;
|
|
final bool isImageInBase64;
|
|
late final List<int> selectedIndexes;
|
|
static const name = 'createDietScreenPreview';
|
|
static const path = '/create-diet-screen/preview';
|
|
DietPreviewScreen({super.key, required this.diet, required this.isImageInBase64}) {
|
|
selectedIndexes = List.generate(diet.dailySchedule.length, (_) => 0);
|
|
}
|
|
|
|
@override
|
|
State<DietPreviewScreen> createState() => _DietPreviewScreenState();
|
|
}
|
|
|
|
class _DietPreviewScreenState extends State<DietPreviewScreen> {
|
|
final ScrollController scrollController = ScrollController();
|
|
Uint8List? imageData;
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
if (widget.diet.image != null && widget.isImageInBase64) {
|
|
imageData = base64.decode(widget.diet.image!);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
scrollController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final s = S.of(context);
|
|
return Scaffold(
|
|
backgroundColor: appTheme.gray100,
|
|
resizeToAvoidBottomInset: true,
|
|
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: const [],
|
|
),
|
|
body: SingleChildScrollView(
|
|
controller: scrollController,
|
|
padding: const EdgeInsets.only(bottom: 40),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const SizedBox(height: 8),
|
|
MainBackgroundBouble(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
if (imageData != null)
|
|
Stack(
|
|
children: [
|
|
Image.memory(imageData!, height: 300, width: MediaQuery.sizeOf(context).width, fit: BoxFit.fill),
|
|
Positioned(
|
|
bottom: 16,
|
|
left: 0,
|
|
right: 0,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
InfoBouble(
|
|
backgroundColor: appTheme.whiteA700,
|
|
children: [
|
|
SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12),
|
|
const SizedBox(width: 8),
|
|
Text(widget.diet.totalViews.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
|
|
],
|
|
),
|
|
const SizedBox(width: 12),
|
|
GestureDetector(
|
|
onTap: () {},
|
|
child: InfoBouble(
|
|
backgroundColor: appTheme.whiteA700,
|
|
children: [
|
|
SvgPicture.asset(
|
|
'assets/icons/heart.svg',
|
|
width: 14,
|
|
height: 12,
|
|
colorFilter: widget.diet.wasLikedByMe ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(widget.diet.totalLikes.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
)
|
|
else if (!widget.isImageInBase64 && widget.diet.image != null && (widget.diet.image?.isNotEmpty ?? false))
|
|
Stack(
|
|
children: [
|
|
CachedNetworkImage(
|
|
imageUrl: widget.diet.image?.startsWith('https') == true
|
|
? widget.diet.image!
|
|
: '${sl<AppConfig>().baseUrl}/storage/${widget.diet.image}',
|
|
height: 300,
|
|
width: MediaQuery.sizeOf(context).width,
|
|
fit: BoxFit.fill,
|
|
),
|
|
Positioned(
|
|
bottom: 16,
|
|
left: 0,
|
|
right: 0,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
InfoBouble(
|
|
backgroundColor: appTheme.whiteA700,
|
|
children: [
|
|
SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12),
|
|
const SizedBox(width: 8),
|
|
Text(widget.diet.totalViews.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
|
|
],
|
|
),
|
|
const SizedBox(width: 12),
|
|
GestureDetector(
|
|
onTap: () {},
|
|
child: InfoBouble(
|
|
backgroundColor: appTheme.whiteA700,
|
|
children: [
|
|
SvgPicture.asset(
|
|
'assets/icons/heart.svg',
|
|
width: 14,
|
|
height: 12,
|
|
colorFilter: widget.diet.wasLikedByMe ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(widget.diet.totalLikes.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: Text(s.about_diet, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
|
|
),
|
|
const SizedBox(height: 12),
|
|
InfoRow(diet: widget.diet, type: ProductType.diet),
|
|
ExpandableText(text: widget.diet.details),
|
|
const SizedBox(height: 20),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: AuthorCard(author: widget.diet.author, title: s.diet_author),
|
|
),
|
|
const SizedBox(height: 16),
|
|
],
|
|
),
|
|
),
|
|
const 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),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
ListView.builder(
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
shrinkWrap: true,
|
|
itemBuilder: (context, index) {
|
|
return _dayOfPlan(widget.diet.dailySchedule[index + 1] ?? {}, index, s);
|
|
},
|
|
itemCount: widget.diet.dailySchedule.length,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Padding _dayOfPlan(Map<int, Map<int, 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: const 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}', style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)),
|
|
const Padding(padding: 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)],
|
|
),
|
|
const SizedBox(height: 8),
|
|
ListView.builder(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber] + 1]?[index + 1], s),
|
|
itemCount: day[widget.selectedIndexes[dayNumber] + 1]?.length ?? 0,
|
|
),
|
|
const 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,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
SingleChildRenderObjectWidget _daily(DailySchedule? daily, S s) {
|
|
if (daily == null) return const SizedBox.shrink();
|
|
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)),
|
|
),
|
|
const Spacer(),
|
|
Text('${daily.quantity} ${getLocalizedMeasurementUnits(s, daily.portion)}', style: TextStyles.textMSemibold.copyWith(color: appTheme.black)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|