lidolist_page.dart 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. import 'dart:io';
  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:jiffy/jiffy.dart';
  7. import 'package:path_provider/path_provider.dart';
  8. import 'package:scroll_to_index/scroll_to_index.dart';
  9. import 'package:tp5/core/basic_page.dart';
  10. import 'package:tp5/core/utils.dart';
  11. import 'package:tp5/lido/lido_api.dart';
  12. import 'package:tp5/lido/model/Lidoapi_list.dart';
  13. import 'package:tp5/lido/w_lidoflt.dart';
  14. import 'package:tp5/pdf/pdf_page.dart';
  15. class LidolistPage extends ConsumerStatefulWidget {
  16. const LidolistPage({super.key, required this.params});
  17. final LidolistPageParams params;
  18. @override
  19. ConsumerState<ConsumerStatefulWidget> createState() => _LidolistPageState();
  20. }
  21. class _LidolistPageState extends ConsumerState<LidolistPage> {
  22. final bottomnavstyle = ElevatedButton.styleFrom(
  23. shape: RoundedRectangleBorder(
  24. borderRadius: BorderRadius.circular(5.0),
  25. ),
  26. backgroundColor:
  27. const Color.fromARGB(255, 0, 36, 53) //elevated btton background color
  28. );
  29. final AutoScrollController _scrollCtrl = AutoScrollController();
  30. List<LidoapiList> legs = <LidoapiList>[];
  31. _scrollToDate({Jiffy? date}) {
  32. final jdate = date ?? Jiffy.now().toUtc();
  33. bool found = false;
  34. int id = 0;
  35. for (var leg in legs) {
  36. if (Jiffy.parseFromMillisecondsSinceEpoch(
  37. leg.leg?.estimatedDepartureTime ?? 0,
  38. isUtc: true)
  39. .isSameOrAfter(jdate.subtract(hours: 1))) {
  40. found = true;
  41. break;
  42. }
  43. id++;
  44. }
  45. Future.delayed(const Duration(milliseconds: 100)).then((value) {
  46. if (found && mounted && _scrollCtrl.hasClients) {
  47. _scrollCtrl.scrollToIndex(id,
  48. duration: const Duration(milliseconds: 1300),
  49. preferPosition: AutoScrollPosition.begin);
  50. }
  51. });
  52. }
  53. @override
  54. void initState() {
  55. Future.delayed(Duration.zero).then((x) async {
  56. // print(await ref
  57. // .read(lidoapiProvider)
  58. // .login(user: "TAR13176", pass: "FaresWiem08_a"));
  59. ref.read(isLoadingProvider.notifier).state = true;
  60. final out = await ref.read(lidoapiProvider).list(
  61. start: widget.params.datestart,
  62. end: widget.params.dateend,
  63. dep: widget.params.dep ?? "",
  64. des: widget.params.des ?? "",
  65. al: widget.params.al ?? "",
  66. fnum: widget.params.fnum ?? "",
  67. );
  68. if ((out["error"] == null && out["data"] is List) ||
  69. (out["cache"] != null)) {
  70. final data =
  71. (out["error"] == null ? out["data"] : (out["cache"])["data"]);
  72. legs.clear();
  73. for (var e in data ?? []) {
  74. //print(e);
  75. legs.add(LidoapiList.fromJson(e));
  76. }
  77. } else {
  78. context.showError(out["error"]);
  79. }
  80. setState(() {});
  81. ref.read(isLoadingProvider.notifier).state = false;
  82. _scrollToDate();
  83. //print("Lidolistpage: out= $out");
  84. // print((LidoapiList.fromJson(out["data"][0])));
  85. // writeStringToFile("${out["data"][0]}");
  86. });
  87. super.initState();
  88. }
  89. Future<void> writeStringToFile(String content) async {
  90. try {
  91. final directory = await getApplicationDocumentsDirectory();
  92. final file = File('${directory.path}/lidoapilist.txt');
  93. // Write the content to the file
  94. await file.writeAsString(content);
  95. print('Content written to file: ${file.path}');
  96. } catch (e) {
  97. print('Error writing to file: $e');
  98. }
  99. }
  100. @override
  101. Widget build(BuildContext context) {
  102. // final now = ref.watch(clockProvider);
  103. return BasicPage(
  104. actions: [
  105. IconButton(
  106. onPressed: () => context.push("/lido/settings"),
  107. icon: const Icon(Icons.settings)),
  108. const Gap(10)
  109. ],
  110. bottomNavigationBar: Container(
  111. padding: const EdgeInsets.all(8),
  112. // color: Colors.black,
  113. decoration: BoxDecoration(
  114. gradient: LinearGradient(
  115. begin: Alignment.topCenter,
  116. end: Alignment.bottomCenter,
  117. colors: [
  118. Colors.grey[700]!,
  119. Colors.black,
  120. ],
  121. )),
  122. child: Row(
  123. mainAxisAlignment: MainAxisAlignment.spaceAround,
  124. children: [
  125. ElevatedButton.icon(
  126. onPressed: () {
  127. _changeDay(context);
  128. },
  129. icon: const Icon(
  130. Icons.calendar_month), //icon data for elevated button
  131. label: const Text("Change\n Day"), //label text
  132. style: bottomnavstyle,
  133. ),
  134. const Gap(10),
  135. ElevatedButton.icon(
  136. onPressed: () {
  137. _searchFlights(context);
  138. },
  139. icon: const Icon(Icons.manage_search),
  140. label: const Text("Search\nFlights"),
  141. style: bottomnavstyle,
  142. ),
  143. const Gap(10), //icon data for elevated button
  144. ],
  145. ),
  146. ),
  147. title: "Lido / List",
  148. body: ListView.builder(
  149. itemCount: legs.length,
  150. itemBuilder: (_, index) => AutoScrollTag(
  151. key: ValueKey(index),
  152. controller: _scrollCtrl,
  153. index: index,
  154. child: _getItem(_, index)),
  155. shrinkWrap: true,
  156. controller: _scrollCtrl,
  157. ),
  158. );
  159. }
  160. int? _loadingOFP;
  161. _getItem(BuildContext buildContext, int index) {
  162. return InkWell(
  163. onTap: () async {
  164. final legid = legs[index].briefingId ?? "";
  165. if (_loadingOFP == null) {
  166. setState(() {
  167. _loadingOFP = index;
  168. });
  169. final ofp = await ref.read(lidoapiProvider).ofppdf(legid: legid);
  170. setState(() {
  171. _loadingOFP = null;
  172. });
  173. if (((ofp["data"] is Map) &&
  174. (ofp["data"]?["downloaded"] ?? false) == true) ||
  175. (ofp["cache"] != null)) {
  176. context.push("/pdf",
  177. extra: PdfPageParams(
  178. file: ofp["cache"] ?? ofp["data"]?["fileid"] ?? "",
  179. title: legid,
  180. initialZoom: 1));
  181. } else {
  182. context.showError("Cannot download PDF File !!!");
  183. }
  184. }
  185. },
  186. child:
  187. // Text("${legs[index].leg?.departureAirportIcao} ${legs[index].leg?.destinationAirportIcao} ${legs[index].leg?.flightNumber} ${Jiffy.parseFromMillisecondsSinceEpoch(legs[index].leg?.estimatedDepartureTime ?? 0, isUtc: true).format(pattern: "ddMMMyy HHmm")} ${Jiffy.parseFromMillisecondsSinceEpoch(legs[index].leg?.scheduledDepartureTime ?? 0, isUtc: true).format(pattern: "ddMMMyy HHmm")} ${legs[index].leg?.fuel?.blockFuel}"),
  188. Row(children: [
  189. if (_loadingOFP == index) const CircularProgressIndicator(),
  190. Expanded(child: WLidoflt(lidoapilist: legs[index]))
  191. ]));
  192. }
  193. void _changeDay(BuildContext context) {}
  194. TextEditingController ctrldep = TextEditingController();
  195. TextEditingController ctrldes = TextEditingController();
  196. TextEditingController ctrlairline = TextEditingController();
  197. TextEditingController ctrlfnum = TextEditingController();
  198. TextEditingController ctrlstartdate = TextEditingController();
  199. TextEditingController ctrlenddate = TextEditingController();
  200. void _searchFlights(xcontext) async {
  201. ref.read(isLoadingProvider.notifier).state = true;
  202. ref.read(isLoadingProvider.notifier).state = false;
  203. ctrldep.text = widget.params.dep ?? "";
  204. ctrldes.text = widget.params.des ?? "";
  205. ctrlairline.text = widget.params.al ?? "";
  206. ctrlfnum.text = widget.params.fnum ?? "";
  207. ctrlstartdate.text =
  208. widget.params.datestart?.format(pattern: "ddMMMyy") ?? "";
  209. ctrlenddate.text = widget.params.dateend?.format(pattern: "ddMMMyy") ?? "";
  210. final res = await showModalBottomSheet(
  211. context: context,
  212. builder: (context) => _searchFilter(xcontext, null, null));
  213. if (res is LidolistPageParams) context.push("/lido/list", extra: res);
  214. }
  215. Widget _searchFilter(BuildContext context, DateTime? min, DateTime? max) {
  216. min = min ?? DateTime.now().subtract(const Duration(days: 7));
  217. max = max ?? DateTime.now().add(const Duration(days: 7));
  218. return Container(
  219. padding: const EdgeInsets.all(20),
  220. child: Column(
  221. mainAxisSize: MainAxisSize.min,
  222. children: [
  223. Row(
  224. children: [
  225. Expanded(
  226. child: TextField(
  227. decoration:
  228. const InputDecoration(labelText: "Departure Airport"),
  229. maxLength: 3, // Set maximum length
  230. controller: ctrldep,
  231. ),
  232. ),
  233. const SizedBox(width: 10),
  234. Expanded(
  235. child: TextField(
  236. decoration:
  237. const InputDecoration(labelText: "Arrival Airport"),
  238. maxLength: 3, // Set maximum length
  239. controller: ctrldes,
  240. ),
  241. ),
  242. ],
  243. ),
  244. const SizedBox(height: 15),
  245. Row(
  246. children: [
  247. Expanded(
  248. child: TextField(
  249. controller: ctrlairline,
  250. decoration:
  251. const InputDecoration(labelText: "Airline IATA code"),
  252. maxLength: 2, // Set maximum length
  253. ),
  254. ),
  255. const SizedBox(width: 10),
  256. Expanded(
  257. child: TextField(
  258. controller: ctrlfnum,
  259. decoration: const InputDecoration(labelText: "Flight number"),
  260. maxLength: 6, // Set maximum length
  261. ),
  262. ),
  263. ],
  264. ),
  265. const SizedBox(height: 15),
  266. Row(
  267. children: [
  268. Expanded(
  269. child: TextField(
  270. decoration:
  271. const InputDecoration(labelText: "Starting date"),
  272. controller: ctrlstartdate,
  273. readOnly:
  274. true, //set it true, so that user will not able to edit text
  275. onTap: () async {
  276. DateTime? pickedDate = await showDatePicker(
  277. context: context,
  278. initialDate: DateTime.now().toUtc(),
  279. firstDate:
  280. min!, //DateTime.now () - not to allow to choose before today.
  281. lastDate: max!);
  282. if (pickedDate != null) {
  283. String formattedDate =
  284. Jiffy.parseFromDateTime(pickedDate).format(
  285. pattern:
  286. "ddMMMyy"); //formatted date output using intl package => 2021-03-16
  287. setState(() {
  288. ctrlstartdate.text = formattedDate;
  289. if (ctrlenddate.text == "" ||
  290. Jiffy.parseFromDateTime(pickedDate).isAfter(
  291. Jiffy.parse(ctrlenddate.text,
  292. pattern: "ddMMMyy", isUtc: true))) {
  293. ctrlenddate.text = formattedDate;
  294. }
  295. });
  296. } else {
  297. print("Date is not selected");
  298. }
  299. }),
  300. ),
  301. const SizedBox(width: 10),
  302. Expanded(
  303. child: TextField(
  304. decoration: const InputDecoration(labelText: "Ending date"),
  305. controller: ctrlenddate,
  306. readOnly:
  307. true, //set it true, so that user will not able to edit text
  308. onTap: () async {
  309. DateTime? pickedDate = await showDatePicker(
  310. context: context,
  311. initialDate: DateTime.now().toUtc(),
  312. firstDate: min!,
  313. lastDate: max!);
  314. if (pickedDate != null) {
  315. String formattedDate =
  316. Jiffy.parseFromDateTime(pickedDate)
  317. .format(pattern: "ddMMMyy");
  318. setState(() {
  319. ctrlenddate.text = formattedDate;
  320. if (ctrlstartdate.text == "" ||
  321. Jiffy.parseFromDateTime(pickedDate).isBefore(
  322. Jiffy.parse(ctrlstartdate.text,
  323. pattern: "ddMMMyy", isUtc: true))) {
  324. ctrlstartdate.text = formattedDate;
  325. }
  326. });
  327. } else {
  328. print("Date is not selected");
  329. }
  330. }),
  331. ),
  332. ],
  333. ),
  334. const SizedBox(height: 35),
  335. SizedBox(
  336. width: 360,
  337. child: ElevatedButton(
  338. onPressed: () async =>
  339. // await context.push("/lido/list",
  340. // extra: LidolistPageParams(
  341. // dep: ctrldep.text.toUpperCase(),
  342. // des: ctrldes.text.toUpperCase(),
  343. // al: ctrlairline.text.toUpperCase(),
  344. // fnum: ctrlfnum.text,
  345. // datestart: ctrlstartdate.text,
  346. // dateend: ctrlenddate.text,
  347. // )),
  348. Navigator.pop(
  349. context,
  350. LidolistPageParams(
  351. dep: ctrldep.text.toUpperCase(),
  352. des: ctrldes.text.toUpperCase(),
  353. al: ctrlairline.text.toUpperCase(),
  354. fnum: ctrlfnum.text,
  355. datestart: ctrlstartdate.text == ""
  356. ? null
  357. : Jiffy.parse(ctrlstartdate.text,
  358. pattern: "ddMMMyy", isUtc: true),
  359. dateend: ctrlenddate.text == ""
  360. ? null
  361. : Jiffy.parse(ctrlenddate.text,
  362. pattern: "ddMMMyy", isUtc: true),
  363. )), // Close the bottom sheet
  364. style: ElevatedButton.styleFrom(
  365. backgroundColor: Colors.green, // Set button color to green
  366. shape: RoundedRectangleBorder(
  367. borderRadius:
  368. BorderRadius.circular(15), // Add rounded corners
  369. ),
  370. padding:
  371. const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
  372. ),
  373. child: const Text(
  374. 'Search Flights',
  375. style: TextStyle(fontSize: 18, color: Colors.white),
  376. ),
  377. ),
  378. ),
  379. ],
  380. ),
  381. );
  382. }
  383. _titleInfo(String? title, String? info,
  384. {double sizetitle = 10,
  385. double sizeinfo = 16,
  386. Color color = Colors.blueGrey}) =>
  387. Column(
  388. children: [
  389. Text(
  390. title ?? "---",
  391. style: TextStyle(color: Colors.grey, fontSize: sizetitle),
  392. ),
  393. Text(info ?? "---",
  394. style: TextStyle(color: color, fontSize: sizeinfo)),
  395. ],
  396. );
  397. }
  398. class LidolistPageParams {
  399. const LidolistPageParams({
  400. this.dateend,
  401. this.datestart,
  402. this.dep,
  403. this.des,
  404. this.al,
  405. this.fnum,
  406. this.lidouser,
  407. this.lidopass,
  408. });
  409. final Jiffy? dateend;
  410. final Jiffy? datestart;
  411. final String? dep;
  412. final String? des;
  413. final String? al;
  414. final String? fnum;
  415. final String? lidouser;
  416. final String? lidopass;
  417. }