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.
 
 
 
 
 
 

341 line
13 KiB

  1. // ignore_for_file: public_member_api_docs, sort_constructors_first
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_gen/gen_l10n/app_localizations.dart';
  4. import 'package:font_awesome_flutter/font_awesome_flutter.dart';
  5. import 'package:go_router/go_router.dart';
  6. import 'package:intl/intl.dart';
  7. import 'package:provider/provider.dart';
  8. import 'package:qadirneyriz/config/config.dart';
  9. import 'package:qadirneyriz/screens/meeting/diolog_meetings_filters.dart';
  10. import 'package:qadirneyriz/screens/meeting/state.dart';
  11. import 'package:qadirneyriz/setting/setting.dart';
  12. import 'package:qadirneyriz/utils/enums/status.dart';
  13. import 'package:qadirneyriz/utils/tools/tools.dart';
  14. import 'package:qadirneyriz/widgets/card_meeting.dart';
  15. import 'package:qadirneyriz/widgets/custom_appbar.dart';
  16. import 'package:qadirneyriz/widgets/empty_widget.dart';
  17. import 'package:qadirneyriz/widgets/error_widget.dart';
  18. import 'package:qadirneyriz/widgets/icon_button.dart';
  19. import 'package:qadirneyriz/widgets/loading_widget.dart';
  20. import 'package:qadirneyriz/widgets/today_widget.dart';
  21. class MeetingsScreen extends StatefulWidget {
  22. const MeetingsScreen({super.key});
  23. @override
  24. State<MeetingsScreen> createState() => _MeetingsScreenState();
  25. }
  26. class _MeetingsScreenState extends State<MeetingsScreen> {
  27. late ScrollController _scrollController;
  28. late MeetingsState meetingsState;
  29. @override
  30. void initState() {
  31. _scrollController = ScrollController();
  32. _scrollController.addListener(_scrollListener);
  33. meetingsState = Provider.of<MeetingsState>(context, listen: false);
  34. Future.delayed(Duration.zero, () async {
  35. await meetingsState.getMeetings();
  36. meetingsState.clearFilters();
  37. });
  38. super.initState();
  39. }
  40. @override
  41. void dispose() {
  42. _scrollController.dispose();
  43. super.dispose();
  44. }
  45. _scrollListener() async {
  46. if (_scrollController.offset >=
  47. _scrollController.position.maxScrollExtent &&
  48. !_scrollController.position.outOfRange) {
  49. if (!meetingsState.pageEndedMeetings) {
  50. await meetingsState.nextPageMeetings(
  51. toDate: meetingsState.toDate,
  52. fromDate: meetingsState.fromDate,
  53. location: meetingsState.selectedLocationId,
  54. subject: meetingsState.selectedSubjectId,
  55. meetingManager: meetingsState.selectedManagersId,
  56. meetingStatus: meetingsState.selectedStatusId);
  57. }
  58. }
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. DateTime now = DateTime.now();
  63. String dateMiladi =
  64. Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now));
  65. String dateJalali = Tools.convertToPersianDigits(
  66. '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');
  67. // فرمت کردن تاریخ
  68. return Consumer<MeetingsState>(
  69. builder: (context, value, child) {
  70. return RefreshIndicator(
  71. onRefresh: () async {
  72. await meetingsState.getMeetings();
  73. },
  74. child: CustomScrollView(
  75. physics: AlwaysScrollableScrollPhysics(),
  76. controller: _scrollController,
  77. slivers: <Widget>[
  78. const CustomAppbar(),
  79. SliverToBoxAdapter(
  80. child: TodayWidget(
  81. formattedDate:
  82. setting.userLocalDb.getUser().language == 'en'
  83. ? dateMiladi
  84. : dateJalali),
  85. ),
  86. SliverToBoxAdapter(
  87. child: Padding(
  88. padding:
  89. const EdgeInsets.symmetric(vertical: 30, horizontal: 15),
  90. child: Row(
  91. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  92. crossAxisAlignment: CrossAxisAlignment.center,
  93. children: [
  94. Text(
  95. style: const TextStyle(fontSize: 14),
  96. AppLocalizations.of(context)!.meetings,
  97. ),
  98. IconButtonCustom(
  99. iconColor: value.hasActiveFilters()
  100. ? Colors.white
  101. : config.ui.secendGreen,
  102. backColor: value.hasActiveFilters()
  103. ? config.ui.secendGreen
  104. : Colors.white,
  105. icon: FontAwesomeIcons.sliders,
  106. onTap: () {
  107. showModalBottomSheet(
  108. isScrollControlled: true,
  109. useSafeArea: true,
  110. context: context,
  111. builder: (context) {
  112. return DiologMeetingsFilters();
  113. },
  114. );
  115. },
  116. )
  117. ],
  118. ),
  119. ),
  120. ),
  121. meetingsList(value),
  122. (value.paginationMeetings == Status.ready ||
  123. value.paginationMeetings == Status.empty)
  124. ? const SliverToBoxAdapter()
  125. : const SliverToBoxAdapter(
  126. child: Center(
  127. child: LoadingWidget(
  128. size: 10,
  129. ),
  130. ),
  131. )
  132. ],
  133. ),
  134. );
  135. },
  136. );
  137. }
  138. Widget meetingsList(MeetingsState state) {
  139. switch (state.statusMeetings) {
  140. case Status.ready:
  141. return SliverList.builder(
  142. itemBuilder: (context, index) {
  143. final userRole = setting.userLocalDb.getUser().role;
  144. final items = state.meetingsModel!.data![index];
  145. return Padding(
  146. padding: const EdgeInsets.all(8.0),
  147. child: CustomCardMeeting(
  148. status: items.accepted ?? 0,
  149. titel:
  150. items.subject != null ? items.subject!.subject ?? '' : '',
  151. fromTime: items.azHour ?? '',
  152. toTime: items.taHour ?? "",
  153. location: items.location != null
  154. ? items.location!.address ?? ''
  155. : '',
  156. date: items.dateJalali ?? '',
  157. cardId: items.id ?? 0,
  158. onSelectedMoreButton: (value) async {
  159. switch (value) {
  160. case 'edit':
  161. await context.pushNamed('meetingedit',
  162. pathParameters: {'id': items.id.toString()});
  163. meetingsState.getMeetings();
  164. case 'confirm':
  165. acceptMeeting(state, context, items.id ?? -1);
  166. case 'cancel':
  167. cancelMeeting(state, context, items.id ?? -1);
  168. case 'report':
  169. if (userRole == 1 && items.description != null) {
  170. await context.pushNamed(
  171. 'meetinsammary',
  172. extra: items, // `items` should be a Datum instance
  173. );
  174. await meetingsState.getMeetings();
  175. } else if (userRole == 1 && items.description == null) {
  176. Tools.showCustomSnackBar(
  177. text:
  178. AppLocalizations.of(context)!.thereisnosummary,
  179. isError: true,
  180. context,
  181. );
  182. } else {
  183. await context.pushNamed(
  184. 'meetinsammary',
  185. extra: items, // `items` should be a Datum instance
  186. );
  187. await meetingsState.getMeetings();
  188. }
  189. default:
  190. }
  191. },
  192. itemBuilderMoreButton: (context) => [
  193. if (userRole == 0 || userRole == 2)
  194. PopupMenuItem(
  195. value: 'edit',
  196. child: Row(
  197. children: [
  198. Icon(
  199. Icons.edit,
  200. color: Colors.green,
  201. size: 17,
  202. ),
  203. SizedBox(width: 8),
  204. Text(
  205. AppLocalizations.of(context)!.editmeeting,
  206. style: TextStyle(fontSize: 12),
  207. ),
  208. ],
  209. ),
  210. ),
  211. if ((userRole == 0 || userRole == 2) &&
  212. items.accepted == 0)
  213. PopupMenuItem(
  214. enabled:
  215. state.statusAcceptMeeting != Status.loading,
  216. value: 'confirm',
  217. child: Row(
  218. children: [
  219. Icon(
  220. Icons.check_circle,
  221. color: Colors.green,
  222. size: 17,
  223. ),
  224. SizedBox(width: 8),
  225. Text(
  226. AppLocalizations.of(context)!.acceptmeeting,
  227. style: TextStyle(fontSize: 12),
  228. ),
  229. ],
  230. ),
  231. ),
  232. if ((userRole == 0 || userRole == 2) &&
  233. items.accepted == 0)
  234. PopupMenuItem(
  235. enabled:
  236. state.statusCancelMeeting != Status.loading,
  237. value: 'cancel',
  238. child: Row(
  239. children: [
  240. Icon(
  241. Icons.cancel,
  242. color: Colors.green,
  243. size: 17,
  244. ),
  245. SizedBox(width: 8),
  246. Text(
  247. AppLocalizations.of(context)!.cancelmeeting,
  248. style: TextStyle(fontSize: 12),
  249. ),
  250. ],
  251. ),
  252. ),
  253. PopupMenuItem(
  254. value: 'report',
  255. child: Row(
  256. children: [
  257. Icon(
  258. Icons.receipt_long,
  259. color: Colors.green,
  260. size: 17,
  261. ),
  262. SizedBox(width: 8),
  263. Text(
  264. AppLocalizations.of(context)!.meetingsummary,
  265. style: TextStyle(fontSize: 12),
  266. ),
  267. ],
  268. ),
  269. ),
  270. ]),
  271. );
  272. },
  273. itemCount: state.meetingsModel!.data!.length,
  274. );
  275. case Status.loading:
  276. return SliverFillRemaining(child: const LoadingWidget());
  277. case Status.error:
  278. return SliverFillRemaining(
  279. child: CustomErrorWidget(
  280. onPressed: () async {
  281. await state.getMeetings(refresh: true);
  282. },
  283. ),
  284. );
  285. case Status.empty:
  286. return SliverFillRemaining(child: EmptyStateWidget());
  287. default:
  288. return Container();
  289. }
  290. }
  291. void cancelMeeting(
  292. MeetingsState state, BuildContext context, int cardId) async {
  293. final status = await state.cancelMeeting(id: cardId);
  294. if (status == Status.ready) {
  295. Tools.showCustomSnackBar(
  296. text: AppLocalizations.of(context)!.meetingcanceled,
  297. isError: false,
  298. context,
  299. );
  300. await meetingsState.getMeetings();
  301. } else {
  302. Tools.showCustomSnackBar(
  303. text: AppLocalizations.of(context)!.error,
  304. isError: true,
  305. context,
  306. );
  307. }
  308. }
  309. void acceptMeeting(
  310. MeetingsState state, BuildContext context, int cardId) async {
  311. final status = await state.acceptMeeting(id: cardId);
  312. if (status == Status.ready) {
  313. Tools.showCustomSnackBar(
  314. text: AppLocalizations.of(context)!.meetingaccepted,
  315. isError: false,
  316. context,
  317. );
  318. await meetingsState.getMeetings();
  319. } else {
  320. Tools.showCustomSnackBar(
  321. text: AppLocalizations.of(context)!.error,
  322. isError: true,
  323. context,
  324. );
  325. }
  326. }
  327. }