diff --git a/assets/images/img_send.svg b/assets/images/img_send.svg
new file mode 100644
index 0000000..5dedda3
--- /dev/null
+++ b/assets/images/img_send.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/core/utils/image_constant.dart b/lib/core/utils/image_constant.dart
index 8c9c098..07aa9ab 100644
--- a/lib/core/utils/image_constant.dart
+++ b/lib/core/utils/image_constant.dart
@@ -106,6 +106,8 @@ class ImageConstant {
static String imgMic = '$imagePath/img_mic.svg';
+ static String imgSend = '$imagePath/img_send.svg';
+
static String imgAttach = '$imagePath/img_attach.svg';
static String imgExit = '$imagePath/img_nav_exit.svg';
diff --git a/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart b/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart
index 3c13686..c77a0dc 100644
--- a/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart
+++ b/lib/presentation/feed/blog_post_screen/bloc/blog_post_bloc.dart
@@ -1,10 +1,12 @@
import 'dart:async';
+import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart' as http;
+import 'package:intl/intl.dart';
import 'dart:convert';
import '/core/app_export.dart';
import 'package:eatvio_app/presentation/feed/blog_post_screen/models/blog_post_model.dart';
@@ -48,12 +50,10 @@ class BlogPostBloc extends Bloc {
author: currentState.author,
comments: currentState.comments));
} else {
- emit(BlogPostLoadedState(blog_post: data));
- final author = await _fetchAuthor(data['id']);
- emit(BlogPostLoadedState(blog_post: data, author: author));
- final comments = [await _fetchComments(data['id'])];
emit(BlogPostLoadedState(
- blog_post: data, author: author, comments: comments));
+ blog_post: data,
+ author: await _fetchAuthor(data['id']),
+ comments: fillCommentList(await _fetchComments(data['id']))));
}
} else {
// Один или несколько ключевых полей отсутствуют, обрабатываем ошибку
@@ -109,13 +109,11 @@ class BlogPostBloc extends Bloc {
'Authorization': 'Bearer $token',
},
);
- print(response.body);
final data = jsonDecode(response.body);
- print(data);
return data;
}
- _fetchComments(int id) async {
+ Future _fetchComments(int id) async {
final box = await Hive.openBox('token');
final token = box.get('token');
if (token == null) {
@@ -129,9 +127,21 @@ class BlogPostBloc extends Bloc {
'Authorization': 'Bearer $token',
},
);
- print(response.body);
final data = jsonDecode(response.body);
- print(data);
return data;
}
+
+ List fillCommentList(List comments) {
+ List list = [];
+ for (int i = 0; i < comments.length; i++) {
+ list.add(CommentModel(
+ id: comments[i]['id'].toString(),
+ userImage: '',
+ username: 'Вася Пупкин',
+ dateText: DateFormat('dd.MM')
+ .format(DateTime.parse(comments[i]['updated_at'])),
+ greetingText: comments[i]['body']));
+ }
+ return list;
+ }
}
diff --git a/lib/presentation/feed/blog_post_screen/blog_post_screen.dart b/lib/presentation/feed/blog_post_screen/blog_post_screen.dart
index 293dfb2..77cdd64 100644
--- a/lib/presentation/feed/blog_post_screen/blog_post_screen.dart
+++ b/lib/presentation/feed/blog_post_screen/blog_post_screen.dart
@@ -1,8 +1,12 @@
import 'bloc/blog_post_bloc.dart';
import 'models/blog_post_model.dart';
+import 'models/comment_model.dart';
+import 'widgets/comment_widget.dart';
import 'package:eatvio_app/core/app_export.dart';
import 'package:flutter/material.dart';
import 'package:eatvio_app/widgets/custom_bottom_bar.dart';
+import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart';
+import 'package:eatvio_app/widgets/custom_outlined_button.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
@@ -50,98 +54,203 @@ class BlogPostScreen extends StatelessWidget {
decoration: AppDecoration.fillGray,
child: ListView(
children: [
- SizedBox(height: 30.v),
- Container(
- margin: EdgeInsets.only(
- left: 16.h,
- right: 20.h,
- bottom: 10.h,
- ),
- padding: EdgeInsets.all(12.h),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: const BorderRadius.all(Radius.circular(12)),
- boxShadow: [
- BoxShadow(
- color: Colors.grey.withOpacity(0.5),
- spreadRadius: 2,
- blurRadius: 5,
- offset: Offset(0, 3),
- ),
- ],
- ),
- child: Column(mainAxisSize: MainAxisSize.min, children: [
- CachedNetworkImage(
- imageUrl: dotenv.env['STORAGE_URL']! +
- (state.blog_post?['image'] ?? ''),
- imageBuilder: (context, imageProvider) => CircleAvatar(
- backgroundImage: imageProvider,
- radius: 25,
- ),
- placeholder: (context, url) =>
- CircularProgressIndicator(),
- errorWidget: (context, url, error) => CircleAvatar(
- child: Icon(Icons.person),
- backgroundColor: Colors.white,
- radius: 25,
- ),
- ),
- SizedBox(height: 16.0),
- Text(state.blog_post?['title'],
- style: CustomTextStyles.titleMediumBlack),
- SizedBox(height: 8.0),
- Text(
- state.blog_post?['description'],
- ),
- SizedBox(height: 16.0),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- ElevatedButton(
- onPressed: () => Navigator.pushNamed(
- context,
- AppRoutes.blogPostEditScreen,
- arguments: state.blog_post?['id'].toString(),
- ),
- child: Text('Редактировать'),
- ),
- ElevatedButton(
- onPressed: () => context
- .read()
- .add(DeleteEntry(state.blog_post?['id'])),
- child: Text('Удалить'),
- ),
- ],
- )
- ]),
- )
+ SizedBox(height: 15.v),
+ _buildHeaderRow(context, state),
+ SizedBox(height: 15.v),
+ _buildBlogPostData(context, state),
+ SizedBox(height: 15.v),
+ _buildTextField(context, state),
+ SizedBox(height: 15.v),
+ _buildCommentSection(context, state),
],
),
),
bottomNavigationBar: _buildBottomBar(context)));
}
- ///Handling route based on bottom click actions
- String getCurrentRoute(BottomBarEnum type) {
- switch (type) {
- case BottomBarEnum.tf:
- return AppRoutes.blogPostScreen;
- default:
- return "/";
- }
+ _buildHeaderRow(BuildContext context, BlogPostLoadedState state) {
+ final String name = state.author?['name'];
+ return Container(
+ margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h),
+ padding: EdgeInsets.symmetric(
+ horizontal: 24.h,
+ vertical: 12.v,
+ ),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.all(Radius.circular(12)),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.grey.withOpacity(0.5),
+ spreadRadius: 2,
+ blurRadius: 5,
+ offset: Offset(0, 3),
+ ),
+ ],
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomImageView(
+ imagePath: ImageConstant.imgArrowLeft,
+ onTap: () => NavigatorService.goBack()),
+ Padding(
+ padding: EdgeInsets.only(top: 1.v),
+ child: Row(
+ children: [
+ Align(
+ alignment: Alignment.centerRight,
+ child: Text(
+ "$name",
+ style: CustomTextStyles.titleMediumBlack,
+ ),
+ ),
+ CachedNetworkImage(
+ imageUrl: dotenv.env['STORAGE_URL']! +
+ (state.author?['profile_photo_path'] ?? ''),
+ imageBuilder: (context, imageProvider) => CircleAvatar(
+ backgroundImage: imageProvider,
+ radius: 25,
+ ),
+ placeholder: (context, url) => CircularProgressIndicator(),
+ errorWidget: (context, url, error) => CircleAvatar(
+ child: Icon(Icons.person),
+ backgroundColor: Colors.white,
+ radius: 25,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
}
- ///Handling page based on route
- Widget getCurrentPage(
- BuildContext context,
- String currentRoute,
- ) {
- switch (currentRoute) {
- case AppRoutes.blogPostScreen:
- return BlogPostScreen.builder(context);
- default:
- return BlogPostScreen();
- }
+ _buildBlogPostData(BuildContext context, BlogPostLoadedState state) {
+ return Container(
+ margin: EdgeInsets.only(
+ left: 16.h,
+ right: 20.h,
+ bottom: 10.h,
+ ),
+ padding: EdgeInsets.all(12.h),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.all(Radius.circular(12)),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.grey.withOpacity(0.5),
+ spreadRadius: 2,
+ blurRadius: 5,
+ offset: Offset(0, 3),
+ ),
+ ],
+ ),
+ child: Column(mainAxisSize: MainAxisSize.min, children: [
+ CachedNetworkImage(
+ imageUrl:
+ dotenv.env['STORAGE_URL']! + (state.blog_post?['image'] ?? ''),
+ imageBuilder: (context, imageProvider) => ClipRRect(
+ borderRadius: const BorderRadius.all(Radius.circular(8.0)),
+ child: Image(
+ image: imageProvider,
+ ),
+ ),
+ placeholder: (context, url) => CircularProgressIndicator(),
+ ),
+ SizedBox(height: 16.0),
+ Text(state.blog_post?['title'],
+ style: CustomTextStyles.titleMediumBlack),
+ SizedBox(height: 8.0),
+ Text(
+ state.blog_post?['description'],
+ ),
+ SizedBox(height: 16.0),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ ElevatedButton(
+ onPressed: () => Navigator.pushNamed(
+ context,
+ AppRoutes.blogPostEditScreen,
+ arguments: state.blog_post?['id'].toString(),
+ ),
+ child: Text('Редактировать'),
+ ),
+ ElevatedButton(
+ onPressed: () => context
+ .read()
+ .add(DeleteEntry(state.blog_post?['id'])),
+ child: Text('Удалить'),
+ ),
+ ],
+ )
+ ]),
+ );
+ }
+
+ _buildTextField(BuildContext context, BlogPostLoadedState state) {
+ return Container(
+ margin: EdgeInsets.only(
+ left: 16.h,
+ right: 20.h,
+ bottom: 10.h,
+ ),
+ padding: EdgeInsets.all(12.h),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.all(Radius.circular(12)),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.grey.withOpacity(0.5),
+ spreadRadius: 2,
+ blurRadius: 5,
+ offset: Offset(0, 3),
+ ),
+ ],
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Column(
+ children: [
+ CustomTextFormField(
+ maxLines: 8,
+ ),
+ SizedBox(height: 15.h),
+ CustomOutlinedButton(
+ text: "Оставить отзыв",
+ margin: EdgeInsets.only(bottom: 5),
+ buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
+ decoration: BoxDecoration(
+ color: Colors.transparent,
+ ),
+ onPressed: () => print("tap"),
+ // Установите прозрачный фон
+ )
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+
+ _buildCommentSection(BuildContext context, BlogPostLoadedState state) {
+ return ListView.separated(
+ shrinkWrap: true,
+ separatorBuilder: (context, index) {
+ return SizedBox(
+ height: 10.v,
+ );
+ },
+ itemCount: state.comments?.length ?? 0,
+ itemBuilder: (context, index) {
+ CommentModel model = state.comments?[index];
+ return CommentWidget(
+ model,
+ );
+ });
}
_buildBottomBar(BuildContext context) {
diff --git a/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart b/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart
index a005b74..67cbe66 100644
--- a/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart
+++ b/lib/presentation/feed/blog_post_screen/models/blog_post_model.dart
@@ -1,19 +1,20 @@
// ignore_for_file: must_be_immutable
import 'package:equatable/equatable.dart';
-
-/// This class defines the variables used in the [blog_post_screen],
-/// and is typically used to hold data that is passed between different parts of the application.
+import 'package:eatvio_app/presentation/feed/blog_post_screen/models/comment_model.dart';
class BlogPostModel extends Equatable {
final String blog_postID;
+ BlogPostModel({required this.blog_postID, this.comments = const []});
+ List comments;
- BlogPostModel({required String blog_postID}) : blog_postID = blog_postID;
-
- BlogPostModel copyWith(String blog_postID) {
- return BlogPostModel(blog_postID: blog_postID);
+ BlogPostModel copyWith({String? blog_postID, List? comments}) {
+ return BlogPostModel(
+ blog_postID: blog_postID ?? this.blog_postID,
+ comments: comments ?? this.comments,
+ );
}
@override
- List