lidolist_page.dart 16 KB

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