Sonnat Project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
9.8 KiB

1 year ago
1 year ago
1 year ago
10 months ago
1 year ago
11 months ago
11 months ago
1 year ago
10 months ago
11 months ago
1 year ago
11 months ago
1 year ago
1 year ago
11 months ago
10 months ago
1 year ago
11 months ago
11 months ago
11 months ago
1 year ago
10 months ago
11 months ago
1 year ago
11 months ago
1 year ago
1 year ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
1 year ago
1 year ago
1 year ago
11 months ago
1 year ago
11 months ago
1 year ago
11 months ago
1 year ago
10 months ago
1 year ago
1 year ago
10 months ago
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_bloc/flutter_bloc.dart';
  3. import 'package:flutter_svg/flutter_svg.dart';
  4. import 'package:sonnat/core/extensions/context_extension.dart';
  5. import 'package:sonnat/core/extensions/string_extension.dart';
  6. import 'package:sonnat/core/html/html_viewer.dart';
  7. import 'package:sonnat/core/utils/app_constants.dart';
  8. import 'package:sonnat/core/utils/base_cubit_type.dart';
  9. import 'package:sonnat/features/single_post/cubit/single_post_cubit.dart';
  10. import 'package:sonnat/features/single_post/widget/add_comment_widget.dart';
  11. import 'package:sonnat/features/single_post/widget/author_comment_widget.dart';
  12. import 'package:sonnat/features/single_post/widget/post_comment_widget.dart';
  13. class SinglePostScreen extends StatefulWidget {
  14. final int postId;
  15. const SinglePostScreen({super.key, required this.postId});
  16. @override
  17. State<SinglePostScreen> createState() => _SinglePostScreenState();
  18. }
  19. class _SinglePostScreenState extends State<SinglePostScreen> {
  20. late final SinglePostCubit _cubit;
  21. final TextEditingController _fullNameController = TextEditingController();
  22. bool _loading = true;
  23. @override
  24. void initState() {
  25. _cubit = BlocProvider.of<SinglePostCubit>(context);
  26. _cubit.getSinglePostData(postId: widget.postId);
  27. super.initState();
  28. }
  29. @override
  30. Widget build(BuildContext context) {
  31. return Scaffold(
  32. body: SafeArea(
  33. child: BlocBuilder<SinglePostCubit, BaseCubitType<SinglePostState>>(
  34. builder: (context, state) {
  35. switch (state.eventName!) {
  36. case SinglePostState.empty:
  37. break;
  38. case SinglePostState.data:
  39. _loading = false;
  40. _fullNameController.text = '';
  41. _cubit.empty();
  42. break;
  43. case SinglePostState.loading:
  44. _loading = true;
  45. break;
  46. case SinglePostState.error:
  47. _loading = false;
  48. break;
  49. }
  50. if (_loading) {
  51. return const Center(child: CircularProgressIndicator());
  52. }
  53. if (_cubit.model == null) {
  54. return const Center(child: Text('خطا در دریافت اطلاعات'));
  55. }
  56. String? thumbnail = _cubit.model!.thumbnail;
  57. return SingleChildScrollView(
  58. child: Column(
  59. children: [
  60. SizedBox(
  61. height: 304,
  62. child: Stack(
  63. fit: StackFit.expand,
  64. children: [
  65. thumbnail == null
  66. ? Center(
  67. child: Icon(
  68. Icons.image_search,
  69. color: Colors.grey.withOpacity(0.5),
  70. size: 150,
  71. ),
  72. )
  73. : Image.network(
  74. thumbnail,
  75. fit: BoxFit.cover,
  76. errorBuilder: (context, error, stackTrace) {
  77. return Center(
  78. child: Icon(
  79. Icons.image_search,
  80. color: Colors.grey.withOpacity(0.5),
  81. size: 150,
  82. ),
  83. );
  84. },
  85. ),
  86. PositionedDirectional(
  87. end: 16,
  88. top: 16,
  89. child: GestureDetector(
  90. onTap: () {
  91. Navigator.pop(context);
  92. },
  93. child: const Icon(
  94. Icons.arrow_forward_rounded,
  95. color: Colors.white,
  96. ),
  97. ),
  98. ),
  99. Positioned(
  100. bottom: 0,
  101. left: 0,
  102. right: 0,
  103. child: Container(
  104. height: 150,
  105. width: 1,
  106. decoration: BoxDecoration(
  107. gradient: LinearGradient(
  108. begin: Alignment.bottomCenter,
  109. end: Alignment.topCenter,
  110. colors: [
  111. Colors.black.withOpacity(0.7),
  112. Colors.black.withOpacity(0),
  113. ],
  114. ),
  115. ),
  116. ),
  117. ),
  118. Padding(
  119. padding: EdgeInsetsDirectional.only(
  120. start: context.width * 26 / AppConstants.instance.appWidth,
  121. end: context.width * 37 / AppConstants.instance.appWidth,
  122. bottom: 18,
  123. ),
  124. child: Align(
  125. alignment: Alignment.bottomCenter,
  126. child: Row(
  127. children: [
  128. Padding(
  129. padding: const EdgeInsets.all(8),
  130. child: SvgPicture.asset('ic_share'.svgPath),
  131. ),
  132. const Spacer(),
  133. Text(
  134. _cubit.model!.commentCount.toString(),
  135. style: const TextStyle(
  136. color: Colors.white,
  137. fontSize: 17,
  138. ),
  139. ),
  140. Padding(
  141. padding: const EdgeInsets.all(8),
  142. child: SvgPicture.asset('ic_comment'.svgPath),
  143. ),
  144. const SizedBox(width: 21),
  145. Text(
  146. _cubit.model!.viewCount.toString(),
  147. style: const TextStyle(
  148. color: Colors.white,
  149. fontSize: 17,
  150. ),
  151. ),
  152. Padding(
  153. padding: const EdgeInsets.all(8),
  154. child: SvgPicture.asset('ic_view'.svgPath),
  155. ),
  156. ],
  157. ),
  158. ),
  159. ),
  160. const Padding(
  161. padding: EdgeInsets.all(8),
  162. child: Align(
  163. alignment: Alignment.bottomCenter,
  164. child: Row(
  165. mainAxisAlignment: MainAxisAlignment.end,
  166. children: [],
  167. ),
  168. ),
  169. ),
  170. ],
  171. ),
  172. ),
  173. Padding(
  174. padding: EdgeInsetsDirectional.only(
  175. start: context.width * 26 / AppConstants.instance.appWidth,
  176. end: context.width * 37 / AppConstants.instance.appWidth,
  177. top: 16,
  178. ),
  179. child: Column(
  180. crossAxisAlignment: CrossAxisAlignment.start,
  181. children: [
  182. Text(
  183. _cubit.model!.title,
  184. style: const TextStyle(
  185. fontWeight: FontWeight.bold,
  186. fontSize: 16,
  187. ),
  188. ),
  189. Text(
  190. _cubit.model!.publishDate,
  191. style: const TextStyle(fontSize: 11),
  192. ),
  193. HTMLViewer(
  194. htmlContent: _cubit.model!.content,
  195. fontSizeFactor: 1,
  196. ),
  197. const SizedBox(height: 30),
  198. Container(
  199. width: context.width,
  200. height: 1,
  201. color: const Color(0xffD3D8E9),
  202. ),
  203. const SizedBox(height: 30),
  204. AuthorCommentWidget(controller: _fullNameController),
  205. const SizedBox(height: 30),
  206. AddCommentWidget(sendComment: _sendComment),
  207. if (_cubit.commentList.isEmpty) const SizedBox(height: 30),
  208. const SizedBox(height: 8),
  209. ListView.builder(
  210. shrinkWrap: true,
  211. physics: const NeverScrollableScrollPhysics(),
  212. itemBuilder: (context, index) {
  213. return PostCommentWidget(comment: _cubit.commentList[index]);
  214. },
  215. itemCount: _cubit.commentList.length,
  216. ),
  217. ],
  218. ),
  219. ),
  220. ],
  221. ),
  222. );
  223. },
  224. ),
  225. ),
  226. );
  227. }
  228. void _sendComment(String comment) {
  229. if (_fullNameController.text.trim().isEmpty) {
  230. return;
  231. }
  232. _cubit.addComment(comment, _fullNameController.text.trim());
  233. }
  234. }