| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 | // ignore_for_file: unused_importimport 'dart:developer';import 'package:collection/collection.dart';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:flutter_riverpod/flutter_riverpod.dart';import 'package:gap/gap.dart';import 'package:go_router/go_router.dart';import 'package:google_fonts/google_fonts.dart';import 'package:jiffy/jiffy.dart';import 'package:linear_progress_bar/linear_progress_bar.dart';import 'package:multi_select_flutter/multi_select_flutter.dart';import 'package:tp5/core/core.dart';import 'package:tp5/csv/csv_data.dart';import 'package:tp5/csv/data.dart';import 'package:tp5/flightslist/w_flt.dart';import 'package:tp5/fltinfo/delaycodes.dart';import 'package:tp5/fltinfo/widget/w_cadre.dart';import 'package:tp5/ftl/widget/w_shadowbox.dart';import 'package:tp5/lido/lido_api.dart';import 'package:tp5/lido/model/Lidoapi_list.dart';import 'package:tp5/lido/model/Lidoapi_ofp.dart';import 'package:tp5/lido/w_lidoflt.dart';import 'package:tp5/pdf/pdf_page.dart';import 'package:tp5/roster/api/crewlink_api.dart';import 'package:tp5/roster/models/duty.dart';import 'package:tp5/roster/widgets/w_airport.dart';import 'package:tp5/roster/widgets/w_citypair.dart';import 'package:tp5/roster/widgets/w_crew.dart';import 'package:tp5/roster/widgets/w_day.dart';import 'package:tp5/roster/widgets/w_fnum.dart';import 'package:tp5/roster/widgets/w_hour.dart';import 'package:tp5/widgets/my_row.dart';class DutyinfoPage extends ConsumerStatefulWidget {  const DutyinfoPage({required this.params, super.key});  final DutyinfoParams params;  @override  ConsumerState<ConsumerStatefulWidget> createState() => _DutyinfoPageState();}class _DutyinfoPageState extends ConsumerState<DutyinfoPage> {  @override  void initState() {    Future.delayed(Duration.zero, () {      if (widget.params.tlc != null) {        final qualif = ref.read(dataProvider).qualif;        collegeSelected = qualif            .where((e) => e.tlc == widget.params.tlc)            .map((e) => e.college ?? "")            .toSet()            .toList();        acSelected = qualif            .where((e) => e.tlc == widget.params.tlc)            .map((e) => e.ac ?? "")            .toSet()            .toList();        baseSelected = qualif            .where((e) => e.tlc == widget.params.tlc)            .map((e) => e.base ?? "")            .toSet()            .toList();      }      crewPnlegLoad();    });    super.initState();  }  // List crew = [];  Jiffy _now = Jiffy.now().toUtc();  @override  Widget build(BuildContext context) {    //final data = ref.watch(dataProvider);    //final pnleg = data.pnleg;    // final _dateNotifiedcrew = data.pnlegupdate;    _now = ref.watch(clockProvider);    //final qualif = ref.watch(dataProvider).qualif;    return Scaffold(      appBar: AppBar(        title: MyRow(          // mainAxisAlignment: MainAxisAlignment.spaceBetween,          children: [            Text(                '${widget.params.dutytype ?? ""} ${widget.params.label ?? ""} ${widget.params.dep}${widget.params.des != null ? "-${widget.params.des}" : ""}'),            const Gap(10),            Text(widget.params.jdep!.format(pattern: "EEE ddMMM'yy"),                style: const TextStyle(fontSize: 12)),          ],        ),        leading: IconButton(          icon: const Icon(Icons.arrow_back),          onPressed: () {            context.pop(context);          },        ),        actions: [          Text(            '${widget.params.dutytype ?? "Duty"} info',            style: TextStyle(                fontSize: 12,                fontWeight: FontWeight.w700,                color: Colors.yellow),          ),          Gap(10)        ],      ),      body: ListView(        padding: const EdgeInsets.all(5),        children: [          WCadre(            child: Column(              children: [                WDay(date: widget.params.jdep!),                if (widget.params.label != null)                  Text(                    widget.params.label!,                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),                  )                else if (widget.params.dutytype != null)                  Text(                    widget.params.dutytype!,                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),                  ),                Row(                  mainAxisAlignment: MainAxisAlignment.center,                  mainAxisSize: MainAxisSize.max,                  children: [                    if (widget.params.des != null)                      WCitypair(                          iata1: "${widget.params.dep}",                          iata2: widget.params.des ?? "---")                    else                      WAirport(iata: widget.params.dep ?? "---"),                  ],                ),                Row(                    mainAxisAlignment: MainAxisAlignment.center,                    mainAxisSize: MainAxisSize.max,                    children: [                      WHour(jiffy: widget.params.jdep!),                      if (widget.params.jdes != null) ...[                        const Gap(20),                        WHour(jiffy: widget.params.jdes!)                      ],                    ]),                const Gap(10)              ],            ),          ),          const Gap(20),          if (widget.params.dutytype == "standby")            _stdbyCrew()          else            _notifiedCrew(),        ],      ),    );  }  Jiffy? _dateNotifiedcrew;  static List<Pnleg> filterPnleg(Map data) {    final List<Pnleg> pnleg = data["pnleg"];    final DutyinfoParams filter = data["filter"];    return pnleg        .where((leg) => ((filter.jdep == null ||                (filter.sameday                    ? (leg.jdep?.startOf(Unit.day) ==                        filter.jdep?.startOf(Unit.day))                    : ((leg.jdep == filter.jdep) &&                        (filter.jdes == null || leg.jarr == filter.jdes)))) &&            (filter.dep == null || leg.dep == filter.dep) &&            (filter.des == null || leg.arr == filter.des) &&            (filter.label == null || leg.label == filter.label) &&            (filter.dutytype == null || leg.dutytype == filter.dutytype)))        .toList();  }  List<Pnleg> crewPnleg = [];  bool crewPnlegLoading = false;  crewPnlegLoad() async {    crewPnlegLoading = true;    setState(() {});    final data = ref.watch(dataProvider);    final pnleg = data.pnleg;    _dateNotifiedcrew = data.pnlegupdate;    crewPnleg =        await compute(filterPnleg, {"pnleg": pnleg, "filter": widget.params});    crewPnlegLoading = false;    setState(() {});  }  _notifiedCrew() {    // final qualif = ref.watch(qualifProvider(CrewFilter()));    final qualif = ref.watch(dataProvider).qualif;    return WCadre(      titleright: crewPnlegLoading          ? Padding(              padding: const EdgeInsets.all(5.0),              child: CircularProgressIndicator(),            )          : ElevatedButton.icon(              label: const Text("Update", style: TextStyle(fontSize: 9)),              onPressed: () async {                await crewPnlegLoad();              },              icon: const Icon(Icons.update)),      title: "Notified Crew (alt)",      bottomright: _dateNotifiedcrew != null          ? Text("data retrieved ${_dateNotifiedcrew?.from(_now)}",              style: GoogleFonts.robotoMono(                  fontSize: 10, fontWeight: FontWeight.w300))          : null,      child: crewPnleg.isEmpty          ? const Text("No data found !")          : Column(              children: [                Padding(                  padding: const EdgeInsets.all(8.0),                  child: Column(                      children: crewPnleg                          .mapIndexed((int i, leg) => {                                "index": i,                                "college": (["F", ""].contains(leg.type))                                    ? "DH"                                    : (qualif                                            .firstWhereOrNull((e) =>                                                (e.tlc == leg.tlc) &&                                                (e.ac == leg.actype))                                            ?.college ??                                        qualif                                            .firstWhereOrNull(                                                (e) => e.tlc == leg.tlc)                                            ?.college ??                                        "--")                              })                          .sortedByCompare(                              (e) => e["college"].toString(), collegeSort)                          .map<Widget>((e) {                    final x = crewPnleg.elementAt(e["index"] as int);                    // final pn = qualif.firstWhereOrNull((e) => e.tlc == x.tlc);                    final pn = (qualif.firstWhereOrNull(                            (e) => (e.tlc == x.tlc) && (e.ac == x.actype)) ??                        qualif.firstWhereOrNull((e) => e.tlc == x.tlc));                    return WCrew(                      college: pn?.college,                      mle: x.tlc,                      base: pn?.base,                      name: "${pn?.lname}, ${pn?.fname}",                    );                  }).toList()),                )              ],            ),    );  }  List<String> collegeSelected = [];  List<String> acSelected = [];  List<String> baseSelected = [];  _stdbyCrew() {    // final qualif = ref.watch(qualifProvider(CrewFilter()));    final qualif = ref.watch(dataProvider).qualif;    final tlcs = crewPnleg.map((e) => e.tlc).toSet();    final pairs = qualif        .where((e) => tlcs.contains(e.tlc))        .map((e) => "${e.college},${e.ac},${e.base}")        .toSet()        .map((e) => e.split(","))        .toList();    final List<String> pnfilterd = qualif        .where((q) =>            ((collegeSelected.isEmpty || collegeSelected.contains(q.college)) &&                (acSelected.isEmpty || acSelected.contains(q.ac)) &&                (baseSelected.isEmpty || baseSelected.contains(q.base))))        .map((e) => e.tlc ?? "")        .toSet()        .toList();    final List<Pnleg> crewPnlegFiltered =        crewPnleg.where((e) => pnfilterd.contains(e.tlc)).toList();    return WCadre(      titleright: crewPnlegLoading          ? Padding(              padding: const EdgeInsets.all(5.0),              child: CircularProgressIndicator(),            )          : ElevatedButton.icon(              label: const Text("Update", style: TextStyle(fontSize: 9)),              onPressed: () async {                await crewPnlegLoad();              },              icon: const Icon(Icons.update)),      title: "STDBY Crew",      bottomright: _dateNotifiedcrew != null          ? Text("data retrieved ${_dateNotifiedcrew?.from(_now)}",              style: GoogleFonts.robotoMono(                  fontSize: 10, fontWeight: FontWeight.w300))          : null,      child: crewPnleg.isEmpty          ? const Text("No data found !")          : Column(              children: [                MyRow(                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,                  children: [                    Gap(5),                    Column(                      children: [                        const Text('College:', style: TextStyle(fontSize: 11)),                        Text("(${(collegeSelected.length)})",                            style: TextStyle(fontSize: 11))                      ],                    ),                    Gap(5),                    MultiSelectChipDisplay(                      colorator: (value) => (collegeSelected.contains(value))                          ? Colors.green[800]                          : Colors.grey[900],                      //chipColor: Colors.blue[900],                      icon: null,                      textStyle: TextStyle(fontSize: 9, color: Colors.white),                      scrollBar: HorizontalScrollBar(),                      scroll: true,                      items: pairs                          .map((e) => e[0])                          .sortedByCompare((e) => e, collegeSort)                          .toSet()                          .map((e) => MultiSelectItem(e, "$e"))                          .toList(),                      onTap: (value) {                        setState(() {                          if (collegeSelected.contains(value)) {                            collegeSelected.remove(value);                          } else {                            collegeSelected.add(value);                          }                        });                      },                    ),                  ],                ),                MyRow(                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,                  children: [                    Gap(5),                    Column(                      children: [                        const Text('ACs:', style: TextStyle(fontSize: 11)),                        Text("(${(acSelected.length)})",                            style: TextStyle(fontSize: 11))                      ],                    ),                    Gap(5),                    MultiSelectChipDisplay(                      colorator: (value) => (acSelected.contains(value))                          ? Colors.green[800]                          : Colors.grey[900],                      //chipColor: Colors.blue[900],                      icon: null,                      textStyle: TextStyle(fontSize: 9, color: Colors.white),                      scrollBar: HorizontalScrollBar(),                      scroll: true,                      items: pairs                          .map((e) => e[1])                          .sortedByCompare((e) => e, acSort)                          .toSet()                          .map((e) => MultiSelectItem(e, "$e"))                          .toList(),                      onTap: (value) {                        setState(() {                          if (acSelected.contains(value)) {                            acSelected.remove(value);                          } else {                            acSelected.add(value);                          }                        });                      },                    ),                  ],                ),                MyRow(                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,                  children: [                    const Gap(5),                    Column(                      children: [                        const Text('Base:', style: TextStyle(fontSize: 11)),                        Text("(${(baseSelected.length)})",                            style: TextStyle(fontSize: 11))                      ],                    ),                    const Gap(5),                    MultiSelectChipDisplay(                      colorator: (value) => (baseSelected.contains(value))                          ? Colors.green[800]                          : Colors.grey[900],                      //chipColor: Colors.blue[900],                      icon: null,                      textStyle: TextStyle(fontSize: 9, color: Colors.white),                      scrollBar: HorizontalScrollBar(),                      scroll: true,                      items: pairs                          .map((e) => e[2])                          .sortedByCompare((e) => e, baseSort)                          .toSet()                          .map((e) => MultiSelectItem(e, "$e"))                          .toList(),                      onTap: (value) {                        setState(() {                          if (baseSelected.contains(value)) {                            baseSelected.remove(value);                          } else {                            baseSelected.add(value);                          }                        });                      },                    ),                  ],                ),                Padding(                  padding: const EdgeInsets.all(8.0),                  child: Column(                      children: crewPnlegFiltered                          .mapIndexed((int i, leg) {                            // print(leg);                            return {                              "index": i,                              "college": (qualif                                          .where((e) => e.tlc == leg.tlc)                                          .map((e) => e.college)                                          .sortedByCompare(                                              (e) => e ?? "", collegeSort))                                      .firstOrNull ??                                  "--",                              // "jdep": (leg.jdep?.millisecondsSinceEpoch ?? 0)                              "jdep": (leg.label ?? "0")                            };                          })                          .sortedByCompare(                              (e) => [                                    e["jdep"].toString(),                                    e["college"].toString()                                  ],                              jdepcollegeSort)                          .map<Widget>((e) {                            final x =                                crewPnlegFiltered.elementAt(e["index"] as int);                            // final pn =                            //     qualif.firstWhereOrNull((e) => e.tlc == x.tlc);                            final pn = (qualif.firstWhereOrNull((e) =>                                    (e.tlc == x.tlc) && (e.ac == x.actype)) ??                                qualif.firstWhereOrNull((e) => e.tlc == x.tlc));                            return Row(                              children: [                                Text("${e["jdep"]}"),                                WCrew(                                  college: pn?.college,                                  mle: x.tlc,                                  base: pn?.base,                                  name: "${pn?.lname}, ${pn?.fname}",                                ),                              ],                            );                          })                          .toList()),                )              ],            ),    );  }}class DutyinfoParams {  const DutyinfoParams({    this.tlc,    this.sameday = false,    this.date,    this.start,    this.end,    this.label,    this.dutytype,    this.jdep,    this.jdes,    this.dep,    this.des,  });  final String? tlc;  final bool sameday;  final Jiffy? start;  final Jiffy? end;  final String? date;  final String? label;  final String? dutytype;  final Jiffy? jdep;  final Jiffy? jdes;  final String? dep;  final String? des;}int collegeSort(String a, String b) {  // Define the order based on your requirements  final order = ['CP', 'FO', 'PU', 'SE', 'ST', 'JU'];  // Get the index of each element in the order list  final indexA = !order.contains(a) ? 99 : order.indexOf(a);  final indexB = !order.contains(b) ? 99 : order.indexOf(b);  // Compare based on the index  return indexA.compareTo(indexB);}int acSort(String a, String b) {  // Define the order based on your requirements  final order = ['320', '330', '32N', '319', '32T'];  // Get the index of each element in the order list  final indexA = !order.contains(a) ? 99 : order.indexOf(a);  final indexB = !order.contains(b) ? 99 : order.indexOf(b);  // Compare based on the index  return indexA.compareTo(indexB);}int baseSort(String a, String b) {  // Define the order based on your requirements  final order = ['TUN', 'MIR', 'DJE'];  // Get the index of each element in the order list  final indexA = !order.contains(a) ? 99 : order.indexOf(a);  final indexB = !order.contains(b) ? 99 : order.indexOf(b);  // Compare based on the index  return indexA.compareTo(indexB);}int jdepcollegeSort(List<String> a, List<String> b) {  final String x = a[0];  final String y = b[0];  final res = x.compareTo(y);  if (res == 0) {    return collegeSort(a[1], b[1]);  } else {    return res;  }}
 |