1
0

rosters_page.dart 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. import 'package:collection/collection.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_riverpod/flutter_riverpod.dart';
  4. import 'package:gap/gap.dart';
  5. import 'package:go_router/go_router.dart';
  6. import 'package:hive_flutter/hive_flutter.dart';
  7. import 'package:jiffy/jiffy.dart';
  8. import 'package:super_sliver_list/super_sliver_list.dart';
  9. import 'package:tp5/core/basic_page.dart';
  10. import 'package:tp5/core/utils.dart';
  11. import 'package:tp5/csv/data.dart';
  12. import 'package:linked_scroll_controller/linked_scroll_controller.dart';
  13. import 'package:tp5/fltinfo/view/dutyinfo_page.dart';
  14. import 'package:tp5/fltinfo/view/fltinfo_page.dart';
  15. import 'package:tp5/rosters/rosters_crew_filter.dart';
  16. import 'package:tp5/widgets/my_col.dart';
  17. import 'package:tp5/widgets/my_row.dart';
  18. import 'package:google_fonts/google_fonts.dart';
  19. class RostersPage extends ConsumerStatefulWidget {
  20. const RostersPage({super.key});
  21. @override
  22. ConsumerState<ConsumerStatefulWidget> createState() => _RostersPageState();
  23. }
  24. class _RostersPageState extends ConsumerState<RostersPage> {
  25. final scrollControllerGroup = LinkedScrollControllerGroup();
  26. Map<int, Map<int, ScrollController>> scrollCtrls = {};
  27. final _listControllerV = ListController();
  28. final _listControllerH = ListController();
  29. ScrollController? _getCtrl(int i, {int cat = 0}) {
  30. if (!scrollCtrls.containsKey(cat)) {
  31. // print("rosterspage: getctrl: create cat: $cat");
  32. scrollCtrls.addAll({cat: {}});
  33. }
  34. if (!scrollCtrls[cat]!.containsKey(i)) {
  35. scrollCtrls[cat]![i] = scrollControllerGroup.addAndGet();
  36. // print("rosterspage: getctrl: create index: $i");
  37. }
  38. // scrollControllerGroup.jumpTo(scrollControllerGroup.offset);
  39. return scrollCtrls[cat]![i]!;
  40. }
  41. final bottomnavstyle = ElevatedButton.styleFrom(
  42. shape: RoundedRectangleBorder(
  43. borderRadius: BorderRadius.circular(5.0),
  44. ),
  45. backgroundColor:
  46. const Color.fromARGB(255, 0, 36, 53) //elevated btton background color
  47. );
  48. TextEditingController ctrldep = TextEditingController();
  49. TextEditingController ctrldes = TextEditingController();
  50. TextEditingController ctrlairline = TextEditingController();
  51. TextEditingController ctrlfnum = TextEditingController();
  52. Map<String, String> flightFilter = {
  53. "dep": "",
  54. "des": "",
  55. "al": "",
  56. "fnum": ""
  57. };
  58. void _searchFlights(xcontext) async {
  59. ctrldep.text = flightFilter["dep"] ?? "";
  60. ctrldes.text = flightFilter["des"] ?? "";
  61. ctrlairline.text = flightFilter["al"] ?? "";
  62. ctrlfnum.text = flightFilter["fnum"] ?? "";
  63. final res = await showModalBottomSheet(
  64. context: context, builder: (context) => _flightFilter(xcontext));
  65. if (res is Map<String, String>) {
  66. Hive.box("settings").put("rosters.filter.flights", (res));
  67. setState(() {
  68. flightFilter = res;
  69. });
  70. }
  71. }
  72. Widget _flightFilter(BuildContext context) {
  73. return Container(
  74. padding: const EdgeInsets.all(20),
  75. child: Column(mainAxisSize: MainAxisSize.min, children: [
  76. Row(
  77. children: [
  78. Expanded(
  79. child: TextField(
  80. decoration:
  81. const InputDecoration(labelText: "Departure Airport"),
  82. maxLength: 3, // Set maximum length
  83. controller: ctrldep,
  84. ),
  85. ),
  86. const SizedBox(width: 10),
  87. Expanded(
  88. child: TextField(
  89. decoration:
  90. const InputDecoration(labelText: "Arrival Airport"),
  91. maxLength: 3, // Set maximum length
  92. controller: ctrldes,
  93. ),
  94. ),
  95. ],
  96. ),
  97. const SizedBox(height: 15),
  98. Row(
  99. children: [
  100. Expanded(
  101. child: TextField(
  102. controller: ctrlairline,
  103. decoration:
  104. const InputDecoration(labelText: "Airline IATA code"),
  105. maxLength: 2, // Set maximum length
  106. ),
  107. ),
  108. const SizedBox(width: 10),
  109. Expanded(
  110. child: TextField(
  111. controller: ctrlfnum,
  112. decoration: const InputDecoration(labelText: "Flight number"),
  113. maxLength: 6, // Set maximum length
  114. ),
  115. ),
  116. ],
  117. ),
  118. const SizedBox(height: 15),
  119. const SizedBox(height: 35),
  120. SizedBox(
  121. width: 360,
  122. child: ElevatedButton(
  123. onPressed: () async => Navigator.pop(context, {
  124. "dep": ctrldep.text.toUpperCase(),
  125. "des": ctrldes.text.toUpperCase(),
  126. "al": ctrlairline.text.toUpperCase(),
  127. "fnum": ctrlfnum.text.toUpperCase()
  128. }), // Close the bottom sheet
  129. style: ElevatedButton.styleFrom(
  130. backgroundColor: Colors.green, // Set button color to green
  131. shape: RoundedRectangleBorder(
  132. borderRadius:
  133. BorderRadius.circular(15), // Add rounded corners
  134. ),
  135. padding:
  136. const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
  137. ),
  138. child: const Text(
  139. 'Flight filter',
  140. style: TextStyle(fontSize: 18, color: Colors.white),
  141. ),
  142. ),
  143. ),
  144. ]));
  145. }
  146. Map<String, List<String>> crewFilter = {"college": [], "ac": [], "base": []};
  147. void _searchCrew(xcontext, List<Qualif> qualif) async {
  148. final res = await showModalBottomSheet(
  149. context: context,
  150. builder: (context) =>
  151. RostersCrewFilter(qualif: qualif, crewFilter: crewFilter));
  152. if (res is Map<String, List<String>>) {
  153. Hive.box("settings").put("rosters.filter.crew", (res));
  154. setState(() {
  155. crewFilter = res;
  156. });
  157. }
  158. }
  159. final double rosterswidth = 110;
  160. final double rostersheight = 60;
  161. Widget _duty2line(Pnleg leg, {bool showdatedep = true}) {
  162. // print(
  163. // ">>${leg.label},${leg.type},${leg.dep},${leg.arr},${leg.jdep?.format(pattern: "HHmm")},${leg.jarr?.format(pattern: "HHmm")},");
  164. final whdep = showdatedep
  165. ? Text(
  166. "${leg.jdep?.format(pattern: "HHmm")}",
  167. style: const TextStyle(fontSize: 10, color: Colors.teal),
  168. )
  169. : const Row(children: [
  170. Icon(
  171. Icons.arrow_back_ios_new_outlined,
  172. size: 12,
  173. color: Colors.teal,
  174. ),
  175. Icon(
  176. Icons.arrow_back_ios_new_outlined,
  177. size: 12,
  178. color: Colors.teal,
  179. ),
  180. ]);
  181. final wharr = Text(
  182. "${leg.jarr?.format(pattern: "HHmm")}",
  183. style: const TextStyle(fontSize: 10, color: Colors.teal),
  184. );
  185. if (leg.type == "L" || (leg.type == "F")) {
  186. return InkWell(
  187. onTap: () {
  188. context.push("/fltinfo",
  189. extra: FltinfoParams(
  190. al: leg.al,
  191. fnum: leg.fnum,
  192. dep: leg.dep,
  193. des: leg.arr,
  194. jdep: leg.jdep,
  195. jdes: leg.jarr));
  196. },
  197. child: MyRow(children: [
  198. whdep,
  199. const Gap(3),
  200. Text(
  201. "${leg.dep}-${leg.arr}",
  202. style: GoogleFonts.robotoMono(
  203. fontSize: 11, fontWeight: FontWeight.w300),
  204. ),
  205. const Gap(3),
  206. wharr,
  207. ]),
  208. );
  209. } else if ((leg.type == "G") ||
  210. ((leg.dep ?? "") != "" && (leg.arr ?? "") != "")) {
  211. return InkWell(
  212. onTap: () {
  213. context.push("/dutyinfo",
  214. extra: DutyinfoParams(
  215. dutytype: leg.dutytype,
  216. label: leg.label,
  217. dep: leg.dep,
  218. des: leg.arr,
  219. jdep: leg.jdep,
  220. jdes: leg.jarr));
  221. },
  222. child: MyRow(children: [
  223. whdep,
  224. const Gap(3),
  225. const Text("Limo ",
  226. style: TextStyle(fontSize: 11, color: Colors.amber)),
  227. Text(
  228. "${leg.dep}-${leg.arr}",
  229. style: GoogleFonts.robotoMono(
  230. fontSize: 11, fontWeight: FontWeight.w300),
  231. ),
  232. const Gap(3),
  233. wharr,
  234. ]),
  235. );
  236. }
  237. // else if ((leg.type == "F") ||
  238. // ((leg.dep ?? "") != "" && (leg.arr ?? "") != "")) {
  239. // return MyRow(children: [
  240. // whdep,
  241. // const Gap(3),
  242. // const Text("DH ", style: TextStyle(fontSize: 11, color: Colors.amber)),
  243. // Text(
  244. // "${leg.dep}-${leg.arr}",
  245. // style:
  246. // GoogleFonts.robotoMono(fontSize: 11, fontWeight: FontWeight.w300),
  247. // ),
  248. // const Gap(3),
  249. // wharr,
  250. // ]);
  251. // }
  252. else if ((!["OFF", "CM", "CA", "PP"].contains(leg.label)) &&
  253. (leg.jarr != null &&
  254. leg.jdep != null &&
  255. DTInterval(leg.jdep!, leg.jarr!).duration.inHours < 18)) {
  256. return InkWell(
  257. onTap: () {
  258. context.push("/dutyinfo",
  259. extra: DutyinfoParams(
  260. dutytype: leg.dutytype,
  261. label: leg.label,
  262. dep: leg.dep,
  263. des: leg.arr,
  264. jdep: leg.jdep,
  265. jdes: leg.jarr));
  266. },
  267. child: MyRow(children: [
  268. whdep,
  269. const Gap(3),
  270. Text("${leg.type == "S" ? "SIMU " : ""}${leg.label}",
  271. style: const TextStyle(fontSize: 11, color: Colors.amber)),
  272. Text(
  273. " ${leg.dep}",
  274. style: GoogleFonts.robotoMono(
  275. fontSize: 8, fontWeight: FontWeight.w300),
  276. ),
  277. const Gap(3),
  278. wharr,
  279. ]),
  280. );
  281. } else {
  282. return Text(
  283. leg.label ?? "",
  284. style: TextStyle(
  285. fontSize: 16,
  286. color: Colors.blueGrey[800],
  287. fontWeight: FontWeight.w700,
  288. letterSpacing: 1),
  289. );
  290. }
  291. }
  292. Widget _rostersDay(
  293. {required Jiffy date,
  294. required List<Pnleg> legs,
  295. Color? color,
  296. bool border = false}) {
  297. return Container(
  298. decoration: BoxDecoration(
  299. border: border ? Border.all(color: Colors.white, width: 1) : null,
  300. color: color ?? Colors.grey[900]),
  301. width: rosterswidth,
  302. height: rosterswidth,
  303. child: Column(children: [
  304. Row(
  305. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  306. children: [
  307. Text(
  308. date.format(pattern: "EEE"),
  309. style: const TextStyle(
  310. fontSize: 14,
  311. color: Colors.blueGrey,
  312. fontWeight: FontWeight.w700),
  313. ),
  314. Text(
  315. date.format(pattern: "dd MMM "),
  316. style: const TextStyle(
  317. fontSize: 14,
  318. color: Color.fromARGB(255, 151, 163, 55),
  319. fontWeight: FontWeight.w500),
  320. )
  321. ],
  322. ),
  323. Expanded(
  324. child: MyCol(
  325. crossAxisAlignment: CrossAxisAlignment.start,
  326. children: legs
  327. .map((leg) => _duty2line(leg,
  328. showdatedep: date.yMEd == leg.jdep?.yMEd))
  329. .toList()))
  330. ]),
  331. );
  332. }
  333. bool showalldates = false;
  334. List<Jiffy> alldates = [];
  335. List<String> alltlcs = [];
  336. List<String> favtlcs = [];
  337. @override
  338. Widget build(BuildContext context) {
  339. final data = ref.watch(dataProvider);
  340. final pnleg = data.pnleg;
  341. final qualif = data.qualif;
  342. // final now = ref.watch(clockProvider);
  343. final now = Jiffy.now().toUtc();
  344. // final pnlegmeta = ref.watch(pnlegMeta);
  345. // alltlcs = pnlegmeta.tlcs;
  346. // alldates = pnlegmeta.dates;
  347. alltlcs = data.pnleg_tlcs;
  348. alldates = data.pnleg_dates;
  349. final dates = alldates.where(
  350. (e) => e.isAfter(now.toUtc().startOf(Unit.day).subtract(days: 3)));
  351. // final dates = data.pnleg_dates.where(
  352. // (e) => e.isAfter(now.toUtc().startOf(Unit.day).subtract(days: 3)));
  353. final Set<String> tlcsCrewfilter = qualif
  354. .where((e) => ((crewFilter["college"]!.isEmpty ||
  355. crewFilter["college"]!.contains(e.college)) &&
  356. (crewFilter["ac"]!.isEmpty || crewFilter["ac"]!.contains(e.ac)) &&
  357. (crewFilter["base"]!.isEmpty ||
  358. crewFilter["base"]!.contains(e.base))))
  359. .map((e) => e.tlc ?? "")
  360. .toSet();
  361. final Set<String> tlcsFlightfilter = (flightFilter.values.every((e) => e == "")
  362. ? alltlcs
  363. : alltlcs.where((e) => ((flightFilter["al"] == "" ||
  364. pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.al == flightFilter["al"])) !=
  365. null) &&
  366. (flightFilter["fnum"] == "" ||
  367. pnleg.firstWhereOrNull((k) =>
  368. (k.tlc == e) && (k.fnum == flightFilter["fnum"])) !=
  369. null) &&
  370. (flightFilter["dep"] == "" ||
  371. pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.dep == flightFilter["dep"])) !=
  372. null) &&
  373. (flightFilter["des"] == "" ||
  374. pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.arr == flightFilter["des"])) !=
  375. null))))
  376. .toSet();
  377. // final Set<String> tlcsFlightfilter = pnleg
  378. // .where((k) => (k.jdep != null &&
  379. // (k.jdep!.isSameOrAfter(dates.first.startOf(Unit.day))) &&
  380. // (flightFilter["al"] == "" || k.al == flightFilter["al"]) &&
  381. // (flightFilter["fnum"] == "" || k.fnum == flightFilter["fnum"]) &&
  382. // (flightFilter["dep"] == "" || k.dep == flightFilter["dep"]) &&
  383. // (flightFilter["des"] == "" || k.arr == flightFilter["des"])))
  384. // .map((e) => e.tlc ?? "")
  385. // .toSet();
  386. final tlcs = (tlcsCrewfilter.intersection(tlcsFlightfilter).sortedBy((e) =>
  387. "${data.qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${data.qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}"));
  388. Widget getPnIndex(index, tlcs, cat) {
  389. final qualifData = qualif.where((k) => k.tlc == tlcs.elementAt(index));
  390. final tlc = tlcs.elementAt(index);
  391. final dutiesTlcAll = ref.watch(pnlegByTlcProvider(tlc));
  392. final dutiesTlc = flightFilter.values.every((x) => x == "")
  393. ? dutiesTlcAll
  394. : (dutiesTlcAll.where((e) => ((flightFilter["al"] == "" ||
  395. e.al == flightFilter["al"]) &&
  396. (flightFilter["fnum"] == "" || e.fnum == flightFilter["fnum"]) &&
  397. (flightFilter["dep"] == "" || e.dep == flightFilter["dep"]) &&
  398. (flightFilter["des"] == "" || e.arr == flightFilter["des"]))));
  399. final name =
  400. "${qualifData.firstOrNull?.lname?.capitalizeword()}, ${qualifData.firstOrNull?.fname?.capitalizeword()}";
  401. final base = "${qualifData.map((e) => e.base).toSet()}";
  402. return Column(
  403. crossAxisAlignment: CrossAxisAlignment.start,
  404. children: [
  405. Padding(
  406. padding: const EdgeInsets.all(2),
  407. child: Row(children: [
  408. const Gap(10),
  409. SizedBox.square(
  410. dimension: 15,
  411. child: InkWell(
  412. onTap: () {
  413. if (favtlcs.contains(tlc)) {
  414. favtlcs.remove(tlc);
  415. } else {
  416. favtlcs.add(tlc);
  417. }
  418. setState(() {});
  419. Hive.box("settings").put("rosters.favtlcs", favtlcs);
  420. },
  421. child: Icon(
  422. (favtlcs.contains(tlc))
  423. ? Icons.favorite
  424. : Icons.favorite_border,
  425. size: 18,
  426. color:
  427. (favtlcs.contains(tlc)) ? Colors.red : Colors.grey,
  428. ),
  429. )),
  430. const Gap(10),
  431. Text(name,
  432. style: const TextStyle(
  433. fontWeight: FontWeight.w700, letterSpacing: 1)),
  434. const Gap(10),
  435. Text(
  436. tlc,
  437. style: const TextStyle(
  438. fontSize: 12, fontWeight: FontWeight.w300),
  439. ),
  440. const Gap(5),
  441. Text(
  442. base,
  443. style: GoogleFonts.robotoMono(
  444. fontSize: 11, fontWeight: FontWeight.w300),
  445. )
  446. ])),
  447. SizedBox(
  448. height: rostersheight,
  449. child: (dates.isEmpty)
  450. ? const Text("No Pnlegs data found")
  451. : SuperListView.builder(
  452. listController: _listControllerH,
  453. delayPopulatingCacheArea: true,
  454. // controller: scrollControllerGroup.addAndGet(), //_scrollCtrl,
  455. controller: _getCtrl(index, cat: cat), //_scrollCtrl,
  456. scrollDirection: Axis.horizontal,
  457. itemCount: dates.length, // Number of horizontal items
  458. itemBuilder: (context, horizontalIndex) {
  459. final date = dates.elementAt(horizontalIndex);
  460. final duties = dutiesTlc.where((e) => DTInterval(
  461. e.jdep ??
  462. e.jdate?.startOf(Unit.day) ??
  463. Jiffy.now(),
  464. e.jarr ?? e.jdate?.endOf(Unit.day) ?? Jiffy.now())
  465. .isOverlap(DTInterval(
  466. date.startOf(Unit.day), date.endOf(Unit.day))));
  467. if (pnleg.isEmpty) {
  468. return const Padding(
  469. padding: EdgeInsets.all(5.0),
  470. child: Center(
  471. child: Text("No Pnlegs data found"),
  472. ),
  473. );
  474. }
  475. return Padding(
  476. padding: const EdgeInsets.symmetric(
  477. horizontal: 2, vertical: 1),
  478. child: _rostersDay(
  479. date: date,
  480. legs: duties.toList(),
  481. color: date
  482. .endOf(Unit.day)
  483. .isBefore(now.startOf(Unit.day))
  484. ? Colors.grey[900]
  485. : Colors.black,
  486. border: date.yMEd == now.yMEd),
  487. );
  488. },
  489. ),
  490. ),
  491. ],
  492. );
  493. }
  494. return BasicPage(
  495. actions: [Text("showing ${tlcs.length} crew member"), const Gap(5)],
  496. bottomNavigationBar: Container(
  497. padding: const EdgeInsets.only(left: 8, right: 8, bottom: 2, top: 6),
  498. // color: Colors.black,
  499. decoration: BoxDecoration(
  500. gradient: LinearGradient(
  501. begin: Alignment.topCenter,
  502. end: Alignment.bottomCenter,
  503. colors: [
  504. Colors.grey[700]!,
  505. Colors.black,
  506. ],
  507. )),
  508. child: Column(
  509. mainAxisSize: MainAxisSize.min,
  510. children: [
  511. Row(
  512. mainAxisAlignment: MainAxisAlignment.spaceAround,
  513. children: [
  514. Row(
  515. children: [
  516. ElevatedButton.icon(
  517. onPressed: () {
  518. _searchCrew(context, qualif);
  519. },
  520. icon: const Icon(Icons
  521. .calendar_month), //icon data for elevated button
  522. label: const Text("Filter\nCrew"), //label text
  523. style: bottomnavstyle,
  524. ),
  525. const Gap(10),
  526. Row(
  527. children: [
  528. Column(
  529. mainAxisSize: MainAxisSize.min,
  530. children: crewFilter.keys
  531. .where((e) => crewFilter[e]!.isNotEmpty)
  532. .map((e) => Text(
  533. "${crewFilter[e]}",
  534. style: const TextStyle(
  535. fontSize: 12, color: Colors.yellow),
  536. ))
  537. .toList()),
  538. const Gap(10),
  539. if (crewFilter.values.flattened.isNotEmpty)
  540. Badge(
  541. label: Text(crewFilter.values.flattened.length
  542. .toString()),
  543. child: IconButton.outlined(
  544. onPressed: () {
  545. for (var k in crewFilter.keys) {
  546. crewFilter[k]!.clear();
  547. }
  548. Hive.box("settings")
  549. .delete("rosters.filter.crew");
  550. setState(() {});
  551. },
  552. icon: const Icon(Icons.filter_alt_off_rounded,
  553. size: 18)),
  554. ),
  555. ],
  556. )
  557. ],
  558. ),
  559. const Gap(10),
  560. Row(
  561. children: [
  562. ElevatedButton.icon(
  563. onPressed: () {
  564. _searchFlights(context);
  565. },
  566. icon: const Icon(Icons.manage_search),
  567. label: const Text("Filter\nFlights"),
  568. style: bottomnavstyle,
  569. ),
  570. const Gap(10),
  571. if (flightFilter.values.any((e) => e != ""))
  572. Badge(
  573. label: Text(flightFilter.values
  574. .where((e) => e != "")
  575. .length
  576. .toString()),
  577. child: IconButton.outlined(
  578. onPressed: () {
  579. for (var k in flightFilter.keys) {
  580. flightFilter[k] = "";
  581. }
  582. Hive.box("settings")
  583. .delete("rosters.filter.flights");
  584. setState(() {});
  585. },
  586. icon: const Icon(Icons.filter_alt_off_rounded,
  587. size: 18)),
  588. )
  589. ],
  590. ),
  591. const Gap(10), //icon data for elevated button
  592. ],
  593. ),
  594. Row(
  595. mainAxisAlignment: MainAxisAlignment.end,
  596. children: [
  597. data.aclegupdate != null
  598. ? Text("data retrieved ${data.pnlegupdate?.from(now)}",
  599. style: GoogleFonts.robotoMono(
  600. fontSize: 10,
  601. fontWeight: FontWeight.w300,
  602. color: Colors.white))
  603. : Text("no data found",
  604. style: GoogleFonts.robotoMono(
  605. fontSize: 10, fontWeight: FontWeight.w300))
  606. ],
  607. ),
  608. ],
  609. ),
  610. ),
  611. title: "Rosters",
  612. body: tlcs.isEmpty
  613. ? const Text("no Pnleg data")
  614. : Column(
  615. children: [
  616. Column(
  617. children: favtlcs
  618. .mapIndexed(
  619. (index, tlc) => getPnIndex(index, favtlcs, 1))
  620. .toList()),
  621. const Divider(),
  622. Expanded(
  623. child: SuperListView.builder(
  624. listController: _listControllerV,
  625. delayPopulatingCacheArea: true,
  626. itemCount: tlcs.length, // Number of list items
  627. itemBuilder: (context, index) {
  628. return getPnIndex(index, tlcs, 0);
  629. },
  630. ),
  631. ),
  632. ],
  633. ));
  634. }
  635. @override
  636. void initState() {
  637. Future.delayed(Duration.zero).then((x) async {
  638. final savedcrewfilter =
  639. await Hive.box("settings").get("rosters.filter.crew");
  640. final savedflightsfilter =
  641. await Hive.box("settings").get("rosters.filter.flights");
  642. final savedfavtlcs = await Hive.box("settings").get("rosters.favtlcs");
  643. // print(
  644. // "rosters: saved crew filter: ${savedcrewfilter.runtimeType} $savedcrewfilter");
  645. // print("rosters: saved flights filter: $savedflightsfilter");
  646. if (savedcrewfilter != null && savedcrewfilter is Map) {
  647. crewFilter = savedcrewfilter
  648. .map((key, value) => MapEntry(key, List<String>.from(value)));
  649. }
  650. if (savedflightsfilter != null && savedflightsfilter is Map) {
  651. flightFilter =
  652. savedflightsfilter.map((key, value) => MapEntry(key, value));
  653. }
  654. if (savedfavtlcs != null && savedfavtlcs is List<String>) {
  655. favtlcs = savedfavtlcs;
  656. }
  657. if (favtlcs.isEmpty) {
  658. final crewlinkuser = Hive.box("profile").get("crewlink_user");
  659. if (crewlinkuser is String && crewlinkuser.isNotEmpty) {
  660. favtlcs.add(crewlinkuser);
  661. }
  662. }
  663. setState(() {});
  664. });
  665. super.initState();
  666. }
  667. }
  668. class PnlegMeta {
  669. PnlegMeta({required this.tlcs, required this.dates});
  670. final List<String> tlcs;
  671. final List<Jiffy> dates;
  672. }
  673. // final pnlegMeta = Provider((ref) {
  674. // print("data: start analyzing pnleg");
  675. // final now = Jiffy.now();
  676. // final data = ref.watch(dataProvider);
  677. // final pnlegs = data.pnleg;
  678. // final qualif = data.qualif;
  679. // Set<String> tlcs = {};
  680. // Set<Jiffy> dates = {};
  681. // for (Pnleg pnleg in pnlegs) {
  682. // tlcs.add(pnleg.tlc ?? "");
  683. // dates.add(pnleg.jdep?.startOf(Unit.day) ??
  684. // Jiffy.parse(pnleg.date ?? "01/01/1970",
  685. // pattern: "dd/MM/yyyy", isUtc: true));
  686. // }
  687. // // final restlcs = tlcs.sortedBy((k) =>qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
  688. // final restlcs = tlcs.sortedBy((e) =>
  689. // "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
  690. // final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
  691. // print(
  692. // "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
  693. // return PnlegMeta(tlcs: restlcs, dates: resdates);
  694. // });
  695. // final pnlegMeta = Provider((ref) {
  696. // print("data: start analyzing pnleg");
  697. // final now = Jiffy.now();
  698. // final data = ref.watch(dataProvider);
  699. // final pnleg = data.pnleg;
  700. // final qualif = data.qualif;
  701. // print(
  702. // "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
  703. // return PnlegMeta(
  704. // tlcs: pnleg.fold(<String>{}, (t, e) => {...t, e.tlc ?? ""}).sortedBy((e) {
  705. // final pn = qualif.firstWhereOrNull((q) => q.tlc == e);
  706. // return "${pn?.lname} ${pn?.fname}";
  707. // }),
  708. // dates: pnleg.fold(
  709. // <Jiffy>{},
  710. // (t, e) => {
  711. // ...t,
  712. // e.jdep?.startOf(Unit.day) ??
  713. // Jiffy.parse(e.date ?? "01/01/1970",
  714. // pattern: "dd/MM/yyyy", isUtc: true)
  715. // }).sortedBy((e) => e.dateTime));
  716. // });