Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

469 linhas
20 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:go_router/go_router.dart';
  5. import 'package:provider/provider.dart';
  6. import 'package:qadirneyriz/global/global_class/selected_item.dart';
  7. import 'package:qadirneyriz/global/global_state/global_state.dart';
  8. import 'package:qadirneyriz/diologs/diolog_add_location.dart';
  9. import 'package:qadirneyriz/diologs/diolog_add_subject.dart';
  10. import 'package:qadirneyriz/diologs/diolog_add_user.dart';
  11. import 'package:qadirneyriz/screens/meeting_edit/state.dart';
  12. import 'package:qadirneyriz/utils/enums/status.dart';
  13. import 'package:qadirneyriz/utils/tools/tools.dart';
  14. import 'package:qadirneyriz/widgets/ExpansionTileCustom.dart';
  15. import 'package:qadirneyriz/widgets/checkBox_inTile.dart';
  16. import 'package:qadirneyriz/widgets/custom_appbar.dart';
  17. import 'package:qadirneyriz/widgets/custom_button.dart';
  18. import 'package:qadirneyriz/widgets/ink_warpper.dart';
  19. import 'package:qadirneyriz/widgets/loading_widget.dart';
  20. import 'package:qadirneyriz/widgets/picker.dart';
  21. class MeetingEditScreen extends StatefulWidget {
  22. final int id;
  23. const MeetingEditScreen({
  24. Key? key,
  25. required this.id,
  26. }) : super(key: key);
  27. @override
  28. State<MeetingEditScreen> createState() => _MeetingEditScreenState();
  29. }
  30. class _MeetingEditScreenState extends State<MeetingEditScreen> {
  31. final _formKey = GlobalKey<FormState>(); // Key for form validation
  32. // all states we have
  33. late MeetingEditState meetingEditState;
  34. late GlobalState globalState;
  35. @override
  36. void initState() {
  37. super.initState();
  38. //set states
  39. meetingEditState = Provider.of<MeetingEditState>(context, listen: false);
  40. globalState = Provider.of<GlobalState>(context, listen: false);
  41. Future.delayed(Duration.zero, () async {
  42. // get items
  43. await meetingEditState.getOneMeeting(id: widget.id);
  44. await globalState.getAllFiltersItems();
  45. // set variables
  46. meetingEditState.setAllVariablesAtStart(id: widget.id);
  47. });
  48. }
  49. @override
  50. Widget build(BuildContext context) {
  51. return Scaffold(
  52. body: Consumer2<MeetingEditState, GlobalState>(
  53. builder: (context, meetingEditState, globalState, child) {
  54. return CustomScrollView(
  55. slivers: <Widget>[
  56. CustomAppbar(title: AppLocalizations.of(context)!.editmeeting),
  57. SliverFillRemaining(
  58. child: content(context, meetingEditState, globalState)),
  59. ],
  60. );
  61. },
  62. ),
  63. );
  64. }
  65. Widget content(BuildContext context, MeetingEditState meetingEditState,
  66. GlobalState globalState) {
  67. if (meetingEditState.oneMeetingStatus[widget.id] == Status.ready &&
  68. globalState.allFiltersStatus == Status.ready) {
  69. final itemInOneMeeting = meetingEditState.oneMeetingModel![widget.id]!;
  70. return Padding(
  71. // This is now wrapped inside SliverToBoxAdapter
  72. padding: const EdgeInsets.all(16.0),
  73. child: Form(
  74. key: _formKey,
  75. child: SingleChildScrollView(
  76. child: Column(
  77. crossAxisAlignment: CrossAxisAlignment.start,
  78. children: [
  79. // subject ExpansionTile
  80. Padding(
  81. padding: const EdgeInsets.symmetric(vertical: 8.0),
  82. child: ExpansionTileCustom(
  83. isForm: true,
  84. subTitile: AppLocalizations.of(context)!.meetingsubject,
  85. title: meetingEditState.selectedSubject.id != null
  86. ? meetingEditState.selectedSubject.text ?? ''
  87. : meetingEditState
  88. .oneMeetingModel![widget.id]!.subject !=
  89. null
  90. ? meetingEditState.oneMeetingModel![widget.id]!
  91. .subject!.subject ??
  92. ''
  93. : '',
  94. widgets: <Widget>[
  95. CheckBoxInTile(
  96. text: AppLocalizations.of(context)!.newsubject,
  97. onTap: () async {
  98. await showDialog(
  99. context: context, // این باید کانتکست فعلی باشد
  100. builder: (BuildContext context) {
  101. return AddSubjectDiolog();
  102. },
  103. );
  104. },
  105. hasIcon: true,
  106. backColor: Colors.white,
  107. textColor: Colors.black.withOpacity(.5),
  108. ),
  109. Column(
  110. children: globalState.subjectsModel!.map((subject) {
  111. bool isSelected =
  112. meetingEditState.selectedSubject.id == subject.id;
  113. return CheckBoxInTile(
  114. backColor:
  115. isSelected ? Color(0xff06CF64) : Colors.white,
  116. textColor: isSelected ? Colors.white : Colors.black,
  117. text: subject.subject ?? '',
  118. hasIcon: false,
  119. onTap: () {
  120. setState(() {
  121. meetingEditState.selectedSubject = ItemSelected(
  122. text: subject.subject ?? '',
  123. id: subject.id ??
  124. 0); // Update selected location
  125. });
  126. },
  127. );
  128. }).toList(),
  129. ),
  130. ],
  131. ),
  132. ),
  133. // Date Picker
  134. Padding(
  135. padding: const EdgeInsets.symmetric(vertical: 8.0),
  136. child: PickerCustom(
  137. showDate: meetingEditState.fromDate != null
  138. ? meetingEditState.fromDate ?? ''
  139. : itemInOneMeeting.dateJalali ?? '',
  140. onTap: () {
  141. showDialog(
  142. context: context,
  143. builder: (context) {
  144. return Dialog(
  145. child: Tools.shamsiDateCalendarWidget(
  146. context,
  147. (newDate) {
  148. String fromDateString =
  149. '${newDate.year}/${newDate.month}/${newDate.day}';
  150. meetingEditState.setFromDate(
  151. fromDateString); // Update the selected date
  152. },
  153. ),
  154. );
  155. },
  156. );
  157. },
  158. isForm: true,
  159. title: AppLocalizations.of(context)!.date,
  160. ),
  161. ),
  162. // From and To time Range Pickers
  163. Padding(
  164. padding: const EdgeInsets.symmetric(vertical: 15.0),
  165. child: Row(
  166. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  167. crossAxisAlignment: CrossAxisAlignment.end,
  168. children: [
  169. PickerCustom(
  170. showDate: meetingEditState.selectedStartTime != null
  171. ? Tools.formatTime(
  172. meetingEditState.selectedStartTime!.hour,
  173. meetingEditState.selectedStartTime!.minute)
  174. : itemInOneMeeting.azHour ?? '',
  175. onTap: () async {
  176. TimeOfDay? picked = await showTimePicker(
  177. context: context,
  178. initialTime: meetingEditState.selectedStartTime!,
  179. );
  180. if (picked != null &&
  181. picked != meetingEditState.selectedStartTime)
  182. setState(() {
  183. meetingEditState.selectedStartTime = picked;
  184. });
  185. },
  186. isForm: true,
  187. icon: Icons.access_time_outlined,
  188. title: AppLocalizations.of(context)!.clock,
  189. ),
  190. Text(AppLocalizations.of(context)!.to),
  191. PickerCustom(
  192. showDate: meetingEditState.selectedEndTime != null
  193. ? Tools.formatTime(
  194. meetingEditState.selectedEndTime!.hour,
  195. meetingEditState.selectedEndTime!.minute)
  196. : itemInOneMeeting.taHour ?? '',
  197. isForm: true,
  198. icon: Icons.access_time_outlined,
  199. onTap: () async {
  200. TimeOfDay? picked = await showTimePicker(
  201. context: context,
  202. initialTime: meetingEditState.selectedEndTime!,
  203. );
  204. if (picked != null &&
  205. picked != meetingEditState.selectedEndTime)
  206. setState(() {
  207. meetingEditState.selectedEndTime = picked;
  208. });
  209. },
  210. ),
  211. ],
  212. ),
  213. ),
  214. // Location ExpansionTile
  215. Padding(
  216. padding: const EdgeInsets.symmetric(vertical: 8.0),
  217. child: ExpansionTileCustom(
  218. isForm: true,
  219. subTitile: AppLocalizations.of(context)!.location,
  220. title: meetingEditState.selectedLocation.id != null
  221. ? meetingEditState.selectedLocation.text ?? ''
  222. : itemInOneMeeting.location != null
  223. ? itemInOneMeeting.location!.address ?? ''
  224. : '',
  225. widgets: <Widget>[
  226. CheckBoxInTile(
  227. text: AppLocalizations.of(context)!.newlocation,
  228. onTap: () async {
  229. await showDialog(
  230. context: context, // این باید کانتکست فعلی باشد
  231. builder: (BuildContext context) {
  232. return AddLocationDiolog();
  233. },
  234. );
  235. },
  236. hasIcon: true,
  237. backColor: Colors.white,
  238. textColor: Colors.black.withOpacity(.5),
  239. ),
  240. Column(
  241. children: globalState.locationsModel!.map((location) {
  242. bool isSelected =
  243. meetingEditState.selectedLocation.id ==
  244. location.id;
  245. return CheckBoxInTile(
  246. backColor:
  247. isSelected ? Color(0xff06CF64) : Colors.white,
  248. textColor: isSelected ? Colors.white : Colors.black,
  249. text: location.address ?? '',
  250. hasIcon: false,
  251. onTap: () {
  252. setState(() {
  253. meetingEditState.selectedLocation =
  254. ItemSelected(
  255. text: location.address,
  256. id: location
  257. .id); // Update selected location
  258. });
  259. },
  260. );
  261. }).toList(),
  262. ),
  263. ],
  264. ),
  265. ),
  266. // Another ExpansionTile for users
  267. Padding(
  268. padding: const EdgeInsets.symmetric(vertical: 8.0),
  269. child: ExpansionTileCustom(
  270. isForm: true,
  271. subTitile: AppLocalizations.of(context)!.users,
  272. title: AppLocalizations.of(context)!.selectusers,
  273. widgets: <Widget>[
  274. CheckBoxInTile(
  275. text: AppLocalizations.of(context)!.newmember,
  276. onTap: () async {
  277. await showDialog(
  278. context: context, // این باید کانتکست فعلی باشد
  279. builder: (BuildContext context) {
  280. return AddUserDiolog();
  281. },
  282. );
  283. },
  284. hasIcon: true,
  285. backColor: Colors.white,
  286. textColor: Colors.black.withOpacity(.5),
  287. ),
  288. Column(
  289. children: globalState.usersModel != null
  290. ? globalState.usersModel!.map((user) {
  291. bool isSelected = meetingEditState
  292. .selectedUsersItems
  293. .contains(user.id);
  294. return Container(
  295. margin: EdgeInsets.symmetric(
  296. vertical: 5.0, horizontal: 10),
  297. decoration: BoxDecoration(
  298. color: isSelected
  299. ? Color(0xff06CF64)
  300. : Colors.white,
  301. borderRadius: BorderRadius.circular(10),
  302. boxShadow: [
  303. BoxShadow(
  304. color: Colors.black12,
  305. blurRadius: 8,
  306. offset: Offset(0, 4),
  307. ),
  308. ],
  309. ),
  310. child: InkWrapper(
  311. onTap: () {
  312. setState(() {
  313. if (isSelected) {
  314. meetingEditState.selectedUsersItems
  315. .remove(user.id);
  316. } else {
  317. meetingEditState.selectedUsersItems
  318. .add(user.id ?? 0);
  319. }
  320. });
  321. },
  322. child: Padding(
  323. padding: const EdgeInsets.all(10.0),
  324. child: Row(
  325. children: [
  326. Text(
  327. maxLines: 1,
  328. overflow: TextOverflow.ellipsis,
  329. user.name ?? '',
  330. style: TextStyle(
  331. fontSize: 12,
  332. color: isSelected
  333. ? Colors.white
  334. : Colors.black,
  335. ),
  336. ),
  337. ],
  338. ),
  339. ),
  340. ),
  341. );
  342. }).toList()
  343. : [],
  344. ),
  345. ],
  346. ),
  347. ),
  348. // Final ExpansionTile if required
  349. Padding(
  350. padding: const EdgeInsets.symmetric(vertical: 10.0),
  351. child: ExpansionTileCustom(
  352. isForm: true,
  353. subTitile: AppLocalizations.of(context)!.meetingmanager,
  354. title: meetingEditState.selectedManager.id != null
  355. ? meetingEditState.selectedManager.text ?? ''
  356. : itemInOneMeeting.manager != null
  357. ? itemInOneMeeting.manager!.name ?? ''
  358. : '',
  359. widgets: <Widget>[
  360. Column(
  361. children:
  362. globalState.meetingsManagerModel!.map((manager) {
  363. bool isSelected =
  364. meetingEditState.selectedManager.id == manager.id;
  365. return CheckBoxInTile(
  366. backColor:
  367. isSelected ? Color(0xff06CF64) : Colors.white,
  368. textColor: isSelected ? Colors.white : Colors.black,
  369. text: manager.name ?? '',
  370. hasIcon: false,
  371. onTap: () {
  372. setState(() {
  373. meetingEditState.selectedManager = ItemSelected(
  374. id: manager.id,
  375. text: manager
  376. .name); // Update selected manager
  377. });
  378. },
  379. );
  380. }).toList(),
  381. ),
  382. ],
  383. ),
  384. ),
  385. // Submit Button
  386. SizedBox(
  387. height: 60,
  388. ),
  389. submit(context)
  390. ],
  391. ),
  392. ),
  393. ),
  394. );
  395. } else if (meetingEditState.oneMeetingStatus[widget.id] == Status.loading ||
  396. globalState.allFiltersStatus == Status.loading) {
  397. return const LoadingWidget();
  398. } else {
  399. return Container();
  400. }
  401. }
  402. CustomButton submit(BuildContext context) {
  403. switch (meetingEditState.statusEitMeeting) {
  404. case Status.loading:
  405. return CustomButton(
  406. width: double.infinity,
  407. hieght: 50,
  408. fontSize: 16,
  409. onPressed: null,
  410. text: AppLocalizations.of(context)!.loading);
  411. default:
  412. return CustomButton(
  413. width: double.infinity,
  414. hieght: 50,
  415. fontSize: 16,
  416. onPressed: () async {
  417. final status = await meetingEditState.editMeeting(
  418. id: widget.id,
  419. locationId: meetingEditState.selectedLocation.id ?? -1,
  420. subjectId: meetingEditState.selectedSubject.id ?? -1,
  421. managerId: meetingEditState.selectedManager.id ?? -1,
  422. fromHour: Tools.formatTime(
  423. meetingEditState.selectedStartTime!.hour,
  424. meetingEditState.selectedStartTime!.minute),
  425. toHour: Tools.formatTime(
  426. meetingEditState.selectedEndTime!.hour,
  427. meetingEditState.selectedEndTime!.minute),
  428. dateMeeting: meetingEditState.fromDate ?? '',
  429. members: meetingEditState.selectedUsersItems);
  430. if (status == Status.ready) {
  431. context.pop();
  432. Tools.showCustomSnackBar(
  433. text: AppLocalizations.of(context)!.editdone,
  434. isError: false,
  435. context,
  436. );
  437. } else {
  438. Tools.showCustomSnackBar(
  439. text: meetingEditState.errorsEditMeeting == null
  440. ? meetingEditState.messageEditMeeting ??
  441. AppLocalizations.of(context)!.haserror
  442. : Tools.combineErrorMessages(
  443. meetingEditState.errorsEditMeeting ?? {}),
  444. isError: true,
  445. context,
  446. );
  447. }
  448. },
  449. text: AppLocalizations.of(context)!.submit);
  450. }
  451. }
  452. }