您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

339 行
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 = DateFormat('yyyy-MM-dd').format(now);
  64. String dateJalali =
  65. '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'; // فرمت کردن تاریخ
  66. return Consumer<MeetingsState>(
  67. builder: (context, value, child) {
  68. return RefreshIndicator(
  69. onRefresh: () async {
  70. await meetingsState.getMeetings();
  71. },
  72. child: CustomScrollView(
  73. physics: AlwaysScrollableScrollPhysics(),
  74. controller: _scrollController,
  75. slivers: <Widget>[
  76. const CustomAppbar(),
  77. SliverToBoxAdapter(
  78. child: TodayWidget(
  79. formattedDate:
  80. setting.userLocalDb.getUser().language == 'en'
  81. ? dateMiladi
  82. : dateJalali),
  83. ),
  84. SliverToBoxAdapter(
  85. child: Padding(
  86. padding:
  87. const EdgeInsets.symmetric(vertical: 30, horizontal: 15),
  88. child: Row(
  89. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  90. crossAxisAlignment: CrossAxisAlignment.center,
  91. children: [
  92. Text(
  93. style: const TextStyle(fontSize: 14),
  94. AppLocalizations.of(context)!.meetings,
  95. ),
  96. IconButtonCustom(
  97. iconColor: value.hasActiveFilters()
  98. ? Colors.white
  99. : config.ui.secendGreen,
  100. backColor: value.hasActiveFilters()
  101. ? config.ui.secendGreen
  102. : Colors.white,
  103. icon: FontAwesomeIcons.sliders,
  104. onTap: () {
  105. showModalBottomSheet(
  106. isScrollControlled: true,
  107. useSafeArea: true,
  108. context: context,
  109. builder: (context) {
  110. return DiologMeetingsFilters();
  111. },
  112. );
  113. },
  114. )
  115. ],
  116. ),
  117. ),
  118. ),
  119. meetingsList(value),
  120. (value.paginationMeetings == Status.ready ||
  121. value.paginationMeetings == Status.empty)
  122. ? const SliverToBoxAdapter()
  123. : const SliverToBoxAdapter(
  124. child: Center(
  125. child: LoadingWidget(
  126. size: 10,
  127. ),
  128. ),
  129. )
  130. ],
  131. ),
  132. );
  133. },
  134. );
  135. }
  136. Widget meetingsList(MeetingsState state) {
  137. switch (state.statusMeetings) {
  138. case Status.ready:
  139. return SliverList.builder(
  140. itemBuilder: (context, index) {
  141. final userRole = setting.userLocalDb.getUser().role;
  142. final items = state.meetingsModel!.data![index];
  143. return Padding(
  144. padding: const EdgeInsets.all(8.0),
  145. child: CustomCardMeeting(
  146. status: items.accepted ?? 0,
  147. titel:
  148. items.subject != null ? items.subject!.subject ?? '' : '',
  149. fromTime: items.azHour ?? '',
  150. toTime: items.taHour ?? "",
  151. location: items.location != null
  152. ? items.location!.address ?? ''
  153. : '',
  154. date: items.dateJalali ?? '',
  155. cardId: items.id ?? 0,
  156. onSelectedMoreButton: (value) async {
  157. switch (value) {
  158. case 'edit':
  159. await context.pushNamed('meetingedit',
  160. pathParameters: {'id': items.id.toString()});
  161. meetingsState.getMeetings();
  162. case 'confirm':
  163. acceptMeeting(state, context, items.id ?? -1);
  164. case 'cancel':
  165. cancelMeeting(state, context, items.id ?? -1);
  166. case 'report':
  167. if (userRole == 1 && items.description != null) {
  168. await context.pushNamed(
  169. 'meetinsammary',
  170. extra: items, // `items` should be a Datum instance
  171. );
  172. await meetingsState.getMeetings();
  173. } else if (userRole == 1 && items.description == null) {
  174. Tools.showCustomSnackBar(
  175. text:
  176. AppLocalizations.of(context)!.thereisnosummary,
  177. isError: true,
  178. context,
  179. );
  180. } else {
  181. await context.pushNamed(
  182. 'meetinsammary',
  183. extra: items, // `items` should be a Datum instance
  184. );
  185. await meetingsState.getMeetings();
  186. }
  187. default:
  188. }
  189. },
  190. itemBuilderMoreButton: (context) => [
  191. if (userRole == 0 || userRole == 2)
  192. PopupMenuItem(
  193. value: 'edit',
  194. child: Row(
  195. children: [
  196. Icon(
  197. Icons.edit,
  198. color: Colors.green,
  199. size: 17,
  200. ),
  201. SizedBox(width: 8),
  202. Text(
  203. AppLocalizations.of(context)!.editmeeting,
  204. style: TextStyle(fontSize: 12),
  205. ),
  206. ],
  207. ),
  208. ),
  209. if ((userRole == 0 || userRole == 2) &&
  210. items.accepted == 0)
  211. PopupMenuItem(
  212. enabled:
  213. state.statusAcceptMeeting != Status.loading,
  214. value: 'confirm',
  215. child: Row(
  216. children: [
  217. Icon(
  218. Icons.check_circle,
  219. color: Colors.green,
  220. size: 17,
  221. ),
  222. SizedBox(width: 8),
  223. Text(
  224. AppLocalizations.of(context)!.acceptmeeting,
  225. style: TextStyle(fontSize: 12),
  226. ),
  227. ],
  228. ),
  229. ),
  230. if ((userRole == 0 || userRole == 2) &&
  231. items.accepted == 0)
  232. PopupMenuItem(
  233. enabled:
  234. state.statusCancelMeeting != Status.loading,
  235. value: 'cancel',
  236. child: Row(
  237. children: [
  238. Icon(
  239. Icons.cancel,
  240. color: Colors.green,
  241. size: 17,
  242. ),
  243. SizedBox(width: 8),
  244. Text(
  245. AppLocalizations.of(context)!.cancelmeeting,
  246. style: TextStyle(fontSize: 12),
  247. ),
  248. ],
  249. ),
  250. ),
  251. PopupMenuItem(
  252. value: 'report',
  253. child: Row(
  254. children: [
  255. Icon(
  256. Icons.receipt_long,
  257. color: Colors.green,
  258. size: 17,
  259. ),
  260. SizedBox(width: 8),
  261. Text(
  262. AppLocalizations.of(context)!.meetingsummary,
  263. style: TextStyle(fontSize: 12),
  264. ),
  265. ],
  266. ),
  267. ),
  268. ]),
  269. );
  270. },
  271. itemCount: state.meetingsModel!.data!.length,
  272. );
  273. case Status.loading:
  274. return SliverFillRemaining(child: const LoadingWidget());
  275. case Status.error:
  276. return SliverFillRemaining(
  277. child: CustomErrorWidget(
  278. onPressed: () async {
  279. await state.getMeetings(refresh: true);
  280. },
  281. ),
  282. );
  283. case Status.empty:
  284. return SliverFillRemaining(child: EmptyStateWidget());
  285. default:
  286. return Container();
  287. }
  288. }
  289. void cancelMeeting(
  290. MeetingsState state, BuildContext context, int cardId) async {
  291. final status = await state.cancelMeeting(id: cardId);
  292. if (status == Status.ready) {
  293. Tools.showCustomSnackBar(
  294. text: AppLocalizations.of(context)!.meetingcanceled,
  295. isError: false,
  296. context,
  297. );
  298. await meetingsState.getMeetings();
  299. } else {
  300. Tools.showCustomSnackBar(
  301. text: AppLocalizations.of(context)!.error,
  302. isError: true,
  303. context,
  304. );
  305. }
  306. }
  307. void acceptMeeting(
  308. MeetingsState state, BuildContext context, int cardId) async {
  309. final status = await state.acceptMeeting(id: cardId);
  310. if (status == Status.ready) {
  311. Tools.showCustomSnackBar(
  312. text: AppLocalizations.of(context)!.meetingaccepted,
  313. isError: false,
  314. context,
  315. );
  316. await meetingsState.getMeetings();
  317. } else {
  318. Tools.showCustomSnackBar(
  319. text: AppLocalizations.of(context)!.error,
  320. isError: true,
  321. context,
  322. );
  323. }
  324. }
  325. }