Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

506 righe
23 KiB

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