1
0

utils.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:collection/collection.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_riverpod/flutter_riverpod.dart';
  6. import 'package:intl/intl.dart';
  7. import 'package:jiffy/jiffy.dart';
  8. import 'package:path_provider/path_provider.dart';
  9. import 'package:timezone/timezone.dart' as tz;
  10. import 'package:tp5/providers/airports.dart';
  11. extension JiffyExtensions on Jiffy? {
  12. Jiffy? latest(Jiffy? val2) {
  13. if (this == null) return val2;
  14. if (val2 == null) return this;
  15. if (this!.isBefore(val2)) {
  16. return val2;
  17. } else {
  18. return this;
  19. }
  20. }
  21. Jiffy? earliset(Jiffy? val2) {
  22. if (this == null) return val2;
  23. if (val2 == null) return this;
  24. if (this!.isAfter(val2)) {
  25. return val2;
  26. } else {
  27. return this;
  28. }
  29. }
  30. Jiffy max(Jiffy val2) {
  31. if (this!.isBefore(val2)) {
  32. return val2;
  33. } else {
  34. return this!;
  35. }
  36. }
  37. Jiffy min(Jiffy val2) {
  38. if (this!.isAfter(val2)) {
  39. return val2;
  40. } else {
  41. return this!;
  42. }
  43. }
  44. Jiffy setTz({String? newtz, String? ap}) =>
  45. Jiffy.parseFromDateTime(tz.TZDateTime.from(
  46. this!.dateTime,
  47. (ap != null)
  48. ? (tz.getLocation(Airports.find(ap)?.timezoneid ?? "UTC"))
  49. : (tz.getLocation(newtz ?? "UTC"))));
  50. }
  51. extension DurationLExtensions on List<Duration> {
  52. Duration get sum => fold(
  53. Duration.zero, (p, e) => Duration(minutes: p.inMinutes + e.inMinutes));
  54. }
  55. extension DurationExtensions on Duration {
  56. Duration max(Duration value) {
  57. return Duration(
  58. milliseconds: (inMilliseconds >= value.inMilliseconds)
  59. ? inMilliseconds
  60. : value.inMilliseconds);
  61. }
  62. Duration add(Duration value) {
  63. return Duration(milliseconds: inMilliseconds + value.inMilliseconds);
  64. }
  65. Duration subtract(Duration value) {
  66. return Duration(milliseconds: inMilliseconds - value.inMilliseconds);
  67. }
  68. Duration multiply(double value) {
  69. return Duration(milliseconds: (inMilliseconds * value).ceil());
  70. }
  71. // Duration intersect(Jiffy start, Jiffy end, dynamic interval) {
  72. // if (interval is List<Jiffy> && interval.length == 2) {
  73. // if ((interval[0].isSameOrBefore(start) &&
  74. // interval[1].isSameOrBefore(start)) ||
  75. // (interval[0].isSameOrAfter(end) && interval[1].isSameOrAfter(end))) {
  76. // return Duration.zero;
  77. // } else if (interval[0].isSameOrAfter(start) &&
  78. // interval[1].isSameOrBefore(end)) {
  79. // return Duration(
  80. // minutes:
  81. // interval[1].diff(interval[0], unit: Unit.minute).toInt().abs());
  82. // } else if (interval[0].isSameOrBefore(start) &&
  83. // interval[1].isSameOrAfter(end)) {
  84. // return Duration(
  85. // minutes: start.diff(end, unit: Unit.minute).toInt().abs());
  86. // } else if (interval[0].isSameOrBefore(start) &&
  87. // interval[1].isSameOrBefore(end)) {
  88. // return Duration(
  89. // minutes: start.diff(interval[1], unit: Unit.minute).toInt().abs());
  90. // } else if (interval[0].isSameOrAfter(start) &&
  91. // interval[1].isSameOrAfter(end)) {
  92. // return Duration(
  93. // minutes: interval[0].diff(end, unit: Unit.minute).toInt().abs());
  94. // } else {
  95. // return Duration.zero;
  96. // }
  97. // } else if (interval is List<List<Jiffy>>) {
  98. // return Duration(
  99. // minutes: interval.map((e) => intersect(start, end, e).inMinutes).sum);
  100. // }
  101. // throw ("Unknown type in Duration intersect: ${interval.first.runtimeType}");
  102. // // return Duration.zero;
  103. // }
  104. String get tohhmm =>
  105. "${NumberFormat("00").format(inHours)}:${NumberFormat("00").format(inMinutes % 60)}";
  106. }
  107. extension StringExtensions on String {
  108. String capitalize() {
  109. if (isEmpty) {
  110. return this;
  111. } else {
  112. return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
  113. }
  114. }
  115. String capitalizeword() {
  116. return split(' ').map((word) => word.capitalize()).join(' ');
  117. }
  118. Jiffy? parseddmmyyyyhhmm() => length >= 15
  119. ? Jiffy.parse(
  120. "${substring(6, 10)}-${substring(3, 5)}-${substring(0, 2)} ${substring(11, 13)}:${substring(13, 15)}",
  121. pattern: 'yyyy-MM-dd HH:mm',
  122. isUtc: true)
  123. : null;
  124. Jiffy? parseyyyymmddhhmm() => length >= 16
  125. ? Jiffy.parse(this,
  126. pattern: 'yyyy-MM-dd HH:mm:ss',
  127. // "${substring(6, 10)}-${substring(3, 5)}-${substring(0, 2)} ${substring(11, 13)}${substring(13, 16)}",
  128. // pattern: 'yyyy-MM-dd HH:mm',
  129. isUtc: true)
  130. : null;
  131. }
  132. extension BuildContextExt on BuildContext {
  133. ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showAlert(
  134. String message,
  135. ) =>
  136. ScaffoldMessenger.of(this).showSnackBar(
  137. SnackBar(
  138. content: Text(
  139. message,
  140. ),
  141. duration: const Duration(milliseconds: 5000),
  142. ),
  143. );
  144. ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showError(
  145. String message,
  146. ) =>
  147. ScaffoldMessenger.of(this).showSnackBar(
  148. SnackBar(
  149. backgroundColor: Colors.red,
  150. content: Text(
  151. message,
  152. style: const TextStyle(
  153. color: Colors.white, fontWeight: FontWeight.w700),
  154. ),
  155. duration: const Duration(milliseconds: 5000),
  156. ),
  157. );
  158. ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showSuccess(
  159. String message,
  160. ) =>
  161. ScaffoldMessenger.of(this).showSnackBar(
  162. SnackBar(
  163. backgroundColor: Colors.green,
  164. content: Text(
  165. message,
  166. style: const TextStyle(
  167. color: Colors.white, fontWeight: FontWeight.w700),
  168. ),
  169. duration: const Duration(milliseconds: 5000),
  170. ),
  171. );
  172. Future<T?> showBottomSheet<T>({
  173. required Widget child,
  174. }) =>
  175. showModalBottomSheet<T>(
  176. context: this,
  177. builder: (_) => child,
  178. );
  179. }
  180. extension AlertDialogExt on AlertDialog {
  181. dynamic show(BuildContext context) => showDialog(
  182. context: context,
  183. builder: (BuildContext mycontext) => this,
  184. );
  185. }
  186. class ClockNotifier extends StateNotifier<Jiffy> {
  187. ClockNotifier() : super(Jiffy.now()) {
  188. timer = Timer.periodic(const Duration(minutes: 1), (timer) {
  189. state = Jiffy.now().toUtc();
  190. });
  191. }
  192. @override
  193. void dispose() {
  194. timer.cancel();
  195. super.dispose();
  196. }
  197. late final Timer timer;
  198. }
  199. final StateNotifierProvider<ClockNotifier, Jiffy> clockProvider =
  200. StateNotifierProvider<ClockNotifier, Jiffy>(
  201. (_) => ClockNotifier(),
  202. );
  203. class PathTo {
  204. static final PathTo _instance = PathTo._internal();
  205. factory PathTo() => _instance;
  206. PathTo._internal();
  207. late Directory _doc;
  208. Future<void> initialize() async {
  209. _doc = await getApplicationDocumentsDirectory();
  210. for (var dir in dirs) {
  211. if (!subd(dir).existsSync()) {
  212. subd(dir).createSync(recursive: true);
  213. }
  214. }
  215. }
  216. Directory subd(dynamic x) {
  217. if (x is String) {
  218. return Directory("${_doc.path}/$x");
  219. // } else if (x is Directory) {
  220. // return Directory("${_doc.path}/${x.path}");
  221. } else if (x is List<String>) {
  222. return subd(x.join("/"));
  223. } else {
  224. throw ("subd : x is not String nor List");
  225. }
  226. }
  227. final List<String> dirs = ["crewlink", "lido", "csv", "download"];
  228. String crewlinkFile(String file) => subd(["crewlink", file]).path;
  229. String csvFile(String file) => subd(["csv", file]).path;
  230. String lidoFile(String file) => subd(["lido", file]).path;
  231. String downloadFile(String file) => subd(["download", file]).path;
  232. }
  233. class DTInterval {
  234. late Jiffy start;
  235. late Jiffy end;
  236. DTInterval(this.start, this.end);
  237. @override
  238. String toString() =>
  239. "<${start.format(pattern: "ddMMMyy HH:mm")} - ${end.format(pattern: "ddMMMyy HH:mm")}>";
  240. //apartir has to be utc
  241. DTInterval.fromHm({
  242. required Jiffy apartir,
  243. required int h,
  244. required int m,
  245. required Duration duration,
  246. required String ap,
  247. }) {
  248. final Jiffy apartirCorrected = apartir.clone().setTz(ap: ap);
  249. Jiffy newval = Jiffy.parseFromDateTime(
  250. apartirCorrected.dateTime.copyWith(hour: h, minute: m));
  251. if (newval.isBefore(apartirCorrected)) newval = newval.add(days: 1);
  252. start = newval.toUtc();
  253. end = start.addDuration(duration).toUtc();
  254. }
  255. // DTInterval.fromHm({
  256. // required Jiffy apartir,
  257. // required int h,
  258. // required int m,
  259. // required Duration duration,
  260. // }) {
  261. // Jiffy newval = Jiffy.parseFromDateTime(
  262. // apartir.clone().dateTime.copyWith(hour: h, minute: m));
  263. // if (newval.isBefore(apartir)) newval = newval.add(days: 1);
  264. // start = newval;
  265. // end = start.addDuration(duration);
  266. // }
  267. bool include(Jiffy x) {
  268. return x.isSameOrAfter(start) && x.isSameOrBefore(end);
  269. }
  270. bool isOverlap(DTInterval x) {
  271. return x.start.isSameOrBefore(end) && x.end.isSameOrAfter(start);
  272. }
  273. bool contains(DTInterval x) {
  274. return include(x.start) && include(x.end);
  275. }
  276. DTInterval? intersection(DTInterval x) {
  277. if (!isOverlap(x)) {
  278. return null;
  279. } else {
  280. return DTInterval(start.max(x.start), end.min(x.end));
  281. }
  282. }
  283. List<DTInterval> intersectionmany(List<DTInterval> x) {
  284. return x.map((e) => intersection(e)).nonNulls.toList();
  285. }
  286. List<DTInterval> minus(DTInterval x) {
  287. if (!isOverlap(x)) {
  288. return [this];
  289. } else if (x.include(start) && x.include(end)) {
  290. return [];
  291. } else if (x.include(start)) {
  292. return [DTInterval(x.end, end)];
  293. } else if (x.include(end)) {
  294. return [DTInterval(start, x.start)];
  295. } else {
  296. return [DTInterval(start, x.start), DTInterval(x.end, end)];
  297. }
  298. }
  299. // List<DTInterval> minus(DTInterval other) {
  300. // List<DTInterval> result = [];
  301. // if (start.isBefore(other.start) && end.isAfter(other.start)) {
  302. // result.add(DTInterval(start, other.start));
  303. // }
  304. // if (start.isBefore(other.end) && end.isAfter(other.end)) {
  305. // result.add(DTInterval(other.end, end));
  306. // }
  307. // return result;
  308. // }
  309. List<DTInterval> minusmany(List<DTInterval> x) {
  310. List<DTInterval> res = [this];
  311. for (var e in x) {
  312. res = res.map((f) => f.minus(e)).flattened.toList();
  313. }
  314. return res;
  315. }
  316. Duration get duration => end.dateTime.difference(start.dateTime);
  317. // Duration get duration => Duration(
  318. // milliseconds: end.diff(start, unit: Unit.millisecond).abs().ceil());
  319. bool isEmpty() {
  320. return start.isSameOrAfter(end);
  321. }
  322. DTInterval toUtc() {
  323. return DTInterval(start.toUtc(), end.toUtc());
  324. }
  325. }