1
0

rosters_page.dart 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  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 = dutiesTlcAll;
  393. // final dutiesTlc = flightFilter.values.every((x) => x == "")
  394. // ? dutiesTlcAll
  395. // : (dutiesTlcAll.where((e) => ((flightFilter["al"] == "" ||
  396. // e.al == flightFilter["al"]) &&
  397. // (flightFilter["fnum"] == "" || e.fnum == flightFilter["fnum"]) &&
  398. // (flightFilter["dep"] == "" || e.dep == flightFilter["dep"]) &&
  399. // (flightFilter["des"] == "" || e.arr == flightFilter["des"]))));
  400. final name =
  401. "${qualifData.firstOrNull?.lname?.capitalizeword()}, ${qualifData.firstOrNull?.fname?.capitalizeword()}";
  402. final base = "${qualifData.map((e) => e.base).toSet()}";
  403. return Column(
  404. crossAxisAlignment: CrossAxisAlignment.start,
  405. children: [
  406. Padding(
  407. padding: const EdgeInsets.all(2),
  408. child: Row(children: [
  409. const Gap(10),
  410. SizedBox.square(
  411. dimension: 15,
  412. child: InkWell(
  413. onTap: () {
  414. if (favtlcs.contains(tlc)) {
  415. favtlcs.remove(tlc);
  416. } else {
  417. favtlcs.add(tlc);
  418. }
  419. setState(() {});
  420. Hive.box("settings").put("rosters.favtlcs", favtlcs);
  421. },
  422. child: Icon(
  423. (favtlcs.contains(tlc))
  424. ? Icons.favorite
  425. : Icons.favorite_border,
  426. size: 18,
  427. color:
  428. (favtlcs.contains(tlc)) ? Colors.red : Colors.grey,
  429. ),
  430. )),
  431. const Gap(10),
  432. Text(name,
  433. style: const TextStyle(
  434. fontWeight: FontWeight.w700, letterSpacing: 1)),
  435. const Gap(10),
  436. Text(
  437. tlc,
  438. style: const TextStyle(
  439. fontSize: 12, fontWeight: FontWeight.w300),
  440. ),
  441. const Gap(5),
  442. Text(
  443. base,
  444. style: GoogleFonts.robotoMono(
  445. fontSize: 11, fontWeight: FontWeight.w300),
  446. )
  447. ])),
  448. SizedBox(
  449. height: rostersheight,
  450. child: (dates.isEmpty)
  451. ? const Text("No Pnlegs data found")
  452. : SuperListView.builder(
  453. listController: _listControllerH,
  454. delayPopulatingCacheArea: true,
  455. // controller: scrollControllerGroup.addAndGet(), //_scrollCtrl,
  456. controller: _getCtrl(index, cat: cat), //_scrollCtrl,
  457. scrollDirection: Axis.horizontal,
  458. itemCount: dates.length, // Number of horizontal items
  459. itemBuilder: (context, horizontalIndex) {
  460. final date = dates.elementAt(horizontalIndex);
  461. final duties = dutiesTlc.where((e) => DTInterval(
  462. e.jdep ??
  463. e.jdate?.startOf(Unit.day) ??
  464. Jiffy.now(),
  465. e.jarr ?? e.jdate?.endOf(Unit.day) ?? Jiffy.now())
  466. .isOverlap(DTInterval(
  467. date.startOf(Unit.day), date.endOf(Unit.day))));
  468. if (pnleg.isEmpty) {
  469. return const Padding(
  470. padding: EdgeInsets.all(5.0),
  471. child: Center(
  472. child: Text("No Pnlegs data found"),
  473. ),
  474. );
  475. }
  476. return Padding(
  477. padding: const EdgeInsets.symmetric(
  478. horizontal: 2, vertical: 1),
  479. child: _rostersDay(
  480. date: date,
  481. legs: duties.toList(),
  482. color: date
  483. .endOf(Unit.day)
  484. .isBefore(now.startOf(Unit.day))
  485. ? Colors.grey[900]
  486. : Colors.black,
  487. border: date.yMEd == now.yMEd),
  488. );
  489. },
  490. ),
  491. ),
  492. ],
  493. );
  494. }
  495. return BasicPage(
  496. actions: [Text("showing ${tlcs.length} crew member"), const Gap(5)],
  497. bottomNavigationBar: Container(
  498. padding: const EdgeInsets.only(left: 8, right: 8, bottom: 2, top: 6),
  499. // color: Colors.black,
  500. decoration: BoxDecoration(
  501. gradient: LinearGradient(
  502. begin: Alignment.topCenter,
  503. end: Alignment.bottomCenter,
  504. colors: [
  505. Colors.grey[700]!,
  506. Colors.black,
  507. ],
  508. )),
  509. child: Column(
  510. mainAxisSize: MainAxisSize.min,
  511. children: [
  512. Row(
  513. mainAxisAlignment: MainAxisAlignment.spaceAround,
  514. children: [
  515. Row(
  516. children: [
  517. ElevatedButton.icon(
  518. onPressed: () {
  519. _searchCrew(context, qualif);
  520. },
  521. icon: const Icon(Icons
  522. .calendar_month), //icon data for elevated button
  523. label: const Text("Filter\nCrew"), //label text
  524. style: bottomnavstyle,
  525. ),
  526. const Gap(10),
  527. Row(
  528. children: [
  529. Column(
  530. mainAxisSize: MainAxisSize.min,
  531. children: crewFilter.keys
  532. .where((e) => crewFilter[e]!.isNotEmpty)
  533. .map((e) => Text(
  534. "${crewFilter[e]}",
  535. style: const TextStyle(
  536. fontSize: 12, color: Colors.yellow),
  537. ))
  538. .toList()),
  539. const Gap(10),
  540. if (crewFilter.values.flattened.isNotEmpty)
  541. Badge(
  542. label: Text(crewFilter.values.flattened.length
  543. .toString()),
  544. child: IconButton.outlined(
  545. onPressed: () {
  546. for (var k in crewFilter.keys) {
  547. crewFilter[k]!.clear();
  548. }
  549. Hive.box("settings")
  550. .delete("rosters.filter.crew");
  551. setState(() {});
  552. },
  553. icon: const Icon(Icons.filter_alt_off_rounded,
  554. size: 18)),
  555. ),
  556. ],
  557. )
  558. ],
  559. ),
  560. const Gap(10),
  561. Row(
  562. children: [
  563. ElevatedButton.icon(
  564. onPressed: () {
  565. _searchFlights(context);
  566. },
  567. icon: const Icon(Icons.manage_search),
  568. label: const Text("Filter\nFlights"),
  569. style: bottomnavstyle,
  570. ),
  571. const Gap(10),
  572. if (flightFilter.values.any((e) => e != ""))
  573. Badge(
  574. label: Text(flightFilter.values
  575. .where((e) => e != "")
  576. .length
  577. .toString()),
  578. child: IconButton.outlined(
  579. onPressed: () {
  580. for (var k in flightFilter.keys) {
  581. flightFilter[k] = "";
  582. }
  583. Hive.box("settings")
  584. .delete("rosters.filter.flights");
  585. setState(() {});
  586. },
  587. icon: const Icon(Icons.filter_alt_off_rounded,
  588. size: 18)),
  589. )
  590. ],
  591. ),
  592. const Gap(10), //icon data for elevated button
  593. ],
  594. ),
  595. Row(
  596. mainAxisAlignment: MainAxisAlignment.end,
  597. children: [
  598. data.aclegupdate != null
  599. ? Text("data retrieved ${data.pnlegupdate?.from(now)}",
  600. style: GoogleFonts.robotoMono(
  601. fontSize: 10,
  602. fontWeight: FontWeight.w300,
  603. color: Colors.white))
  604. : Text("no data found",
  605. style: GoogleFonts.robotoMono(
  606. fontSize: 10, fontWeight: FontWeight.w300))
  607. ],
  608. ),
  609. ],
  610. ),
  611. ),
  612. title: "Rosters",
  613. body: tlcs.isEmpty
  614. ? const Text("no Pnleg data")
  615. : Column(
  616. children: [
  617. Column(
  618. children: favtlcs
  619. .mapIndexed(
  620. (index, tlc) => getPnIndex(index, favtlcs, 1))
  621. .toList()),
  622. const Divider(),
  623. Expanded(
  624. child: SuperListView.builder(
  625. listController: _listControllerV,
  626. delayPopulatingCacheArea: true,
  627. itemCount: tlcs.length, // Number of list items
  628. itemBuilder: (context, index) {
  629. return getPnIndex(index, tlcs, 0);
  630. },
  631. ),
  632. ),
  633. ],
  634. ));
  635. }
  636. @override
  637. void initState() {
  638. Future.delayed(Duration.zero).then((x) async {
  639. final savedcrewfilter =
  640. await Hive.box("settings").get("rosters.filter.crew");
  641. final savedflightsfilter =
  642. await Hive.box("settings").get("rosters.filter.flights");
  643. final savedfavtlcs = await Hive.box("settings").get("rosters.favtlcs");
  644. // print(
  645. // "rosters: saved crew filter: ${savedcrewfilter.runtimeType} $savedcrewfilter");
  646. // print("rosters: saved flights filter: $savedflightsfilter");
  647. if (savedcrewfilter != null && savedcrewfilter is Map) {
  648. crewFilter = savedcrewfilter
  649. .map((key, value) => MapEntry(key, List<String>.from(value)));
  650. }
  651. if (savedflightsfilter != null && savedflightsfilter is Map) {
  652. flightFilter =
  653. savedflightsfilter.map((key, value) => MapEntry(key, value));
  654. }
  655. if (savedfavtlcs != null && savedfavtlcs is List<String>) {
  656. favtlcs = savedfavtlcs;
  657. }
  658. if (favtlcs.isEmpty) {
  659. final crewlinkuser = Hive.box("profile").get("crewlink_user");
  660. if (crewlinkuser is String && crewlinkuser.isNotEmpty) {
  661. favtlcs.add(crewlinkuser);
  662. }
  663. }
  664. setState(() {});
  665. });
  666. super.initState();
  667. }
  668. }
  669. class PnlegMeta {
  670. PnlegMeta({required this.tlcs, required this.dates});
  671. final List<String> tlcs;
  672. final List<Jiffy> dates;
  673. }
  674. // final pnlegMeta = Provider((ref) {
  675. // print("data: start analyzing pnleg");
  676. // final now = Jiffy.now();
  677. // final data = ref.watch(dataProvider);
  678. // final pnlegs = data.pnleg;
  679. // final qualif = data.qualif;
  680. // Set<String> tlcs = {};
  681. // Set<Jiffy> dates = {};
  682. // for (Pnleg pnleg in pnlegs) {
  683. // tlcs.add(pnleg.tlc ?? "");
  684. // dates.add(pnleg.jdep?.startOf(Unit.day) ??
  685. // Jiffy.parse(pnleg.date ?? "01/01/1970",
  686. // pattern: "dd/MM/yyyy", isUtc: true));
  687. // }
  688. // // final restlcs = tlcs.sortedBy((k) =>qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
  689. // final restlcs = tlcs.sortedBy((e) =>
  690. // "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
  691. // final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
  692. // print(
  693. // "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
  694. // return PnlegMeta(tlcs: restlcs, dates: resdates);
  695. // });
  696. // final pnlegMeta = Provider((ref) {
  697. // print("data: start analyzing pnleg");
  698. // final now = Jiffy.now();
  699. // final data = ref.watch(dataProvider);
  700. // final pnleg = data.pnleg;
  701. // final qualif = data.qualif;
  702. // print(
  703. // "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
  704. // return PnlegMeta(
  705. // tlcs: pnleg.fold(<String>{}, (t, e) => {...t, e.tlc ?? ""}).sortedBy((e) {
  706. // final pn = qualif.firstWhereOrNull((q) => q.tlc == e);
  707. // return "${pn?.lname} ${pn?.fname}";
  708. // }),
  709. // dates: pnleg.fold(
  710. // <Jiffy>{},
  711. // (t, e) => {
  712. // ...t,
  713. // e.jdep?.startOf(Unit.day) ??
  714. // Jiffy.parse(e.date ?? "01/01/1970",
  715. // pattern: "dd/MM/yyyy", isUtc: true)
  716. // }).sortedBy((e) => e.dateTime));
  717. // });