import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/feed/models/recipes_model.dart' as step; import 'package:eatvio_app/features/feed/models/recipes_model.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/comments_widget.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:go_router/go_router.dart'; class AboutRecipesScreen extends StatefulWidget { final Recipes recipes; const AboutRecipesScreen({super.key, required this.recipes}); @override State createState() => _AboutRecipesScreenState(); } class _AboutRecipesScreenState extends State { final CommentsCubit commentsCubit = sl(); final textEditingController = TextEditingController(); int? replyId; @override Widget build(BuildContext context) { return BlocProvider( create: (BuildContext context) => commentsCubit ..getComments( widget.recipes.slug, CommentSourceType.recipe, true, ), child: BlocConsumer( listener: (BuildContext context, CommentsState state) { if (state is CommentsStateLoaded) { setState(() { replyId = state.replyId; }); } }, builder: (BuildContext context, CommentsState state) { return Scaffold( 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.withValues(alpha: 0.1), ), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (replyId != null) GestureDetector( onTap: () { context.read().setReplyId(null); setState(() { replyId = null; textEditingController.clear(); }); FocusManager.instance.primaryFocus?.unfocus(); }, child: Container( decoration: BoxDecoration( color: appTheme.blueA400, shape: BoxShape.circle, ), height: 32, width: 32, child: Icon( Icons.close_rounded, size: 18, color: Colors.white, ), ), ), if (replyId != null) SizedBox(width: 8), SizedBox( width: MediaQuery.of(context).size.width - (replyId == null ? 64 : 104), child: TextFormField( onChanged: (_) { setState(() {}); }, controller: textEditingController, maxLines: 5, minLines: 1, keyboardType: TextInputType.multiline, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w400, color: Colors.black, height: 1, ), decoration: InputDecoration( isDense: true, contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), hintText: 'Комментарий', hintStyle: TextStyle( fontSize: 16, fontWeight: FontWeight.w400, height: 1, color: Color(0xFFAEAEB2), ), 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: () { if (textEditingController.text.length > 2) { commentsCubit.sendComment( id: widget.recipes.slug, commentText: textEditingController.text, parentCommentId: replyId, commentSourceType: CommentSourceType.recipe, ); context.read().setReplyId(null); setState(() { textEditingController.clear(); replyId = null; }); FocusManager.instance.primaryFocus?.unfocus(); } }, child: Container( decoration: BoxDecoration( color: textEditingController.text.length > 2 ? appTheme.blueA400 : Colors.grey, shape: BoxShape.circle, ), height: 32, width: 32, child: Icon( Icons.send_rounded, size: 18, color: Colors.white, ), ), ), ], ), ), appBar: AppBar( actions: [ InkWell( borderRadius: BorderRadius.circular(16), onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: widget.recipes.author), child: Ink( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircleAvatar( maxRadius: 16, minRadius: 16, backgroundImage: NetworkImage(widget.recipes.author.authorProfileIcon), ), SizedBox(height: 4), Text( widget.recipes.author.authorName, style: TextStyle( color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400, height: 1, ), ), ], ), ), ), ], ), body: SingleChildScrollView( padding: EdgeInsets.only(bottom: 80), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( widget.recipes.title, style: TextStyle( color: Colors.black, fontSize: 24, fontWeight: FontWeight.w500, height: 1, ), ), ), SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ Icon(Icons.timer_outlined), SizedBox(width: 4), Text( widget.recipes.cookingTime.toString() + ' минут', style: TextStyle( color: Colors.black, fontSize: 12, fontWeight: FontWeight.w400, height: 1, ), ), SizedBox(width: 16), Icon(Icons.fast_forward_outlined), SizedBox(width: 4), Text( widget.recipes.steps.length.toString() + ' этапов', style: TextStyle( color: Colors.black, fontSize: 12, fontWeight: FontWeight.w400, height: 1, ), ), ], ), ), if (widget.recipes.description.isNotEmpty) Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Html( data: widget.recipes.description, style: { "*": Style( color: Colors.black87, ), }, ), ), SizedBox(height: 12), CachedNetworkImage( imageUrl: baseUrl + '/storage/' + widget.recipes.image, ), SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( 'Ингредиенты', style: TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500, height: 1, ), ), ), SizedBox(height: 12), ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _ingredient(widget.recipes.ingredients[index]), separatorBuilder: (context, index) => SizedBox(height: 4), itemCount: widget.recipes.ingredients.length, ), SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( 'Пошаговый рецепт', style: TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500, height: 1, ), ), ), SizedBox(height: 12), ListView.separated( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _step(widget.recipes.steps[index], index + 1), separatorBuilder: (context, index) => Padding( padding: const EdgeInsets.all(16), child: Container( height: 0.4, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(16), ), ), ), itemCount: widget.recipes.steps.length, ), SizedBox(height: 8), Padding( padding: const EdgeInsets.all(16), child: Container( height: 0.4, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(16), ), ), ), SizedBox(height: 8), Container( padding: EdgeInsets.symmetric(horizontal: 16), alignment: Alignment.centerLeft, child: Text( widget.recipes.commentsCount.toString() + ' КОММЕНТАРИЕВ', style: TextStyle( fontSize: 12, color: appTheme.gray500, fontWeight: FontWeight.w400, ), ), ), SizedBox(height: 16), if (state is CommentsStateLoading) Padding( padding: const EdgeInsets.all(32), child: const Loader(), ), if (state is CommentsStateLoaded) CommentsWidget( id: widget.recipes.slug, commentSourceType: CommentSourceType.recipe, comment: state.comment, replyId: replyId, ), ], ), ), ); }, ), ); } _ingredient(Ingredient ingredient) { return Text( '• ' + ingredient.name + ' ' + ingredient.portion + ' ' + (ingredient.unit ?? ''), style: TextStyle( color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400, height: 1.2, ), ); } _step(step.Step step, int stepNumber) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( 'Шаг ' + stepNumber.toString(), style: TextStyle( color: Colors.black54, fontSize: 14, fontWeight: FontWeight.w400, height: 1, ), ), ), SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( step.description, style: TextStyle( color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400, height: 1.2, ), ), ), SizedBox(height: 8), if (step.image.length > 1) Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: CachedNetworkImage(imageUrl: baseUrl + '/storage/' + step.image), ), ), ], ); } }