w_flt.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:gap/gap.dart';
  4. import 'package:google_fonts/google_fonts.dart';
  5. import 'package:linear_progress_bar/linear_progress_bar.dart';
  6. import 'package:tp5/core/utils.dart';
  7. import 'package:tp5/csv/data.dart';
  8. import 'package:tp5/roster/widgets/w_citypair.dart';
  9. import 'package:tp5/roster/widgets/w_hour.dart';
  10. import 'package:tp5/widgets/my_row.dart';
  11. class WFlt extends ConsumerWidget {
  12. const WFlt(
  13. {super.key,
  14. required this.acleg,
  15. this.hide = const [],
  16. this.highlight = false});
  17. final List<String> hide;
  18. final bool highlight;
  19. final Acleg acleg;
  20. String get fltstate {
  21. if (acleg.flt_status == "Arrived" || acleg.flt_status == "Landed") {
  22. return "ARR";
  23. } else if (acleg.flt_status == "Inflight" ||
  24. acleg.flt_status == "Taxiout") {
  25. return "DEP";
  26. } else if (acleg.flt_status == "Delayed") {
  27. return "DEL";
  28. } else if (acleg.flt_status == "Sched") {
  29. return "SCD";
  30. } else {
  31. return "UNK";
  32. }
  33. }
  34. aclegicon() {
  35. if (fltstate == "DEP") {
  36. return Icons.flight_takeoff_rounded;
  37. } else if (fltstate == "ARR") {
  38. return Icons.flight_land_rounded;
  39. } else if (fltstate == "DEL") {
  40. return Icons.timer;
  41. } else if (fltstate == "SCD") {
  42. return Icons.check_rounded;
  43. } else {
  44. return Icons.device_unknown;
  45. }
  46. }
  47. Color aclegcolor() {
  48. if (fltstate == "DEP") {
  49. return Colors.black;
  50. } else if (fltstate == "ARR") {
  51. return Colors.black;
  52. } else if (fltstate == "DEL") {
  53. return Colors.grey[900]!;
  54. } else if (fltstate == "SCD") {
  55. return Colors.grey[900]!;
  56. } else {
  57. return Colors.yellow[900]!;
  58. }
  59. }
  60. @override
  61. Widget build(BuildContext context, WidgetRef ref) {
  62. final now = ref.watch(clockProvider);
  63. return Card(
  64. color: aclegcolor(),
  65. // surfaceTintColor: (fltstate == "DEP") ? Colors.white : null,
  66. shape: RoundedRectangleBorder(
  67. borderRadius: BorderRadius.circular(5.0), // Rounded corners
  68. side: BorderSide(
  69. color: highlight ? Colors.yellow : Colors.transparent, // Border color
  70. width: 2.0, // Border width
  71. ),
  72. ),
  73. elevation: 8.0,
  74. //margin: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 4.0),
  75. child: Column(
  76. children: [
  77. Padding(
  78. padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 0),
  79. child: MyRow(children: [
  80. if (!hide.contains("leading")) _leading(),
  81. if (!hide.contains("timing")) _timing(),
  82. if (!hide.contains("flight")) _flight(),
  83. if (!hide.contains("actype")) _actype(),
  84. if (!hide.contains("booking")) _booking(),
  85. if (!hide.contains("delay")) _delay(),
  86. ]),
  87. ),
  88. if (fltstate == "DEP" && now.isBefore(acleg.jarr!))
  89. Row(children: [
  90. const Gap(60),
  91. Text(
  92. "departed\n${now.dateTime.difference(acleg.jdep!.dateTime).tohhmm} ago",
  93. style: const TextStyle(
  94. fontSize: 9, letterSpacing: 1, color: Colors.grey),
  95. ),
  96. const Gap(5),
  97. Expanded(
  98. child: LinearProgressBar(
  99. maxSteps: acleg.jarr!.dateTime
  100. .difference(acleg.jdep!.dateTime)
  101. .inMinutes,
  102. progressType: LinearProgressBar
  103. .progressTypeLinear, // Use Linear progress
  104. currentStep:
  105. now.dateTime.difference(acleg.jdep!.dateTime).inMinutes,
  106. progressColor: Colors.cyan,
  107. backgroundColor: Colors.grey[700],
  108. borderRadius: BorderRadius.circular(10), // NEW
  109. ),
  110. ),
  111. const Gap(5),
  112. Text(
  113. "arrives\nin ${acleg.jarr!.dateTime.difference(now.dateTime).tohhmm}",
  114. style: const TextStyle(
  115. fontSize: 9, letterSpacing: 1, color: Colors.grey),
  116. ),
  117. const Gap(5)
  118. ]),
  119. const Gap(2),
  120. ],
  121. ),
  122. );
  123. }
  124. _leading() => SizedBox(
  125. width: 50,
  126. child: Padding(
  127. padding: const EdgeInsets.all(4.0),
  128. child: Column(children: [
  129. Icon(aclegicon()),
  130. Text(
  131. acleg.flt_status,
  132. style: const TextStyle(fontSize: 9),
  133. )
  134. ]),
  135. ),
  136. );
  137. _flight() => SizedBox(
  138. width: 100,
  139. child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
  140. WCitypair(
  141. iata1: acleg.DEP_AP_ACTUAL ?? "---",
  142. iata2: acleg.ARR_AP_SCHED ?? "---",
  143. size: 14,
  144. color:
  145. (acleg.ARR_AP_ACTUAL == acleg.ARR_AP_SCHED) ? null : Colors.red,
  146. ),
  147. MyRow(
  148. children: [
  149. Text(
  150. "${acleg.FN_CARRIER}${acleg.FN_NUMBER ?? "---"}${acleg.FN_SUFFIX ?? ""}",
  151. style: const TextStyle(color: Colors.white70, fontSize: 12)),
  152. const Gap(10),
  153. if (acleg.ARR_AP_ACTUAL != acleg.ARR_AP_SCHED &&
  154. acleg.DEP_AP_ACTUAL != acleg.ARR_AP_ACTUAL &&
  155. acleg.blocks[1] != null)
  156. Column(
  157. crossAxisAlignment: CrossAxisAlignment.center,
  158. children: [
  159. const Text("Diverted to",
  160. style: TextStyle(color: Colors.red, fontSize: 9)),
  161. Text(acleg.ARR_AP_ACTUAL ?? "---",
  162. style: const TextStyle(
  163. color: Colors.yellow,
  164. fontSize: 12,
  165. fontWeight: FontWeight.w600)),
  166. ],
  167. ),
  168. if (acleg.ARR_AP_ACTUAL != acleg.ARR_AP_SCHED &&
  169. acleg.DEP_AP_ACTUAL == acleg.ARR_AP_ACTUAL)
  170. Column(
  171. crossAxisAlignment: CrossAxisAlignment.center,
  172. children: [
  173. Text(
  174. (acleg.blocks[1] != null)
  175. ? "Flight back to"
  176. : "Return to",
  177. style: const TextStyle(color: Colors.red, fontSize: 9)),
  178. Text(acleg.ARR_AP_ACTUAL ?? "---",
  179. style: const TextStyle(
  180. color: Colors.yellow,
  181. fontSize: 12,
  182. fontWeight: FontWeight.w600)),
  183. ],
  184. ),
  185. ],
  186. ),
  187. ]),
  188. );
  189. _actype() => SizedBox(
  190. width: 60,
  191. child: Column(
  192. crossAxisAlignment: CrossAxisAlignment.start,
  193. children: [
  194. Text(acleg.AC_REGISTRATION ?? "-----",
  195. style: TextStyle(
  196. color: Colors.yellow[800]!, fontWeight: FontWeight.w700)),
  197. Row(
  198. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  199. children: [
  200. Text(acleg.AC_SUBTYPE ?? "---",
  201. style: const TextStyle(
  202. fontSize: 12,
  203. color: Colors.grey,
  204. fontWeight: FontWeight.w500)),
  205. Text(acleg.AC_OWNER ?? "---",
  206. style: TextStyle(
  207. fontSize: 12,
  208. color: Colors.grey[400]!,
  209. fontWeight: FontWeight.w500)),
  210. ],
  211. )
  212. ],
  213. ),
  214. );
  215. _booking() => SizedBox(
  216. width: 60,
  217. child: Column(
  218. crossAxisAlignment: CrossAxisAlignment.center,
  219. children: [
  220. Text(
  221. acleg.pax_booked ?? "---",
  222. style: GoogleFonts.robotoMono(
  223. fontSize: 11, fontWeight: FontWeight.w300),
  224. ),
  225. Text(
  226. acleg.AC_VERSION ?? "---",
  227. style: GoogleFonts.robotoMono(
  228. color: Colors.grey, fontSize: 9, fontWeight: FontWeight.w300),
  229. ),
  230. ],
  231. ),
  232. );
  233. _timing() => SizedBox(
  234. width: 80,
  235. child: Column(
  236. crossAxisAlignment: CrossAxisAlignment.start,
  237. children: [
  238. Text(
  239. acleg.jdep!.format(pattern: "dd MMM 'yy"),
  240. style: const TextStyle(fontSize: 11, color: Colors.grey),
  241. ),
  242. Row(
  243. children: [
  244. WHour(jiffy: acleg.jdep!, size: 13),
  245. const Gap(10),
  246. WHour(jiffy: acleg.jarr!, size: 13)
  247. ],
  248. ),
  249. if (acleg.jdep!.isAfter(acleg.jdepsched!.add(minutes: 15)))
  250. Row(
  251. mainAxisAlignment: MainAxisAlignment.end,
  252. children: [
  253. Text(
  254. "Delay ",
  255. style: GoogleFonts.robotoMono(
  256. fontSize: 10,
  257. fontWeight: FontWeight.w400,
  258. color: Colors.red[600]),
  259. ),
  260. Padding(
  261. padding: const EdgeInsets.only(right: 8),
  262. child: Text(
  263. acleg.jdep!.dateTime
  264. .difference(acleg.jdepsched!.dateTime)
  265. .tohhmm,
  266. style: GoogleFonts.robotoMono(
  267. fontSize: 10,
  268. fontWeight: FontWeight.w400,
  269. color: Colors.red[200]),
  270. ),
  271. )
  272. ],
  273. ),
  274. if (acleg.slot != null && acleg.slot!.year > 2000)
  275. Row(
  276. mainAxisAlignment: MainAxisAlignment.end,
  277. children: [
  278. Text(
  279. "CTOT ",
  280. style: GoogleFonts.robotoMono(
  281. fontSize: 10,
  282. fontWeight: FontWeight.w600,
  283. color: Colors.amber),
  284. ),
  285. Padding(
  286. padding: const EdgeInsets.only(right: 8),
  287. child: Text(
  288. acleg.slot!.Hm,
  289. style: GoogleFonts.robotoMono(
  290. fontSize: 10,
  291. fontWeight: FontWeight.w400,
  292. color: Colors.amber),
  293. ),
  294. )
  295. ],
  296. ),
  297. ],
  298. ),
  299. );
  300. _delay() => SizedBox(
  301. width: 60,
  302. child: Column(
  303. children: [
  304. if (acleg.dla.isNotEmpty) ...[
  305. const Text("DLA",
  306. style: TextStyle(fontSize: 10, color: Colors.grey)),
  307. ...acleg.dla.map((e) => Text(
  308. "${e[0]} = ${e[1] is Duration ? ((e[1] as Duration).tohhmm) : ""}",
  309. style: const TextStyle(fontSize: 10),
  310. ))
  311. ]
  312. ],
  313. ));
  314. }