1
0

rosters_page.dart 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  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.dutytype == "dhflight" || leg.dutytype == "flight") {
  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.dutytype == "dhlimo") {
  210. return InkWell(
  211. onTap: () {
  212. context.push("/dutyinfo",
  213. extra: DutyinfoParams(
  214. dutytype: leg.dutytype,
  215. // label: leg.label,
  216. dep: leg.dep,
  217. des: leg.arr,
  218. jdep: leg.jdep,
  219. jdes: leg.jarr));
  220. },
  221. child: MyRow(children: [
  222. whdep,
  223. const Gap(3),
  224. const Text("Limo ",
  225. style: TextStyle(fontSize: 11, color: Colors.amber)),
  226. Text(
  227. "${leg.dep}-${leg.arr}",
  228. style: GoogleFonts.robotoMono(
  229. fontSize: 11, fontWeight: FontWeight.w300),
  230. ),
  231. const Gap(3),
  232. wharr,
  233. ]),
  234. );
  235. } else if (leg.dutytype == "standby") {
  236. return InkWell(
  237. onTap: () {
  238. context.push("/dutyinfo",
  239. extra: DutyinfoParams(
  240. sameday: true, tlc: leg.tlc,
  241. dutytype: leg.dutytype,
  242. // label: leg.label,
  243. // dep: leg.dep,
  244. // des: leg.arr,
  245. jdep: leg.jdep,
  246. jdes: leg.jarr,
  247. ));
  248. },
  249. child: MyRow(children: [
  250. whdep,
  251. const Gap(3),
  252. Text("${leg.label}",
  253. style: const TextStyle(fontSize: 11, color: Colors.amber)),
  254. Text(
  255. " ${leg.dep}",
  256. style: GoogleFonts.robotoMono(
  257. fontSize: 8, fontWeight: FontWeight.w300),
  258. ),
  259. const Gap(3),
  260. wharr,
  261. ]),
  262. );
  263. } else if (leg.dutytype == "ground") {
  264. return InkWell(
  265. onTap: () {
  266. context.push("/dutyinfo",
  267. extra: DutyinfoParams(
  268. dutytype: leg.dutytype,
  269. label: leg.label,
  270. dep: leg.dep,
  271. des: leg.arr,
  272. jdep: leg.jdep,
  273. jdes: leg.jarr));
  274. },
  275. child: MyRow(children: [
  276. whdep,
  277. const Gap(3),
  278. Text("${leg.type == "S" ? "SIMU " : ""}${leg.label}",
  279. style: const TextStyle(fontSize: 11, color: Colors.amber)),
  280. Text(
  281. " ${leg.dep}",
  282. style: GoogleFonts.robotoMono(
  283. fontSize: 8, fontWeight: FontWeight.w300),
  284. ),
  285. const Gap(3),
  286. wharr,
  287. ]),
  288. );
  289. } else {
  290. return Text(
  291. leg.label ?? "",
  292. style: TextStyle(
  293. fontSize: 16,
  294. color: Colors.blueGrey[800],
  295. fontWeight: FontWeight.w700,
  296. letterSpacing: 1),
  297. );
  298. }
  299. }
  300. Widget _rostersDay(
  301. {required Jiffy date,
  302. required List<Pnleg> legs,
  303. Color? color,
  304. bool border = false}) {
  305. return Container(
  306. decoration: BoxDecoration(
  307. border: border ? Border.all(color: Colors.white, width: 1) : null,
  308. color: color ?? Colors.grey[900]),
  309. width: rosterswidth,
  310. height: rosterswidth,
  311. child: Column(children: [
  312. Row(
  313. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  314. children: [
  315. Text(
  316. date.format(pattern: "EEE"),
  317. style: const TextStyle(
  318. fontSize: 14,
  319. color: Colors.blueGrey,
  320. fontWeight: FontWeight.w700),
  321. ),
  322. Text(
  323. date.format(pattern: "dd MMM "),
  324. style: const TextStyle(
  325. fontSize: 14,
  326. color: Color.fromARGB(255, 151, 163, 55),
  327. fontWeight: FontWeight.w500),
  328. )
  329. ],
  330. ),
  331. Expanded(
  332. child: MyCol(
  333. crossAxisAlignment: CrossAxisAlignment.start,
  334. children: legs
  335. .map((leg) => _duty2line(leg,
  336. showdatedep: date.yMEd == leg.jdep?.yMEd))
  337. .toList()))
  338. ]),
  339. );
  340. }
  341. bool showalldates = false;
  342. List<Jiffy> alldates = [];
  343. List<String> alltlcs = [];
  344. List<String> favtlcs = [];
  345. @override
  346. Widget build(BuildContext context) {
  347. final data = ref.watch(dataProvider);
  348. final pnleg = data.pnleg;
  349. final qualif = data.qualif;
  350. // final now = ref.watch(clockProvider);
  351. final now = Jiffy.now().toUtc();
  352. // final pnlegmeta = ref.watch(pnlegMeta);
  353. // alltlcs = pnlegmeta.tlcs;
  354. // alldates = pnlegmeta.dates;
  355. alltlcs = data.pnleg_tlcs;
  356. alldates = data.pnleg_dates;
  357. final dates = alldates.where(
  358. (e) => e.isAfter(now.toUtc().startOf(Unit.day).subtract(days: 3)));
  359. // final dates = data.pnleg_dates.where(
  360. // (e) => e.isAfter(now.toUtc().startOf(Unit.day).subtract(days: 3)));
  361. final Set<String> tlcsCrewfilter = qualif
  362. .where((e) => ((crewFilter["college"]!.isEmpty ||
  363. crewFilter["college"]!.contains(e.college)) &&
  364. (crewFilter["ac"]!.isEmpty || crewFilter["ac"]!.contains(e.ac)) &&
  365. (crewFilter["base"]!.isEmpty ||
  366. crewFilter["base"]!.contains(e.base))))
  367. .map((e) => e.tlc ?? "")
  368. .toSet();
  369. final Set<String> tlcsFlightfilter = (flightFilter.values.every((e) => e == "")
  370. ? alltlcs
  371. : alltlcs.where((e) => ((flightFilter["al"] == "" ||
  372. pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.al == flightFilter["al"])) !=
  373. null) &&
  374. (flightFilter["fnum"] == "" ||
  375. pnleg.firstWhereOrNull((k) =>
  376. (k.tlc == e) && (k.fnum == flightFilter["fnum"])) !=
  377. null) &&
  378. (flightFilter["dep"] == "" ||
  379. pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.dep == flightFilter["dep"])) !=
  380. null) &&
  381. (flightFilter["des"] == "" ||
  382. pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.arr == flightFilter["des"])) !=
  383. null))))
  384. .toSet();
  385. // final Set<String> tlcsFlightfilter = pnleg
  386. // .where((k) => (k.jdep != null &&
  387. // (k.jdep!.isSameOrAfter(dates.first.startOf(Unit.day))) &&
  388. // (flightFilter["al"] == "" || k.al == flightFilter["al"]) &&
  389. // (flightFilter["fnum"] == "" || k.fnum == flightFilter["fnum"]) &&
  390. // (flightFilter["dep"] == "" || k.dep == flightFilter["dep"]) &&
  391. // (flightFilter["des"] == "" || k.arr == flightFilter["des"])))
  392. // .map((e) => e.tlc ?? "")
  393. // .toSet();
  394. final tlcs = (tlcsCrewfilter.intersection(tlcsFlightfilter).sortedBy((e) =>
  395. "${data.qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${data.qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}"));
  396. Widget getPnIndex(index, tlcs, cat) {
  397. final qualifData = qualif.where((k) => k.tlc == tlcs.elementAt(index));
  398. final tlc = tlcs.elementAt(index);
  399. final dutiesTlcAll = ref.watch(pnlegByTlcProvider(tlc));
  400. final dutiesTlc = dutiesTlcAll;
  401. // final dutiesTlc = flightFilter.values.every((x) => x == "")
  402. // ? dutiesTlcAll
  403. // : (dutiesTlcAll.where((e) => ((flightFilter["al"] == "" ||
  404. // e.al == flightFilter["al"]) &&
  405. // (flightFilter["fnum"] == "" || e.fnum == flightFilter["fnum"]) &&
  406. // (flightFilter["dep"] == "" || e.dep == flightFilter["dep"]) &&
  407. // (flightFilter["des"] == "" || e.arr == flightFilter["des"]))));
  408. final name =
  409. "${qualifData.firstOrNull?.lname?.capitalizeword()}, ${qualifData.firstOrNull?.fname?.capitalizeword()}";
  410. final base = "${qualifData.map((e) => e.base).toSet()}";
  411. return Column(
  412. crossAxisAlignment: CrossAxisAlignment.start,
  413. children: [
  414. Padding(
  415. padding: const EdgeInsets.all(2),
  416. child: Row(children: [
  417. const Gap(10),
  418. SizedBox.square(
  419. dimension: 15,
  420. child: InkWell(
  421. onTap: () {
  422. if (favtlcs.contains(tlc)) {
  423. favtlcs.remove(tlc);
  424. } else {
  425. favtlcs.add(tlc);
  426. }
  427. setState(() {});
  428. Hive.box("settings").put("rosters.favtlcs", favtlcs);
  429. },
  430. child: Icon(
  431. (favtlcs.contains(tlc))
  432. ? Icons.favorite
  433. : Icons.favorite_border,
  434. size: 18,
  435. color:
  436. (favtlcs.contains(tlc)) ? Colors.red : Colors.grey,
  437. ),
  438. )),
  439. const Gap(10),
  440. Text(name,
  441. style: const TextStyle(
  442. fontWeight: FontWeight.w700, letterSpacing: 1)),
  443. const Gap(10),
  444. Text(
  445. tlc,
  446. style: const TextStyle(
  447. fontSize: 12, fontWeight: FontWeight.w300),
  448. ),
  449. const Gap(5),
  450. Text(
  451. base,
  452. style: GoogleFonts.robotoMono(
  453. fontSize: 11, fontWeight: FontWeight.w300),
  454. )
  455. ])),
  456. SizedBox(
  457. height: rostersheight,
  458. child: (dates.isEmpty)
  459. ? const Text("No Pnlegs data found")
  460. : SuperListView.builder(
  461. listController: _listControllerH,
  462. delayPopulatingCacheArea: true,
  463. // controller: scrollControllerGroup.addAndGet(), //_scrollCtrl,
  464. controller: _getCtrl(index, cat: cat), //_scrollCtrl,
  465. scrollDirection: Axis.horizontal,
  466. itemCount: dates.length, // Number of horizontal items
  467. itemBuilder: (context, horizontalIndex) {
  468. final date = dates.elementAt(horizontalIndex);
  469. final duties = dutiesTlc.where((e) => DTInterval(
  470. e.jdep ??
  471. e.jdate?.startOf(Unit.day) ??
  472. Jiffy.now(),
  473. e.jarr ?? e.jdate?.endOf(Unit.day) ?? Jiffy.now())
  474. .isOverlap(DTInterval(
  475. date.startOf(Unit.day), date.endOf(Unit.day))));
  476. if (pnleg.isEmpty) {
  477. return const Padding(
  478. padding: EdgeInsets.all(5.0),
  479. child: Center(
  480. child: Text("No Pnlegs data found"),
  481. ),
  482. );
  483. }
  484. return Padding(
  485. padding: const EdgeInsets.symmetric(
  486. horizontal: 2, vertical: 1),
  487. child: _rostersDay(
  488. date: date,
  489. legs: duties.toList(),
  490. color: date
  491. .endOf(Unit.day)
  492. .isBefore(now.startOf(Unit.day))
  493. ? Colors.grey[900]
  494. : Colors.black,
  495. border: date.yMEd == now.yMEd),
  496. );
  497. },
  498. ),
  499. ),
  500. ],
  501. );
  502. }
  503. return BasicPage(
  504. actions: [Text("showing ${tlcs.length} crew member"), const Gap(5)],
  505. bottomNavigationBar: Container(
  506. padding: const EdgeInsets.only(left: 8, right: 8, bottom: 2, top: 6),
  507. // color: Colors.black,
  508. decoration: BoxDecoration(
  509. gradient: LinearGradient(
  510. begin: Alignment.topCenter,
  511. end: Alignment.bottomCenter,
  512. colors: [
  513. Colors.grey[700]!,
  514. Colors.black,
  515. ],
  516. )),
  517. child: Column(
  518. mainAxisSize: MainAxisSize.min,
  519. children: [
  520. Row(
  521. mainAxisAlignment: MainAxisAlignment.spaceAround,
  522. children: [
  523. Row(
  524. children: [
  525. ElevatedButton.icon(
  526. onPressed: () {
  527. _searchCrew(context, qualif);
  528. },
  529. icon: const Icon(Icons
  530. .calendar_month), //icon data for elevated button
  531. label: const Text("Filter\nCrew"), //label text
  532. style: bottomnavstyle,
  533. ),
  534. const Gap(10),
  535. Row(
  536. children: [
  537. Column(
  538. mainAxisSize: MainAxisSize.min,
  539. children: crewFilter.keys
  540. .where((e) => crewFilter[e]!.isNotEmpty)
  541. .map((e) => Text(
  542. "${crewFilter[e]}",
  543. style: const TextStyle(
  544. fontSize: 12, color: Colors.yellow),
  545. ))
  546. .toList()),
  547. const Gap(10),
  548. if (crewFilter.values.flattened.isNotEmpty)
  549. Badge(
  550. label: Text(crewFilter.values.flattened.length
  551. .toString()),
  552. child: IconButton.outlined(
  553. onPressed: () {
  554. for (var k in crewFilter.keys) {
  555. crewFilter[k]!.clear();
  556. }
  557. Hive.box("settings")
  558. .delete("rosters.filter.crew");
  559. setState(() {});
  560. },
  561. icon: const Icon(Icons.filter_alt_off_rounded,
  562. size: 18)),
  563. ),
  564. ],
  565. )
  566. ],
  567. ),
  568. const Gap(10),
  569. Row(
  570. children: [
  571. ElevatedButton.icon(
  572. onPressed: () {
  573. _searchFlights(context);
  574. },
  575. icon: const Icon(Icons.manage_search),
  576. label: const Text("Filter\nFlights"),
  577. style: bottomnavstyle,
  578. ),
  579. const Gap(10),
  580. if (flightFilter.values.any((e) => e != ""))
  581. Badge(
  582. label: Text(flightFilter.values
  583. .where((e) => e != "")
  584. .length
  585. .toString()),
  586. child: IconButton.outlined(
  587. onPressed: () {
  588. for (var k in flightFilter.keys) {
  589. flightFilter[k] = "";
  590. }
  591. Hive.box("settings")
  592. .delete("rosters.filter.flights");
  593. setState(() {});
  594. },
  595. icon: const Icon(Icons.filter_alt_off_rounded,
  596. size: 18)),
  597. )
  598. ],
  599. ),
  600. const Gap(10), //icon data for elevated button
  601. ],
  602. ),
  603. Row(
  604. mainAxisAlignment: MainAxisAlignment.end,
  605. children: [
  606. data.aclegupdate != null
  607. ? Text("data retrieved ${data.pnlegupdate?.from(now)}",
  608. style: GoogleFonts.robotoMono(
  609. fontSize: 10,
  610. fontWeight: FontWeight.w300,
  611. color: Colors.white))
  612. : Text("no data found",
  613. style: GoogleFonts.robotoMono(
  614. fontSize: 10, fontWeight: FontWeight.w300))
  615. ],
  616. ),
  617. ],
  618. ),
  619. ),
  620. title: "Rosters",
  621. body: tlcs.isEmpty
  622. ? const Text("no Pnleg data")
  623. : Column(
  624. children: [
  625. Column(
  626. children: favtlcs
  627. .mapIndexed(
  628. (index, tlc) => getPnIndex(index, favtlcs, 1))
  629. .toList()),
  630. const Divider(),
  631. Expanded(
  632. child: SuperListView.builder(
  633. listController: _listControllerV,
  634. delayPopulatingCacheArea: true,
  635. itemCount: tlcs.length, // Number of list items
  636. itemBuilder: (context, index) {
  637. return getPnIndex(index, tlcs, 0);
  638. },
  639. ),
  640. ),
  641. ],
  642. ));
  643. }
  644. @override
  645. void initState() {
  646. Future.delayed(Duration.zero).then((x) async {
  647. final savedcrewfilter =
  648. await Hive.box("settings").get("rosters.filter.crew");
  649. final savedflightsfilter =
  650. await Hive.box("settings").get("rosters.filter.flights");
  651. final savedfavtlcs = await Hive.box("settings").get("rosters.favtlcs");
  652. // print(
  653. // "rosters: saved crew filter: ${savedcrewfilter.runtimeType} $savedcrewfilter");
  654. // print("rosters: saved flights filter: $savedflightsfilter");
  655. if (savedcrewfilter != null && savedcrewfilter is Map) {
  656. crewFilter = savedcrewfilter
  657. .map((key, value) => MapEntry(key, List<String>.from(value)));
  658. }
  659. if (savedflightsfilter != null && savedflightsfilter is Map) {
  660. flightFilter =
  661. savedflightsfilter.map((key, value) => MapEntry(key, value));
  662. }
  663. if (savedfavtlcs != null && savedfavtlcs is List<String>) {
  664. favtlcs = savedfavtlcs;
  665. }
  666. if (favtlcs.isEmpty) {
  667. final crewlinkuser = Hive.box("profile").get("crewlink_user");
  668. if (crewlinkuser is String && crewlinkuser.isNotEmpty) {
  669. favtlcs.add(crewlinkuser);
  670. }
  671. }
  672. setState(() {});
  673. });
  674. super.initState();
  675. }
  676. }
  677. class PnlegMeta {
  678. PnlegMeta({required this.tlcs, required this.dates});
  679. final List<String> tlcs;
  680. final List<Jiffy> dates;
  681. }
  682. // final pnlegMeta = Provider((ref) {
  683. // print("data: start analyzing pnleg");
  684. // final now = Jiffy.now();
  685. // final data = ref.watch(dataProvider);
  686. // final pnlegs = data.pnleg;
  687. // final qualif = data.qualif;
  688. // Set<String> tlcs = {};
  689. // Set<Jiffy> dates = {};
  690. // for (Pnleg pnleg in pnlegs) {
  691. // tlcs.add(pnleg.tlc ?? "");
  692. // dates.add(pnleg.jdep?.startOf(Unit.day) ??
  693. // Jiffy.parse(pnleg.date ?? "01/01/1970",
  694. // pattern: "dd/MM/yyyy", isUtc: true));
  695. // }
  696. // // final restlcs = tlcs.sortedBy((k) =>qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
  697. // final restlcs = tlcs.sortedBy((e) =>
  698. // "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
  699. // final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
  700. // print(
  701. // "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
  702. // return PnlegMeta(tlcs: restlcs, dates: resdates);
  703. // });
  704. // final pnlegMeta = Provider((ref) {
  705. // print("data: start analyzing pnleg");
  706. // final now = Jiffy.now();
  707. // final data = ref.watch(dataProvider);
  708. // final pnleg = data.pnleg;
  709. // final qualif = data.qualif;
  710. // print(
  711. // "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
  712. // return PnlegMeta(
  713. // tlcs: pnleg.fold(<String>{}, (t, e) => {...t, e.tlc ?? ""}).sortedBy((e) {
  714. // final pn = qualif.firstWhereOrNull((q) => q.tlc == e);
  715. // return "${pn?.lname} ${pn?.fname}";
  716. // }),
  717. // dates: pnleg.fold(
  718. // <Jiffy>{},
  719. // (t, e) => {
  720. // ...t,
  721. // e.jdep?.startOf(Unit.day) ??
  722. // Jiffy.parse(e.date ?? "01/01/1970",
  723. // pattern: "dd/MM/yyyy", isUtc: true)
  724. // }).sortedBy((e) => e.dateTime));
  725. // });