Fares 11 kuukautta sitten
vanhempi
sitoutus
3b180f6a94
44 muutettua tiedostoa jossa 415 lisäystä ja 11648 poistoa
  1. 7 1
      android/app/src/main/AndroidManifest.xml
  2. 3 0
      android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml
  3. BIN
      android/app/src/main/res/mipmap-hdpi/launcher_icon.png
  4. BIN
      android/app/src/main/res/mipmap-mdpi/launcher_icon.png
  5. BIN
      android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
  6. BIN
      android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
  7. BIN
      android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
  8. BIN
      assets/logo.png
  9. BIN
      assets/oldlogo.png
  10. 0 25
      lib/auth/api/auth_repository.dart
  11. 0 25
      lib/auth/api/auth_repository.g.dart
  12. 0 3
      lib/auth/auth.dart
  13. 0 13
      lib/auth/providers/auth_user.dart
  14. 0 24
      lib/auth/providers/auth_user.g.dart
  15. 0 238
      lib/auth/view/login_page.dart
  16. 0 238
      lib/auth/view/signup_page.dart
  17. 4 15
      lib/authpages/auth_magiclink.dart
  18. 201 0
      lib/authpages/login_otp.dart
  19. 1 0
      lib/authpages/signup.dart
  20. 48 24
      lib/core/routes.dart
  21. 0 1539
      lib/csv/data copy.dart.bak
  22. 0 1717
      lib/csv/data.bak
  23. 0 175
      lib/flightslist/flightslist_page.dart.bak2
  24. 0 37
      lib/fltinfo/view/datatable.dart.bak
  25. 13 20
      lib/fltinfo/view/dutyinfo_page.dart
  26. 11 4
      lib/fltinfo/view/fltinfo_page.dart
  27. 0 1441
      lib/ftl/provider/ftl copy.dart.bak
  28. 0 1467
      lib/ftl/provider/ftl copy2.dart.bak
  29. 0 1557
      lib/ftl/provider/ftl copy3.dart.bak
  30. 0 787
      lib/ftl/view/ftl_page copy.dart.bak
  31. 0 441
      lib/lido/api_lido4d copy.dart.bak
  32. 1 1
      lib/lido/lido_api.dart
  33. 0 1
      lib/onboarding/onboarding.dart
  34. 0 154
      lib/onboarding/view/verification_page.dart
  35. 6 0
      lib/roster/api/crewlink_api.dart
  36. 0 454
      lib/roster/view/roster_page copy.dart.bak
  37. 50 0
      lib/roster/view/roster_page.dart
  38. 0 375
      lib/rosters/rosters_page.bak2
  39. 0 744
      lib/rosters/rosters_page.bak3
  40. 8 7
      lib/rosters/rosters_page.dart
  41. 16 5
      lib/widgets/nav_drawer.dart
  42. 34 114
      pubspec.lock
  43. 12 2
      pubspec.yaml
  44. BIN
      windows/runner/resources/app_icon.ico

+ 7 - 1
android/app/src/main/AndroidManifest.xml

@@ -8,7 +8,7 @@
     <application
         android:label="tp5"
         android:name="${applicationName}"
-        android:icon="@mipmap/ic_launcher">
+        android:icon="@mipmap/launcher_icon">
         <activity
             android:name=".MainActivity"
             android:exported="true"
@@ -30,6 +30,12 @@
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
+            <intent-filter android:autoVerify="true">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="com.example.tp5" android:host="magic-link" />
+            </intent-filter>
         </activity>
         <!-- Don't delete the meta-data below.
              This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->

+ 3 - 0
android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml

@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+</adaptive-icon>

BIN
android/app/src/main/res/mipmap-hdpi/launcher_icon.png


BIN
android/app/src/main/res/mipmap-mdpi/launcher_icon.png


BIN
android/app/src/main/res/mipmap-xhdpi/launcher_icon.png


BIN
android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png


BIN
android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png


BIN
assets/logo.png


BIN
assets/oldlogo.png


+ 0 - 25
lib/auth/api/auth_repository.dart

@@ -1,25 +0,0 @@
-import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:supabase_flutter/supabase_flutter.dart';
-
-part 'auth_repository.g.dart';
-
-@riverpod
-AuthRepository authRepository(AuthRepositoryRef _) => AuthRepository();
-
-class AuthRepository {
-  final _client = Supabase.instance.client;
-
-  Stream<AuthState> get authState => _client.auth.onAuthStateChange;
-
-  Future<AuthResponse> logIn({
-    required String email,
-    required String password,
-  }) async {
-    return _client.auth.signInWithPassword(
-      email: email,
-      password: password,
-    );
-  }
-
-  Future<void> logout() => _client.auth.signOut();
-}

+ 0 - 25
lib/auth/api/auth_repository.g.dart

@@ -1,25 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'auth_repository.dart';
-
-// **************************************************************************
-// RiverpodGenerator
-// **************************************************************************
-
-String _$authRepositoryHash() => r'7a5e497d6eb8c4c1f189e277e25a7a1d9bae8433';
-
-/// See also [authRepository].
-@ProviderFor(authRepository)
-final authRepositoryProvider = AutoDisposeProvider<AuthRepository>.internal(
-  authRepository,
-  name: r'authRepositoryProvider',
-  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
-      ? null
-      : _$authRepositoryHash,
-  dependencies: null,
-  allTransitiveDependencies: null,
-);
-
-typedef AuthRepositoryRef = AutoDisposeProviderRef<AuthRepository>;
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

+ 0 - 3
lib/auth/auth.dart

@@ -1,3 +0,0 @@
-export 'api/auth_repository.dart';
-export 'providers/auth_user.dart';
-export 'view/login_page.dart';

+ 0 - 13
lib/auth/providers/auth_user.dart

@@ -1,13 +0,0 @@
-import 'package:tp5/auth/auth.dart';
-import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:supabase_flutter/supabase_flutter.dart';
-
-part 'auth_user.g.dart';
-
-@riverpod
-Stream<User?> authUser(AuthUserRef ref) async* {
-  final authStream = ref.read(authRepositoryProvider).authState;
-  await for (final authState in authStream) {
-    yield authState.session?.user;
-  }
-}

+ 0 - 24
lib/auth/providers/auth_user.g.dart

@@ -1,24 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'auth_user.dart';
-
-// **************************************************************************
-// RiverpodGenerator
-// **************************************************************************
-
-String _$authUserHash() => r'2ef9e300270e1713a88dd02760e11f302633e843';
-
-/// See also [authUser].
-@ProviderFor(authUser)
-final authUserProvider = AutoDisposeStreamProvider<User?>.internal(
-  authUser,
-  name: r'authUserProvider',
-  debugGetCreateSourceHash:
-      const bool.fromEnvironment('dart.vm.product') ? null : _$authUserHash,
-  dependencies: null,
-  allTransitiveDependencies: null,
-);
-
-typedef AuthUserRef = AutoDisposeStreamProviderRef<User?>;
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

+ 0 - 238
lib/auth/view/login_page.dart

@@ -1,238 +0,0 @@
-// ignore_for_file: use_build_context_synchronously
-
-import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:go_router/go_router.dart';
-import 'package:tp5/auth/auth.dart';
-import 'package:tp5/core/core.dart';
-import 'package:tp5/core/my_theme.dart';
-import 'package:tp5/onboarding/onboarding.dart';
-
-class LoginPage extends ConsumerStatefulWidget {
-  const LoginPage({super.key});
-
-  @override
-  ConsumerState<LoginPage> createState() => _LoginPageState();
-}
-
-class _LoginPageState extends ConsumerState<LoginPage> {
-  final _formKey = GlobalKey<FormState>();
-  AutovalidateMode? _autovalidateMode;
-  bool _isSubmitting = false;
-
-  final _emailCtrl = TextEditingController();
-  final _passwordCtrl = TextEditingController();
-  final _usernameCtrl = TextEditingController();
-
-  Future<void> _login() async {
-    try {
-      setState(() {
-        _isSubmitting = true;
-      });
-
-      await ref.read(authRepositoryProvider).logIn(
-            email: _emailCtrl.text,
-            password: _passwordCtrl.text,
-          );
-
-      if (mounted) {
-        context.pop();
-      }
-    } catch (e) {
-      setState(() {
-        _isSubmitting = false;
-      });
-
-      context.showAlert(e.toString());
-    }
-  }
-
-  Future<void> _createAccount() async {
-    try {
-      setState(() {
-        _isSubmitting = true;
-      });
-
-      await ref.read(onboardingRepositoryProvider).signUp(
-            email: _emailCtrl.text,
-            password: _passwordCtrl.text,
-            username: _usernameCtrl.text,
-          );
-
-      if (mounted) {
-        context.push(
-          '/verification',
-          extra: VerificationPageParams(
-            email: _emailCtrl.text,
-            password: _passwordCtrl.text,
-            username: _usernameCtrl.text,
-          ),
-        );
-      }
-    } catch (e) {
-      context.showAlert(e.toString());
-    }
-
-    setState(() {
-      _isSubmitting = false;
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    final isDarkMode = ref.watch(appThemeProvider);
-
-    return Scaffold(
-      appBar: AppBar(
-        title: Row(
-          children: [
-            const Text("GeeksforGeeks"),
-            Switch(
-                activeColor: Colors.orange,
-                onChanged: (value) {
-                  ref.read(appThemeProvider.notifier).state = value;
-                },
-                value: isDarkMode)
-          ],
-        ),
-      ),
-      body: SingleChildScrollView(
-        child: Form(
-          key: _formKey,
-          autovalidateMode: _autovalidateMode,
-          child: Column(
-            children: <Widget>[
-              Padding(
-                padding: const EdgeInsets.all(20),
-                child: Center(
-                  child: SizedBox(
-                    width: 300,
-                    child: Image.asset('assets/logo.png'),
-                  ),
-                ),
-              ),
-              Padding(
-                //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0),
-                padding: const EdgeInsets.symmetric(horizontal: 15),
-                child: TextFormField(
-                  controller: _emailCtrl,
-                  readOnly: _isSubmitting,
-                  validator: (value) {
-                    if (value == null || value.isEmpty) {
-                      return 'Please enter your email';
-                    }
-
-                    return null;
-                  },
-                  decoration: const InputDecoration(
-                      border: OutlineInputBorder(),
-                      labelText: 'Phone number, email or username',
-                      hintText: 'Enter valid email id as abc@gmail.com'),
-                ),
-              ),
-              Padding(
-                padding: const EdgeInsets.only(
-                    left: 15.0, right: 15.0, top: 15, bottom: 0),
-                //padding: EdgeInsets.symmetric(horizontal: 15),
-                child: TextFormField(
-                  controller: _passwordCtrl,
-                  readOnly: _isSubmitting,
-                  obscureText: true,
-                  validator: (value) {
-                    if (value == null || value.isEmpty) {
-                      return 'Please enter your password';
-                    }
-
-                    return null;
-                  },
-                  decoration: const InputDecoration(
-                      border: OutlineInputBorder(),
-                      labelText: 'Password',
-                      hintText: 'Enter secure password'),
-                ),
-              ),
-              SizedBox(
-                //height: 65,
-                width: 360,
-                child: Padding(
-                  padding: const EdgeInsets.only(top: 20.0),
-                  child: ElevatedButton(
-                    onPressed: _isSubmitting
-                        ? null
-                        : () {
-                            if (_formKey.currentState!.validate()) {
-                              _login();
-                            } else {
-                              setState(() {
-                                _autovalidateMode = AutovalidateMode.always;
-                              });
-                            }
-                          },
-                    child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Text(
-                        'Log in ',
-                        style: TextStyle(color: Colors.white, fontSize: 20),
-                      ),
-                    ),
-                  ),
-                ),
-              ),
-              const SizedBox(
-                height: 20,
-              ),
-              Center(
-                child: Row(
-                  children: [
-                    const Padding(
-                      padding: EdgeInsets.only(left: 62),
-                      child: Text('Forgot your login details? '),
-                    ),
-                    Padding(
-                      padding: const EdgeInsets.only(left: 1.0),
-                      child: InkWell(
-                          onTap: () {
-                            // print('hello');
-                          },
-                          child: const Text(
-                            'Get help logging in.',
-                            style: TextStyle(fontSize: 14, color: Colors.blue),
-                          )),
-                    ),
-                  ],
-                ),
-              ),
-              const SizedBox(
-                height: 50,
-              ),
-              Center(
-                child: Row(
-                  children: [
-                    const Padding(
-                      padding: EdgeInsets.only(left: 62),
-                      child: Text('don\'t have an account yet? '),
-                    ),
-                    Padding(
-                      padding: const EdgeInsets.only(left: 1.0),
-                      child: InkWell(
-                          onTap: () {
-                            _createAccount();
-                          },
-                          child: const Text(
-                            'Create an account.',
-                            style: TextStyle(
-                                fontSize: 14,
-                                color: Colors.blue,
-                                fontWeight: FontWeight.bold),
-                          )),
-                    ),
-                  ],
-                ),
-              ),
-            ],
-          ),
-        ),
-      ),
-    );
-  }
-}

+ 0 - 238
lib/auth/view/signup_page.dart

@@ -1,238 +0,0 @@
-// ignore_for_file: use_build_context_synchronously
-
-import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:go_router/go_router.dart';
-import 'package:tp5/auth/auth.dart';
-import 'package:tp5/core/core.dart';
-import 'package:tp5/core/my_theme.dart';
-import 'package:tp5/onboarding/onboarding.dart';
-
-class SignUp extends ConsumerStatefulWidget {
-  const SignUp({super.key});
-
-  @override
-  ConsumerState<SignUp> createState() => _SignUpState();
-}
-
-class _SignUpState extends ConsumerState<SignUp> {
-  final _formKey = GlobalKey<FormState>();
-  AutovalidateMode? _autovalidateMode;
-  bool _isSubmitting = false;
-
-  final _emailCtrl = TextEditingController();
-  final _passwordCtrl = TextEditingController();
-  final _usernameCtrl = TextEditingController();
-
-  Future<void> _login() async {
-    try {
-      setState(() {
-        _isSubmitting = true;
-      });
-
-      await ref.read(authRepositoryProvider).logIn(
-            email: _emailCtrl.text,
-            password: _passwordCtrl.text,
-          );
-
-      if (mounted) {
-        context.pop();
-      }
-    } catch (e) {
-      setState(() {
-        _isSubmitting = false;
-      });
-
-      context.showAlert(e.toString());
-    }
-  }
-
-  Future<void> _createAccount() async {
-    try {
-      setState(() {
-        _isSubmitting = true;
-      });
-
-      await ref.read(onboardingRepositoryProvider).signUp(
-            email: _emailCtrl.text,
-            password: _passwordCtrl.text,
-            username: _usernameCtrl.text,
-          );
-
-      if (mounted) {
-        context.push(
-          '/verification',
-          extra: VerificationPageParams(
-            email: _emailCtrl.text,
-            password: _passwordCtrl.text,
-            username: _usernameCtrl.text,
-          ),
-        );
-      }
-    } catch (e) {
-      context.showAlert(e.toString());
-    }
-
-    setState(() {
-      _isSubmitting = false;
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    final isDarkMode = ref.watch(appThemeProvider);
-
-    return Scaffold(
-      appBar: AppBar(
-        title: Row(
-          children: [
-            const Text("GeeksforGeeks"),
-            Switch(
-                activeColor: Colors.orange,
-                onChanged: (value) {
-                  ref.read(appThemeProvider.notifier).state = value;
-                },
-                value: isDarkMode)
-          ],
-        ),
-      ),
-      body: SingleChildScrollView(
-        child: Form(
-          key: _formKey,
-          autovalidateMode: _autovalidateMode,
-          child: Column(
-            children: <Widget>[
-              Padding(
-                padding: const EdgeInsets.all(20),
-                child: Center(
-                  child: SizedBox(
-                    width: 300,
-                    child: Image.asset('assets/logo.png'),
-                  ),
-                ),
-              ),
-              Padding(
-                //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0),
-                padding: const EdgeInsets.symmetric(horizontal: 15),
-                child: TextFormField(
-                  controller: _emailCtrl,
-                  readOnly: _isSubmitting,
-                  validator: (value) {
-                    if (value == null || value.isEmpty) {
-                      return 'Please enter your email';
-                    }
-
-                    return null;
-                  },
-                  decoration: const InputDecoration(
-                      border: OutlineInputBorder(),
-                      labelText: 'Phone number, email or username',
-                      hintText: 'Enter valid email id as abc@gmail.com'),
-                ),
-              ),
-              Padding(
-                padding: const EdgeInsets.only(
-                    left: 15.0, right: 15.0, top: 15, bottom: 0),
-                //padding: EdgeInsets.symmetric(horizontal: 15),
-                child: TextFormField(
-                  controller: _passwordCtrl,
-                  readOnly: _isSubmitting,
-                  obscureText: true,
-                  validator: (value) {
-                    if (value == null || value.isEmpty) {
-                      return 'Please enter your password';
-                    }
-
-                    return null;
-                  },
-                  decoration: const InputDecoration(
-                      border: OutlineInputBorder(),
-                      labelText: 'Password',
-                      hintText: 'Enter secure password'),
-                ),
-              ),
-              SizedBox(
-                //height: 65,
-                width: 360,
-                child: Padding(
-                  padding: const EdgeInsets.only(top: 20.0),
-                  child: ElevatedButton(
-                    onPressed: _isSubmitting
-                        ? null
-                        : () {
-                            if (_formKey.currentState!.validate()) {
-                              _login();
-                            } else {
-                              setState(() {
-                                _autovalidateMode = AutovalidateMode.always;
-                              });
-                            }
-                          },
-                    child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Text(
-                        'Log in ',
-                        style: TextStyle(color: Colors.white, fontSize: 20),
-                      ),
-                    ),
-                  ),
-                ),
-              ),
-              const SizedBox(
-                height: 20,
-              ),
-              Center(
-                child: Row(
-                  children: [
-                    const Padding(
-                      padding: EdgeInsets.only(left: 62),
-                      child: Text('Forgot your login details? '),
-                    ),
-                    Padding(
-                      padding: const EdgeInsets.only(left: 1.0),
-                      child: InkWell(
-                          onTap: () {
-                            // print('hello');
-                          },
-                          child: const Text(
-                            'Get help logging in.',
-                            style: TextStyle(fontSize: 14, color: Colors.blue),
-                          )),
-                    ),
-                  ],
-                ),
-              ),
-              const SizedBox(
-                height: 50,
-              ),
-              Center(
-                child: Row(
-                  children: [
-                    const Padding(
-                      padding: EdgeInsets.only(left: 62),
-                      child: Text('don\'t have an account yet? '),
-                    ),
-                    Padding(
-                      padding: const EdgeInsets.only(left: 1.0),
-                      child: InkWell(
-                          onTap: () {
-                            _createAccount();
-                          },
-                          child: const Text(
-                            'Create an account.',
-                            style: TextStyle(
-                                fontSize: 14,
-                                color: Colors.blue,
-                                fontWeight: FontWeight.bold),
-                          )),
-                    ),
-                  ],
-                ),
-              ),
-            ],
-          ),
-        ),
-      ),
-    );
-  }
-}

+ 4 - 15
lib/authpages/auth_magiclink.dart

@@ -4,12 +4,11 @@ import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:hive_flutter/hive_flutter.dart';
-import 'package:supabase_auth_ui/supabase_auth_ui.dart';
 import 'package:tp5/core/basic_page.dart';
 
 class AuthMagiclink extends ConsumerStatefulWidget {
-  const AuthMagiclink({super.key});
-
+  const AuthMagiclink({super.key, required this.token});
+  final String? token;
   @override
   createState() => _AuthMagiclinkState();
 }
@@ -27,17 +26,7 @@ class _AuthMagiclinkState extends ConsumerState<AuthMagiclink> {
   @override
   Widget build(BuildContext context) {
     return BasicPage(
-      title: "TAR Pilot v5 / Connect",
-      body: SingleChildScrollView(
-          child: SupaMagicAuth(
-        redirectUrl: kIsWeb ? null : 'com.example.tp5://callback',
-        onSuccess: (Session response) {
-          print(response);
-        },
-        onError: (error) {
-          print(error);
-        },
-      )),
-    );
+        title: "TAR Pilot v5 / Connect",
+        body: SingleChildScrollView(child: Text("${widget.token}")));
   }
 }

+ 201 - 0
lib/authpages/login_otp.dart

@@ -0,0 +1,201 @@
+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:supabase_flutter/supabase_flutter.dart';
+import 'package:tp5/core/core.dart';
+
+class LoginOtp extends ConsumerStatefulWidget {
+  const LoginOtp({super.key});
+
+  @override
+  ConsumerState<LoginOtp> createState() => _LoginOtpState();
+}
+
+class _LoginOtpState extends ConsumerState<LoginOtp> {
+  final TextEditingController _emailController = TextEditingController();
+  final TextEditingController _otpController = TextEditingController();
+  bool _isOtpSent = false;
+  bool _isLoading = false;
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text('Sign In'),
+        backgroundColor: Colors.blueAccent,
+      ),
+      body: SingleChildScrollView(
+        child: Padding(
+          padding: const EdgeInsets.all(16.0),
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            crossAxisAlignment: CrossAxisAlignment.stretch,
+            children: [
+              SizedBox(height: 50),
+              Image(
+                image: AssetImage('assets/logo.png'),
+                width: 100,
+                height: 100,
+              ),
+              Gap(20),
+              Text(
+                'Welcome to TAR Pilot v5',
+                style: TextStyle(
+                  fontSize: 24,
+                  fontWeight: FontWeight.bold,
+                  color: Colors.blueAccent,
+                ),
+                textAlign: TextAlign.center,
+              ),
+              SizedBox(height: 20),
+              Text(
+                'Please enter your email to sign in.',
+                style: TextStyle(
+                  fontSize: 16,
+                  color: Colors.grey[700],
+                ),
+                textAlign: TextAlign.center,
+              ),
+              SizedBox(height: 40),
+              TextField(
+                controller: _emailController,
+                decoration: InputDecoration(
+                  labelText: 'Email',
+                  hintText: 'Enter your email',
+                  border: OutlineInputBorder(
+                    borderRadius: BorderRadius.circular(10),
+                  ),
+                  prefixIcon: Icon(Icons.email),
+                ),
+                keyboardType: TextInputType.emailAddress,
+              ),
+              SizedBox(height: 20),
+              if (_isOtpSent) ...[
+                TextField(
+                  controller: _otpController,
+                  decoration: InputDecoration(
+                    labelText: 'OTP',
+                    hintText: 'Enter OTP sent to your email',
+                    border: OutlineInputBorder(
+                      borderRadius: BorderRadius.circular(10),
+                    ),
+                    prefixIcon: Icon(Icons.lock_outline),
+                  ),
+                  keyboardType: TextInputType.number,
+                ),
+                SizedBox(height: 20),
+              ],
+              ElevatedButton(
+                onPressed: _isLoading
+                    ? null
+                    : () async {
+                        final email = _emailController.text;
+                        setState(() => _isLoading = true);
+                        try {
+                          if (!_isOtpSent) {
+                            await Supabase.instance.client.auth.signInWithOtp(
+                                email: email,
+                                shouldCreateUser: false,
+                                emailRedirectTo:
+                                    'com.example.tp5://magic-link');
+                            setState(() => _isOtpSent = true);
+                          } else {
+                            final response =
+                                await Supabase.instance.client.auth.verifyOTP(
+                              email: email,
+                              token: _otpController.text,
+                              type: OtpType.email,
+                            );
+
+                            if (response.session == null) {
+                              _otpController.clear();
+                              ScaffoldMessenger.of(context).showSnackBar(
+                                const SnackBar(
+                                  content:
+                                      Text('Invalid OTP. Please try again.'),
+                                  backgroundColor: Colors.red,
+                                ),
+                              );
+                            } else {
+                              //logged in
+                              print(response.session?.accessToken);
+                              context.go("/home");
+                            }
+                          }
+                        } catch (e) {
+                          if (e is AuthApiException && !_isOtpSent) {
+                            //signup
+                            print("loginotp: new signup");
+                            setState(() => _isLoading = true);
+
+                            await Supabase.instance.client.auth.signInWithOtp(
+                                email: email,
+                                shouldCreateUser: true,
+                                emailRedirectTo:
+                                    'com.example.tp5://auth/magic-link');
+                            setState(() => _isOtpSent = true);
+//go profile after new registration
+                            context.go('/home');
+                          } else {
+                            //error
+                            _otpController.clear();
+                            context.showError('Error: ${e.toString()}');
+                          }
+                        } finally {
+                          if (mounted) {
+                            setState(() => _isLoading = false);
+                          }
+                        }
+                      },
+                style: ElevatedButton.styleFrom(
+                  padding: EdgeInsets.symmetric(vertical: 15),
+                  backgroundColor: Colors.blueAccent,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(10),
+                  ),
+                ),
+                child: _isLoading
+                    ? const SizedBox(
+                        height: 20,
+                        width: 20,
+                        child: CircularProgressIndicator(
+                          color: Colors.white,
+                          strokeWidth: 2,
+                        ),
+                      )
+                    : Text(
+                        _isOtpSent ? 'Verify OTP' : 'Send OTP',
+                        style: TextStyle(fontSize: 18),
+                      ),
+              ),
+              SizedBox(height: 20),
+              if (_isOtpSent)
+                TextButton(
+                  onPressed: () {
+                    // Handle use another email
+                    _emailController.clear();
+                    setState(() => _isOtpSent = false);
+                  },
+                  child: Text(
+                    'Use another mail?',
+                    style: TextStyle(
+                      color: Colors.blueAccent,
+                      fontSize: 16,
+                    ),
+                  ),
+                ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+
+  @override
+  void dispose() {
+    _emailController.dispose();
+    _otpController.dispose();
+    super.dispose();
+  }
+}

+ 1 - 0
lib/authpages/signup.dart

@@ -0,0 +1 @@
+ 

+ 48 - 24
lib/core/routes.dart

@@ -1,14 +1,12 @@
 import 'dart:developer';
 
-import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:go_router/go_router.dart';
 import 'package:hive_flutter/hive_flutter.dart';
 import 'package:jiffy/jiffy.dart';
-import 'package:supabase_auth_ui/supabase_auth_ui.dart';
-import 'package:tp5/auth/auth.dart';
 import 'package:tp5/authpages/auth_magiclink.dart';
+import 'package:tp5/authpages/login_otp.dart';
 import 'package:tp5/core/basic_page.dart';
 import 'package:tp5/core/utils.dart';
 import 'package:tp5/flightslist/flightslist_page.dart';
@@ -24,6 +22,7 @@ import 'package:tp5/roster/view/crewlink_form.dart';
 import 'package:tp5/roster/view/crewlist_page.dart';
 import 'package:tp5/roster/view/roster_page.dart';
 import 'package:tp5/rosters/rosters_page.dart';
+import 'package:supabase_flutter/supabase_flutter.dart';
 
 final routeProvider = Provider<RouterConfig<Object>?>((ref) {
   return _routes;
@@ -31,18 +30,46 @@ final routeProvider = Provider<RouterConfig<Object>?>((ref) {
 
 final _routes = GoRouter(
   debugLogDiagnostics: false,
-  redirect: (_, s) {
-    log("${s.fullPath} | ${s.extra.runtimeType.toString()}", name: "routes");
+  redirect: (context, state) {
+    log("${state.fullPath} | ${state.extra.runtimeType.toString()}",
+        name: "routes");
+
+    // Check app expiration
     if (DateTime.now().isAfter(DateTime(2024, 12, 31))) {
       return "/expired";
     }
 
+    // Get current auth state
+    final session = Supabase.instance.client.auth.currentSession;
+    final isLoggedIn = session != null;
+
+    // List of paths that don't require authentication
+    final publicPaths = ['/auth/login-otp', '/magic-link', '/auth/signup'];
+    final isPublicPath = publicPaths.contains(state.fullPath);
+
+    // Redirect to login if not authenticated and trying to access protected route
+    if (!isLoggedIn && !isPublicPath) {
+      return '/auth/login-otp';
+    }
+
+    // Allow access to public paths even when logged out
+    if (isPublicPath) {
+      return null;
+    }
+
     return null;
   },
-//  initialLocation: '/test',
+  //  initialLocation: '/test',
   // initialLocation: '/auth/magiclink',
-  initialLocation: '/crewlink/roster',
+  initialLocation: '/home',
   routes: [
+    GoRoute(
+        path: '/magic-link',
+        builder: (BuildContext context, GoRouterState state) {
+          // Access query parameters here
+          final token = state.uri.queryParameters['token'];
+          return AuthMagiclink(token: token);
+        }),
     GoRoute(
       path: '/test',
       builder: (context, state) => BasicPage(
@@ -89,9 +116,18 @@ final _routes = GoRouter(
         },
         routes: [
           GoRoute(
-            path: '/magiclink',
-            builder: (context, state) => AuthMagiclink(),
-          )
+              path: '/signup',
+              builder: (BuildContext context, GoRouterState state) {
+                // Access query parameters here
+                return Text("signup");
+              }),
+          GoRoute(
+              path: '/login-otp',
+              builder: (BuildContext context, GoRouterState state) {
+                // Access query parameters here
+                final token = state.uri.queryParameters['token'];
+                return LoginOtp();
+              }),
         ]),
     GoRoute(
       path: '/expired',
@@ -104,20 +140,8 @@ final _routes = GoRouter(
           body: const Text("App is Expired please Update")),
     ),
     GoRoute(
-      path: '/login',
-      builder: (context, state) => const LoginPage(),
-    ),
-    GoRoute(
-      path: '/verification',
-      builder: (context, state) {
-        final params = state.extra as VerificationPageParams?;
-
-        if (params == null) {
-          throw 'Missing `VerificationPageParams` object';
-        }
-
-        return VerificationPage(params: params);
-      },
+      path: '/home',
+      redirect: (context, state) => '/crewlink/roster',
     ),
     GoRoute(
       path: '/pdf',

+ 0 - 1539
lib/csv/data copy.dart.bak

@@ -1,1539 +0,0 @@
-// ignore_for_file: non_constant_identifier_names
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-
-import 'package:collection/collection.dart';
-import 'package:flutter/foundation.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:jiffy/jiffy.dart';
-//import 'package:supabase_flutter/supabase_flutter.dart';
-
-import "package:tp5/core/utils.dart";
-import "package:tp5/csv/csv_data.dart";
-
-class CrewFilter {
-  String? college;
-  String? ac;
-  String? tlc;
-  String? fname;
-  String? lname;
-  String? searchname;
-  CrewFilter({
-    this.college,
-    this.ac,
-    this.tlc,
-    this.fname,
-    this.lname,
-    this.searchname,
-  });
-
-  CrewFilter copyWith({
-    ValueGetter<String?>? college,
-    ValueGetter<String?>? ac,
-    ValueGetter<String?>? tlc,
-    ValueGetter<String?>? fname,
-    ValueGetter<String?>? lname,
-    ValueGetter<String?>? searchname,
-  }) {
-    return CrewFilter(
-      college: college != null ? college() : this.college,
-      ac: ac != null ? ac() : this.ac,
-      tlc: tlc != null ? tlc() : this.tlc,
-      fname: fname != null ? fname() : this.fname,
-      lname: lname != null ? lname() : this.lname,
-      searchname: searchname != null ? searchname() : this.searchname,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'college': college,
-      'ac': ac,
-      'tlc': tlc,
-      'fname': fname,
-      'lname': lname,
-      'searchname': searchname,
-    };
-  }
-
-  factory CrewFilter.fromMap(Map<String, dynamic> map) {
-    return CrewFilter(
-      college: map['college'],
-      ac: map['ac'],
-      tlc: map['tlc'],
-      fname: map['fname'],
-      lname: map['lname'],
-      searchname: map['searchname'],
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory CrewFilter.fromJson(String source) =>
-      CrewFilter.fromMap(json.decode(source));
-
-  @override
-  String toString() {
-    return 'CrewFilter(college: $college, ac: $ac, tlc: $tlc, fname: $fname, lname: $lname, searchname: $searchname)';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-
-    return other is CrewFilter &&
-        other.college == college &&
-        other.ac == ac &&
-        other.tlc == tlc &&
-        other.fname == fname &&
-        other.lname == lname &&
-        other.searchname == searchname;
-  }
-
-  @override
-  int get hashCode {
-    return college.hashCode ^
-        ac.hashCode ^
-        tlc.hashCode ^
-        fname.hashCode ^
-        lname.hashCode ^
-        searchname.hashCode;
-  }
-}
-
-class FlightFilter {
-  String? al;
-  String? fnum;
-  String? date;
-  String? dep;
-  String? arr;
-  Jiffy? jdep;
-  Jiffy? jarr;
-  String? tlc;
-  String? reg;
-  FlightFilter(
-      {this.al,
-      this.fnum,
-      this.date,
-      this.dep,
-      this.arr,
-      this.jdep,
-      this.jarr,
-      this.tlc,
-      this.reg});
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-
-    return other is FlightFilter &&
-        other.al == al &&
-        other.fnum == fnum &&
-        other.date == date &&
-        other.dep == dep &&
-        other.arr == arr &&
-        other.jdep == jdep &&
-        other.jarr == jarr &&
-        other.tlc == tlc &&
-        other.reg == reg;
-  }
-
-  FlightFilter copyWith({
-    ValueGetter<String?>? al,
-    ValueGetter<String?>? fnum,
-    ValueGetter<String?>? date,
-    ValueGetter<String?>? dep,
-    ValueGetter<String?>? arr,
-    ValueGetter<Jiffy?>? jdep,
-    ValueGetter<Jiffy?>? jarr,
-    ValueGetter<String?>? tlc,
-    ValueGetter<String?>? reg,
-  }) {
-    return FlightFilter(
-      al: al != null ? al() : this.al,
-      fnum: fnum != null ? fnum() : this.fnum,
-      date: date != null ? date() : this.date,
-      dep: dep != null ? dep() : this.dep,
-      arr: arr != null ? arr() : this.arr,
-      jdep: jdep != null ? jdep() : this.jdep,
-      jarr: jarr != null ? jarr() : this.jarr,
-      tlc: tlc != null ? tlc() : this.tlc,
-      reg: reg != null ? reg() : this.reg,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'al': al,
-      'fnum': fnum,
-      'date': date,
-      'dep': dep,
-      'arr': arr,
-      'jdep': jdep?.toString(),
-      'jarr': jarr?.toString(),
-      'tlc': tlc,
-      'reg': reg,
-    };
-  }
-
-  factory FlightFilter.fromMap(Map<String, dynamic> map) {
-    return FlightFilter(
-      al: map['al'],
-      fnum: map['fnum'],
-      date: map['date'],
-      dep: map['dep'],
-      arr: map['arr'],
-      jdep: map['jdep'] != null ? Jiffy.parse(map['jdep']) : null,
-      jarr: map['jarr'] != null ? Jiffy.parse(map['jarr']) : null,
-      tlc: map['tlc'],
-      reg: map['reg'],
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory FlightFilter.fromJson(String source) =>
-      FlightFilter.fromMap(json.decode(source));
-
-  @override
-  String toString() {
-    return 'FlightFilter(al: $al, fnum: $fnum, date: $date, dep: $dep, arr: $arr, jdep: $jdep, jarr: $jarr, tlc: $tlc, reg: $reg)';
-  }
-
-  @override
-  int get hashCode {
-    return al.hashCode ^
-        fnum.hashCode ^
-        date.hashCode ^
-        dep.hashCode ^
-        arr.hashCode ^
-        jdep.hashCode ^
-        jarr.hashCode ^
-        tlc.hashCode ^
-        reg.hashCode;
-  }
-}
-
-final pnlegByTlcProvider =
-    Provider. /*autoDispose.*/ family<List<Pnleg>, String>((ref, tlc) => ref
-        .watch(dataProvider)
-        .pnleg
-        .where((leg) => leg.tlc == tlc)
-        .sortedBy((e) =>
-            e.jdep?.dateTime ??
-            Jiffy.parse(e.depdate ?? "01/01/2001",
-                    pattern: "dd/MM/yyyy", isUtc: true)
-                .dateTime)
-        .toList());
-
-final pnlegProvider = Provider.autoDispose.family<List<Pnleg>, FlightFilter>(
-    (ref, flightFilter) => ref
-        .watch(dataProvider)
-        .pnleg
-        .where((leg) =>
-            (leg.al == (flightFilter.al ?? leg.al)) &&
-            (leg.fnum == (flightFilter.fnum ?? leg.fnum)) &&
-            // (leg.jdep?.yMd ==
-            //     (flightFilter.date ?? leg.jdep?.yMd)) && //format yyyy-MM-dd
-            (leg.dep == (flightFilter.dep ?? leg.dep)) &&
-            (leg.arr == (flightFilter.arr ?? leg.arr)) &&
-            (flightFilter.jdep == null ||
-                (leg.jdep != null &&
-                    flightFilter.jdep != null &&
-                    flightFilter.jdep!.isBetween(leg.jdep!.subtract(hours: 5),
-                        leg.jdep!.add(hours: 5)))) &&
-            (flightFilter.jarr == null ||
-                (leg.jarr != null &&
-                    flightFilter.jarr != null &&
-                    flightFilter.jarr!.isBetween(leg.jarr!.subtract(hours: 5),
-                        leg.jarr!.add(hours: 5)))) &&
-            (leg.tlc == (flightFilter.tlc ?? leg.tlc)))
-        .toList());
-
-/*
-final pnlegInterval = Provider((ref) {
-  final pnleg = ref.watch(dataProvider).pnleg;
-  return pnleg.where((leg) => leg.jdep != null && leg.jarr != null).toList();
-});
-
-
-final pnlegDates = Provider((ref) {
-  final pnleg = ref.watch(dataProvider).pnleg;
-  return pnleg.fold(
-      <Jiffy?>{},
-      (t, e) => [...t, e.jdep?.startOf(Unit.day)]
-          .whereNotNull()
-          .sortedBy((k) => k.millisecondsSinceEpoch.toString())
-          .toSet());
-});
-
-final pnlegTlcs = Provider((ref) {
-  final data = ref.watch(dataProvider);
-  final pnleg = data.pnleg;
-  final qualif = data.qualif;
-
-  return pnleg.fold(<String?>{}, (t, e) => {...t, e.tlc}).sortedBy((k) =>
-      qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
-});
-*/
-
-class PnlegMeta {
-  PnlegMeta({required this.tlcs, required this.dates});
-  final List<String> tlcs;
-  final List<Jiffy> dates;
-}
-
-final pnlegMeta = Provider((ref) {
-  print("data: start analyzing pnleg");
-  final now = Jiffy.now();
-  final pnlegs = ref.watch(dataProvider).pnleg;
-  final qualif = ref.watch(dataProvider).qualif;
-  Set<String> tlcs = {};
-  Set<Jiffy> dates = {};
-  for (Pnleg pnleg in pnlegs) {
-    tlcs.add(pnleg.tlc ?? "");
-    dates.add(pnleg.jdep?.startOf(Unit.day) ??
-        Jiffy.parse(pnleg.date ?? "01/01/1970",
-            pattern: "dd/MM/yyyy", isUtc: true));
-  }
-  final restlcs = tlcs.sortedBy((k) =>
-      qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
-  final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
-  print(
-      "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
-  return PnlegMeta(tlcs: restlcs, dates: resdates);
-});
-
-final aclegProvider = Provider.autoDispose.family<List<Acleg>, FlightFilter>(
-    (ref, flightFilter) => ref
-        .watch(dataProvider)
-        .acleg
-        .where((leg) =>
-            (leg.FN_CARRIER == (flightFilter.al ?? leg.FN_CARRIER)) &&
-            (leg.FN_NUMBER == (flightFilter.fnum ?? leg.FN_NUMBER)) &&
-//            (leg.jdep?.yMd ==
-//                (flightFilter.date ?? leg.jdep?.yMd)) && //format yyyy-MM-dd
-            (leg.DEP_AP_ACTUAL == (flightFilter.dep ?? leg.DEP_AP_ACTUAL)) &&
-            (leg.DEP_AP_SCHED == (flightFilter.dep ?? leg.DEP_AP_SCHED)) &&
-            (leg.ARR_AP_ACTUAL == (flightFilter.arr ?? leg.ARR_AP_ACTUAL)) &&
-            (leg.ARR_AP_SCHED == (flightFilter.arr ?? leg.ARR_AP_SCHED)) &&
-            (flightFilter.jdep == null ||
-                (leg.jdep != null &&
-                    flightFilter.jdep != null &&
-                    flightFilter.jdep!.isBetween(leg.jdep!.subtract(hours: 5),
-                        leg.jdep!.add(hours: 5)))) &&
-            (flightFilter.jarr == null ||
-                (leg.jarr != null &&
-                    flightFilter.jarr != null &&
-                    flightFilter.jarr!.isBetween(leg.jarr!.subtract(hours: 5),
-                        leg.jarr!.add(hours: 5)))) &&
-            (leg.AC_REGISTRATION == (flightFilter.reg ?? leg.AC_REGISTRATION)))
-        .toList());
-
-final qualifProvider = Provider.family<List<Qualif>, CrewFilter>(
-    (ref, crewFilter) => ref
-        .watch(dataProvider)
-        .qualif
-        .where((x) => (((crewFilter.tlc ?? x.tlc) == x.tlc &&
-            (crewFilter.college ?? x.college) == x.college &&
-            (crewFilter.ac ?? x.ac) == x.ac &&
-            (crewFilter.lname ?? x.lname ?? "").capitalize() ==
-                (x.lname ?? "").capitalize() &&
-            (crewFilter.fname ?? x.fname ?? "").capitalize() ==
-                (x.fname ?? "").capitalize() &&
-            //search like
-            (crewFilter.searchname == null ||
-                (x.fname ?? "")
-                    .capitalize()
-                    .contains(crewFilter.searchname!.capitalize())) &&
-            (crewFilter.searchname == null ||
-                (x.lname ?? "")
-                    .capitalize()
-                    .contains(crewFilter.searchname!.capitalize())))))
-        .toList());
-
-final dataProvider = StateNotifierProvider<DataNotifier, DataState>((ref) {
-  return DataNotifier();
-});
-
-class DataState {
-  List<Qualif> qualif;
-
-  List<Pnleg> pnleg;
-
-  List<Acleg> acleg;
-
-  Jiffy? qualifupdate;
-  Jiffy? pnlegupdate;
-  Jiffy? aclegupdate;
-
-  DataState({
-    this.qualif = const [],
-    this.pnleg = const [],
-    this.acleg = const [],
-    this.qualifupdate,
-    this.pnlegupdate,
-    this.aclegupdate,
-  });
-
-  DataState copyWith({
-    List<Qualif>? qualif,
-    List<Pnleg>? pnleg,
-    List<Acleg>? acleg,
-    Jiffy? qualifupdate,
-    Jiffy? pnlegupdate,
-    Jiffy? aclegupdate,
-  }) {
-    return DataState(
-      qualif: qualif ?? this.qualif,
-      pnleg: pnleg ?? this.pnleg,
-      acleg: acleg ?? this.acleg,
-      qualifupdate: qualifupdate ?? this.qualifupdate,
-      pnlegupdate: pnlegupdate ?? this.pnlegupdate,
-      aclegupdate: aclegupdate ?? this.aclegupdate,
-    );
-  }
-
-  @override
-  String toString() {
-    return 'DataState(qualif: $qualif, pnleg: $pnleg, acleg: $acleg, qualifupdate: $qualifupdate, pnlegupdate: $pnlegupdate, aclegupdate: $aclegupdate)';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-
-    return other is DataState &&
-        listEquals(other.qualif, qualif) &&
-        listEquals(other.pnleg, pnleg) &&
-        listEquals(other.acleg, acleg) &&
-        other.qualifupdate == qualifupdate &&
-        other.pnlegupdate == pnlegupdate &&
-        other.aclegupdate == aclegupdate;
-  }
-
-  @override
-  int get hashCode {
-    return qualif.hashCode ^
-        pnleg.hashCode ^
-        acleg.hashCode ^
-        qualifupdate.hashCode ^
-        pnlegupdate.hashCode ^
-        aclegupdate.hashCode;
-  }
-}
-
-class DataNotifier extends StateNotifier<DataState> {
-  DataNotifier() : super(DataState()) {
-    loadAll();
-    _timer = Timer.periodic(const Duration(seconds: 10), (timer) async {
-      //update file and load
-      // final response = await Supabase.instance.client.storage.from('your_bucket_name').;
-      print("data: timer tick, check csv files");
-      // print(acleg.where((x) => x.pad_booked != null).map((x) => x.pad_booked));
-      await loadAll();
-    });
-  }
-
-  @override
-  void dispose() {
-    _timer.cancel();
-    super.dispose();
-  }
-
-  loadAll() async {
-    if (pnlegmoistime != pnlegmoisupdate) await loadPnlegsmois();
-    if (aclegtime != aclegupdate) await loadAclegs();
-    if (pnleg3time != pnleg3update) await loadPnlegs3();
-    if (qualiftime != qualifupdate) await loadQualif();
-  }
-
-  late Timer _timer;
-
-  Jiffy? qualifupdate;
-  String get qualiffile => PathTo().csvFile("exportlicence.txt");
-  Jiffy? get qualiftime => File(qualiffile).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("exportlicence.txt")).lastModifiedSync())
-      : null;
-  List<Qualif> qualif = [];
-  loadQualif() async {
-    print("data: qualif update ${qualiftime?.dateTime}");
-    final txt = await File(qualiffile).readAsString();
-    qualif = CsvData.csv2list(txt).map((e) => Qualif.fromList(e)).toList();
-    qualifupdate = qualiftime;
-    state = state.copyWith(qualifupdate: qualifupdate, qualif: qualif);
-  }
-
-  Jiffy? aclegupdate;
-  String get aclegfile => PathTo().csvFile("secondprgtype.zip");
-  Jiffy? get aclegtime => File(aclegfile).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("secondprgtype.zip")).lastModifiedSync())
-      : null;
-  List<Acleg> acleg = [];
-  loadAclegs() async {
-    print("data: acleg update ${aclegtime?.dateTime}");
-
-    final txt =
-        await CsvData.extractTextFileFromZip(aclegfile, "secondprgtype.txt");
-    acleg = CsvData.csv2list(txt)
-        .map((e) => Acleg.fromList(e))
-        .where((leg) =>
-            //only flights of Tunisair
-            (leg.EMPLOYER_CABIN == "TU" ||
-                leg.EMPLOYER_COCKPIT == "TU" ||
-                leg.AC_OWNER == "TU"))
-        .sortedBy((e) => e.jdep!.dateTime)
-        .toList();
-    aclegupdate = aclegtime;
-    state = state.copyWith(aclegupdate: aclegupdate, acleg: acleg);
-
-    //print(acleg);
-  }
-
-  List<Pnleg> get pnleg {
-    if (pnlegmoistime != null &&
-        pnleg3time != null &&
-        pnlegmoistime!.isSameOrBefore(pnleg3time!)) {
-      return pnlegmois;
-    } else if (pnlegmoistime != null &&
-        pnleg3time != null &&
-        pnlegmoistime!.isAfter(pnleg3time!)) {
-      final dates3tlc3 = pnleg3.fold(
-          [],
-          (p, e) => p.contains([e.date, e.tlc]) ? p : p
-            ..add([e.date, e.tlc]));
-      return pnlegmois
-          .where((x) => !dates3tlc3.contains([x.date, x.tlc]))
-          .toList()
-        ..addAll(pnleg3); //pnleg3 dabord
-    } else if (pnlegmoistime == null && pnleg3time != null) {
-      return pnleg3;
-    } else if (pnlegmoistime != null && pnleg3time == null) {
-      return pnlegmois;
-    } else {
-      return <Pnleg>[];
-    }
-  }
-
-  Jiffy? pnlegmoisupdate;
-  String get pnlegmoisfile => PathTo().csvFile("ExportPGRGPNmois.zip");
-  Jiffy? get pnlegmoistime => File(pnlegmoisfile).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("ExportPGRGPNmois.zip")).lastModifiedSync())
-      : null;
-  List<Pnleg> pnlegmois = [];
-  loadPnlegsmois() async {
-    print("data: pnlegmois update ${pnlegmoistime?.dateTime}");
-
-    final txt = await CsvData.extractTextFileFromZip(
-        pnlegmoisfile, "ExportPGRGPNmois.txt");
-    pnlegmois = CsvData.csv2list(txt).map((e) => Pnleg.fromList(e)).toList();
-    pnlegmoisupdate = pnlegmoistime;
-    state = state.copyWith(pnlegupdate: pnlegmoisupdate, pnleg: pnleg);
-
-    //print(pnlegmois);
-  }
-
-  Jiffy? pnleg3update;
-  String get pnleg3file => PathTo().csvFile("exportPGRGPN.zip");
-  Jiffy? get pnleg3time => File(pnleg3file).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("ExportPGRGPNmois.zip")).lastModifiedSync())
-      : null;
-  List<Pnleg> pnleg3 = [];
-  loadPnlegs3() async {
-    print("data: pnleg3 update ${pnleg3time?.dateTime}");
-
-    final txt =
-        await CsvData.extractTextFileFromZip(pnleg3file, "exportPGRGPN.txt");
-    pnleg3 = CsvData.csv2list(txt).map((e) => Pnleg.fromList(e)).toList();
-    pnleg3update = pnleg3time;
-    state = state.copyWith(pnlegupdate: pnleg3update, pnleg: pnleg);
-
-    //print(pnleg3);
-  }
-}
-
-class Qualif {
-  String? tlc;
-  String? lname;
-  String? mname;
-  String? fname;
-  String? date;
-  String? ac;
-  String? college;
-  String? base;
-  Qualif({
-    this.tlc,
-    this.lname,
-    this.mname,
-    this.fname,
-    this.date,
-    this.ac,
-    this.college,
-    this.base,
-  });
-
-  Qualif copyWith({
-    String? tlc,
-    String? lname,
-    String? mname,
-    String? fname,
-    String? date,
-    String? ac,
-    String? college,
-    String? base,
-  }) {
-    return Qualif(
-      tlc: tlc ?? this.tlc,
-      lname: lname ?? this.lname,
-      mname: mname ?? this.mname,
-      fname: fname ?? this.fname,
-      date: date ?? this.date,
-      ac: ac ?? this.ac,
-      college: college ?? this.college,
-      base: base ?? this.base,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return <String, dynamic>{
-      'tlc': tlc,
-      'lname': lname,
-      'mname': mname,
-      'fname': fname,
-      'date': date,
-      'ac': ac,
-      'college': college,
-      'base': base,
-    };
-  }
-
-  factory Qualif.fromList(List datalist) {
-    return Qualif(
-        tlc: datalist[0],
-        lname: datalist[1],
-        mname: datalist[2],
-        fname: datalist[3],
-        date: datalist[4],
-        ac: datalist[5],
-        college: datalist[6],
-        base: datalist[7]);
-  }
-
-  factory Qualif.fromMap(Map<String, dynamic> map) {
-    return Qualif(
-      tlc: map['tlc'] != null ? map['tlc'] as String : null,
-      lname: map['lname'] != null ? map['lname'] as String : null,
-      mname: map['mname'] != null ? map['mname'] as String : null,
-      fname: map['fname'] != null ? map['fname'] as String : null,
-      date: map['date'] != null ? map['date'] as String : null,
-      ac: map['ac'] != null ? map['ac'] as String : null,
-      college: map['college'] != null ? map['college'] as String : null,
-      base: map['base'] != null ? map['base'] as String : null,
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory Qualif.fromJson(String source) =>
-      Qualif.fromMap(json.decode(source) as Map<String, dynamic>);
-
-  @override
-  String toString() {
-    return 'Qualif(tlc: $tlc, lname: $lname, mname: $mname, fname: $fname, date: $date, ac: $ac, college: $college, base: $base)';
-  }
-
-  @override
-  bool operator ==(covariant Qualif other) {
-    if (identical(this, other)) return true;
-
-    return other.tlc == tlc &&
-        other.lname == lname &&
-        other.mname == mname &&
-        other.fname == fname &&
-        other.date == date &&
-        other.ac == ac &&
-        other.college == college &&
-        other.base == base;
-  }
-
-  @override
-  int get hashCode {
-    return tlc.hashCode ^
-        lname.hashCode ^
-        mname.hashCode ^
-        fname.hashCode ^
-        date.hashCode ^
-        ac.hashCode ^
-        college.hashCode ^
-        base.hashCode;
-  }
-}
-
-class Pnleg {
-  String? date;
-  Jiffy? get jdate => date != null
-      ? Jiffy.parse(date ?? "01/01/1970", pattern: "dd/MM/yyyy", isUtc: true)
-      : null;
-
-  String? tlc;
-  String? actype;
-  String? al;
-  String? fnum;
-  String? depdate;
-  String? deptime;
-  String? arrdate;
-  String? arrtime;
-  String? dep;
-  String? arr;
-  String? label;
-  String? type;
-  Jiffy? get jdep =>
-      deptime != null ? "$depdate $deptime".parseddmmyyyyhhmm() : null;
-  Jiffy? get jarr =>
-      arrtime != null ? "$arrdate $arrtime".parseddmmyyyyhhmm() : null;
-  Pnleg({
-    this.date,
-    this.tlc,
-    this.actype,
-    this.al,
-    this.fnum,
-    this.depdate,
-    this.deptime,
-    this.arrdate,
-    this.arrtime,
-    this.dep,
-    this.arr,
-    this.label,
-    this.type,
-  });
-
-  Pnleg copyWith({
-    String? date,
-    String? tlc,
-    String? actype,
-    String? al,
-    String? fnum,
-    String? depdate,
-    String? deptime,
-    String? arrdate,
-    String? arrtime,
-    String? dep,
-    String? arr,
-    String? label,
-    String? type,
-  }) {
-    return Pnleg(
-      date: date ?? this.date,
-      tlc: tlc ?? this.tlc,
-      actype: actype ?? this.actype,
-      al: al ?? this.al,
-      fnum: fnum ?? this.fnum,
-      depdate: depdate ?? this.depdate,
-      deptime: deptime ?? this.deptime,
-      arrdate: arrdate ?? this.arrdate,
-      arrtime: arrtime ?? this.arrtime,
-      dep: dep ?? this.dep,
-      arr: arr ?? this.arr,
-      label: label ?? this.label,
-      type: type ?? this.type,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return <String, dynamic>{
-      'date': date,
-      'tlc': tlc,
-      'actype': actype,
-      'al': al,
-      'fnum': fnum,
-      'depdate': depdate,
-      'deptime': deptime,
-      'arrdate': arrdate,
-      'arrtime': arrtime,
-      'dep': dep,
-      'arr': arr,
-      'label': label,
-      'type': type,
-    };
-  }
-
-  factory Pnleg.fromList(List datalist) {
-    return Pnleg(
-        date: datalist[0],
-        tlc: datalist[1],
-        actype: datalist[2],
-        al: datalist[3],
-        fnum: datalist[4],
-        depdate: datalist[5],
-        deptime: datalist[6],
-        arrdate: datalist[7],
-        arrtime: datalist[8],
-        dep: datalist[9],
-        arr: datalist[10],
-        label: datalist[11],
-        type: datalist[12]);
-  }
-
-  factory Pnleg.fromMap(Map<String, dynamic> map) {
-    return Pnleg(
-      date: map['date'] != null ? map['date'] as String : null,
-      tlc: map['tlc'] != null ? map['tlc'] as String : null,
-      actype: map['actype'] != null ? map['actype'] as String : null,
-      al: map['al'] != null ? map['al'] as String : null,
-      fnum: map['fnum'] != null ? map['fnum'] as String : null,
-      depdate: map['depdate'] != null ? map['depdate'] as String : null,
-      deptime: map['deptime'] != null ? map['deptime'] as String : null,
-      arrdate: map['arrdate'] != null ? map['arrdate'] as String : null,
-      arrtime: map['arrtime'] != null ? map['arrtime'] as String : null,
-      dep: map['dep'] != null ? map['dep'] as String : null,
-      arr: map['arr'] != null ? map['arr'] as String : null,
-      label: map['label'] != null ? map['label'] as String : null,
-      type: map['type'] != null ? map['type'] as String : null,
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory Pnleg.fromJson(String source) =>
-      Pnleg.fromMap(json.decode(source) as Map<String, dynamic>);
-
-  @override
-  String toString() {
-    return 'Pnleg(date: $date, tlc: $tlc, actype: $actype, al: $al, fnum: $fnum, depdate: $depdate, deptime: $deptime, arrdate: $arrdate, arrtime: $arrtime, dep: $dep, arr: $arr, label: $label, type: $type)';
-  }
-
-  @override
-  bool operator ==(covariant Pnleg other) {
-    if (identical(this, other)) return true;
-
-    return other.date == date &&
-        other.tlc == tlc &&
-        other.actype == actype &&
-        other.al == al &&
-        other.fnum == fnum &&
-        other.depdate == depdate &&
-        other.deptime == deptime &&
-        other.arrdate == arrdate &&
-        other.arrtime == arrtime &&
-        other.dep == dep &&
-        other.arr == arr &&
-        other.label == label &&
-        other.type == type;
-  }
-
-  @override
-  int get hashCode {
-    return date.hashCode ^
-        tlc.hashCode ^
-        actype.hashCode ^
-        al.hashCode ^
-        fnum.hashCode ^
-        depdate.hashCode ^
-        deptime.hashCode ^
-        arrdate.hashCode ^
-        arrtime.hashCode ^
-        dep.hashCode ^
-        arr.hashCode ^
-        label.hashCode ^
-        type.hashCode;
-  }
-}
-
-//enum flt_status { sched, delayed, taxiout, enroute, landed, arrived }
-
-class Acleg {
-  String? LEG_NO;
-  String? FN_CARRIER;
-  String? FN_NUMBER;
-  String? FN_SUFFIX;
-  String? DAY_OF_ORIGIN;
-  String? AC_OWNER;
-  String? AC_SUBTYPE;
-  String? AC_VERSION;
-  String? AC_REGISTRATION;
-  String? DEP_AP_ACTUAL;
-  String? DEP_AP_SCHED;
-  String? DEP_DT_EST;
-  Jiffy? get jdepest =>
-      (DEP_DT_EST == null) ? null : DEP_DT_EST!.parseyyyymmddhhmm();
-  String? DEP_SCHED_DT;
-  Jiffy? get jdepsched =>
-      (DEP_SCHED_DT == null) ? null : DEP_SCHED_DT!.parseyyyymmddhhmm();
-  String? ARR_AP_ACTUAL;
-  String? ARR_AP_SCHED;
-  String? ARR_DT_EST;
-  Jiffy? get jarrest =>
-      (ARR_DT_EST == null) ? null : ARR_DT_EST!.parseyyyymmddhhmm();
-  String? ARR_SCHED_DT;
-  Jiffy? get jarrsched =>
-      (ARR_SCHED_DT == null) ? null : ARR_SCHED_DT!.parseyyyymmddhhmm();
-  String? SLOT_TIME_ACTUAL;
-  Jiffy? get slot =>
-      (SLOT_TIME_ACTUAL == null) ? null : SLOT_TIME_ACTUAL!.parseyyyymmddhhmm();
-  String? LEG_TYPE;
-  String? STATUS;
-  String? EMPLOYER_COCKPIT;
-  String? EMPLOYER_CABIN;
-  String? CYCLES;
-  String? DELAY_CODE_01;
-  String? DELAY_CODE_02;
-  String? DELAY_CODE_03;
-  String? DELAY_CODE_04;
-  String? DELAY_TIME_01;
-  String? DELAY_TIME_02;
-  String? DELAY_TIME_03;
-  String? DELAY_TIME_04;
-  String? SUBDELAY_CODE_01;
-  String? SUBDELAY_CODE_02;
-  String? SUBDELAY_CODE_03;
-  String? SUBDELAY_CODE_04;
-  List<String> get delaycode => [
-        DELAY_CODE_01,
-        DELAY_CODE_02,
-        DELAY_CODE_03,
-        DELAY_CODE_04
-      ].whereNotNull().toList();
-  List<String> get delaysubcode => [
-        SUBDELAY_CODE_01,
-        SUBDELAY_CODE_02,
-        SUBDELAY_CODE_03,
-        SUBDELAY_CODE_04
-      ].whereNotNull().toList();
-  List<Duration?> get delaytime => [
-        DELAY_TIME_01 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_01!)),
-        DELAY_TIME_02 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_02!)),
-        DELAY_TIME_03 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_03!)),
-        DELAY_TIME_04 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_04!))
-      ].whereNotNull().toList();
-
-  String? PAX_BOOKED_C;
-  String? PAX_BOOKED_Y;
-  String? get pax_booked => (PAX_BOOKED_C != null || PAX_BOOKED_Y != null)
-      ? "C${PAX_BOOKED_C ?? 0}/Y${PAX_BOOKED_Y ?? 0}"
-      : null;
-  String? PAX_BOOKED_TRS_C;
-  String? PAX_BOOKED_TRS_Y;
-  String? get pax_trs => (PAX_BOOKED_TRS_C != null || PAX_BOOKED_TRS_Y != null)
-      ? "C${PAX_BOOKED_TRS_C ?? 0}/Y${PAX_BOOKED_TRS_Y ?? 0}"
-      : null;
-  String? PAD_BOOKED_C;
-  String? PAD_BOOKED_Y;
-  String? get pad_booked => (PAD_BOOKED_C != null || PAD_BOOKED_Y != null)
-      ? "C${PAD_BOOKED_C ?? 0}/Y${PAD_BOOKED_Y ?? 0}"
-      : null;
-  String? OFFBLOCK_DT_A;
-  String? AIRBORNE_DT_A;
-  String? LANDING_DT_A;
-  String? ONBLOCK_DT_A;
-  List<Jiffy?> get blocks_a => [
-        (OFFBLOCK_DT_A ?? "").parseyyyymmddhhmm(),
-        (AIRBORNE_DT_A ?? "").parseyyyymmddhhmm(),
-        (LANDING_DT_A ?? "").parseyyyymmddhhmm(),
-        (ONBLOCK_DT_A ?? "").parseyyyymmddhhmm()
-      ];
-  String get flt_status {
-    if (blocks[3] != null) {
-      return "Arrived";
-    } else if (blocks[2] != null) {
-      return "Landed";
-    } else if (blocks[1] != null) {
-      return "Inflight";
-    } else if (blocks[0] != null) {
-      return "Taxiout";
-    } else if (jdepest != null &&
-        jarrsched != null &&
-        jdepest!.isAfter(jdepsched!)) {
-      return "Delayed";
-    } else {
-      return "Sched";
-    }
-  }
-
-  String? OFFBLOCK_DT_F;
-  String? AIRBORNE_DT_F;
-  String? LANDING_DT_F;
-  String? ONBLOCK_DT_F;
-  List<Jiffy?> get blocks_f => [
-        (OFFBLOCK_DT_F ?? "").parseyyyymmddhhmm(),
-        (AIRBORNE_DT_F ?? "").parseyyyymmddhhmm(),
-        (LANDING_DT_F ?? "").parseyyyymmddhhmm(),
-        (ONBLOCK_DT_F ?? "").parseyyyymmddhhmm()
-      ];
-
-  String? OFFBLOCK_DT_M;
-  String? AIRBORNE_DT_M;
-  String? LANDING_DT_M;
-  String? ONBLOCK_DT_M;
-  List<Jiffy?> get blocks_m => [
-        (OFFBLOCK_DT_M ?? "").parseyyyymmddhhmm(),
-        (AIRBORNE_DT_M ?? "").parseyyyymmddhhmm(),
-        (LANDING_DT_M ?? "").parseyyyymmddhhmm(),
-        (ONBLOCK_DT_M ?? "").parseyyyymmddhhmm()
-      ];
-  List<Jiffy?> get blocks => [
-        blocks_m[0] ?? blocks_a[0] ?? blocks_f[0],
-        blocks_m[1] ?? blocks_a[1] ?? blocks_f[1],
-        blocks_m[2] ?? blocks_a[2] ?? blocks_f[2],
-        blocks_m[3] ?? blocks_a[3] ?? blocks_f[3]
-      ];
-  Jiffy? get jdep => blocks[0] ?? jdepest ?? jdepsched;
-  Jiffy? get jarr =>
-      blocks[3] ??
-      blocks[2]?.add(minutes: 5) ??
-      (eet == null ? null : blocks[1]?.addDuration(eet!).add(minutes: 8)) ??
-      (eet == null
-          ? null
-          : blocks[0]?.add(minutes: 5).addDuration(eet!).add(minutes: 8)) ??
-      (eet == null
-          ? null
-          : jdep?.addDuration(eet!).add(minutes: 8).add(minutes: 5)) ??
-      jarrest ??
-      jarrsched;
-  String? EET;
-  Duration? get eet => EET == null ? null : Duration(minutes: int.parse(EET!));
-  Acleg({
-    this.LEG_NO,
-    this.FN_CARRIER,
-    this.FN_NUMBER,
-    this.FN_SUFFIX,
-    this.DAY_OF_ORIGIN,
-    this.AC_OWNER,
-    this.AC_SUBTYPE,
-    this.AC_VERSION,
-    this.AC_REGISTRATION,
-    this.DEP_AP_ACTUAL,
-    this.DEP_AP_SCHED,
-    this.DEP_DT_EST,
-    this.DEP_SCHED_DT,
-    this.ARR_AP_ACTUAL,
-    this.ARR_AP_SCHED,
-    this.ARR_DT_EST,
-    this.ARR_SCHED_DT,
-    this.SLOT_TIME_ACTUAL,
-    this.LEG_TYPE,
-    this.STATUS,
-    this.EMPLOYER_COCKPIT,
-    this.EMPLOYER_CABIN,
-    this.CYCLES,
-    this.DELAY_CODE_01,
-    this.DELAY_CODE_02,
-    this.DELAY_CODE_03,
-    this.DELAY_CODE_04,
-    this.DELAY_TIME_01,
-    this.DELAY_TIME_02,
-    this.DELAY_TIME_03,
-    this.DELAY_TIME_04,
-    this.SUBDELAY_CODE_01,
-    this.SUBDELAY_CODE_02,
-    this.SUBDELAY_CODE_03,
-    this.SUBDELAY_CODE_04,
-    this.PAX_BOOKED_C,
-    this.PAX_BOOKED_Y,
-    this.PAX_BOOKED_TRS_C,
-    this.PAX_BOOKED_TRS_Y,
-    this.PAD_BOOKED_C,
-    this.PAD_BOOKED_Y,
-    this.OFFBLOCK_DT_A,
-    this.AIRBORNE_DT_A,
-    this.LANDING_DT_A,
-    this.ONBLOCK_DT_A,
-    this.OFFBLOCK_DT_F,
-    this.AIRBORNE_DT_F,
-    this.LANDING_DT_F,
-    this.ONBLOCK_DT_F,
-    this.OFFBLOCK_DT_M,
-    this.AIRBORNE_DT_M,
-    this.LANDING_DT_M,
-    this.ONBLOCK_DT_M,
-    this.EET,
-  });
-
-  Acleg copyWith({
-    String? LEG_NO,
-    String? FN_CARRIER,
-    String? FN_NUMBER,
-    String? FN_SUFFIX,
-    String? DAY_OF_ORIGIN,
-    String? AC_OWNER,
-    String? AC_SUBTYPE,
-    String? AC_VERSION,
-    String? AC_REGISTRATION,
-    String? DEP_AP_ACTUAL,
-    String? DEP_AP_SCHED,
-    String? DEP_DT_EST,
-    String? DEP_SCHED_DT,
-    String? ARR_AP_ACTUAL,
-    String? ARR_AP_SCHED,
-    String? ARR_DT_EST,
-    String? ARR_SCHED_DT,
-    String? SLOT_TIME_ACTUAL,
-    String? LEG_TYPE,
-    String? STATUS,
-    String? EMPLOYER_COCKPIT,
-    String? EMPLOYER_CABIN,
-    String? CYCLES,
-    String? DELAY_CODE_01,
-    String? DELAY_CODE_02,
-    String? DELAY_CODE_03,
-    String? DELAY_CODE_04,
-    String? DELAY_TIME_01,
-    String? DELAY_TIME_02,
-    String? DELAY_TIME_03,
-    String? DELAY_TIME_04,
-    String? SUBDELAY_CODE_01,
-    String? SUBDELAY_CODE_02,
-    String? SUBDELAY_CODE_03,
-    String? SUBDELAY_CODE_04,
-    String? PAX_BOOKED_C,
-    String? PAX_BOOKED_Y,
-    String? PAX_BOOKED_TRS_C,
-    String? PAX_BOOKED_TRS_Y,
-    String? PAD_BOOKED_C,
-    String? PAD_BOOKED_Y,
-    String? OFFBLOCK_DT_A,
-    String? AIRBORNE_DT_A,
-    String? LANDING_DT_A,
-    String? ONBLOCK_DT_A,
-    String? OFFBLOCK_DT_F,
-    String? AIRBORNE_DT_F,
-    String? LANDING_DT_F,
-    String? ONBLOCK_DT_F,
-    String? OFFBLOCK_DT_M,
-    String? AIRBORNE_DT_M,
-    String? LANDING_DT_M,
-    String? ONBLOCK_DT_M,
-    String? EET,
-  }) {
-    return Acleg(
-      LEG_NO: LEG_NO ?? this.LEG_NO,
-      FN_CARRIER: FN_CARRIER ?? this.FN_CARRIER,
-      FN_NUMBER: FN_NUMBER ?? this.FN_NUMBER,
-      FN_SUFFIX: FN_SUFFIX ?? this.FN_SUFFIX,
-      DAY_OF_ORIGIN: DAY_OF_ORIGIN ?? this.DAY_OF_ORIGIN,
-      AC_OWNER: AC_OWNER ?? this.AC_OWNER,
-      AC_SUBTYPE: AC_SUBTYPE ?? this.AC_SUBTYPE,
-      AC_VERSION: AC_VERSION ?? this.AC_VERSION,
-      AC_REGISTRATION: AC_REGISTRATION ?? this.AC_REGISTRATION,
-      DEP_AP_ACTUAL: DEP_AP_ACTUAL ?? this.DEP_AP_ACTUAL,
-      DEP_AP_SCHED: DEP_AP_SCHED ?? this.DEP_AP_SCHED,
-      DEP_DT_EST: DEP_DT_EST ?? this.DEP_DT_EST,
-      DEP_SCHED_DT: DEP_SCHED_DT ?? this.DEP_SCHED_DT,
-      ARR_AP_ACTUAL: ARR_AP_ACTUAL ?? this.ARR_AP_ACTUAL,
-      ARR_AP_SCHED: ARR_AP_SCHED ?? this.ARR_AP_SCHED,
-      ARR_DT_EST: ARR_DT_EST ?? this.ARR_DT_EST,
-      ARR_SCHED_DT: ARR_SCHED_DT ?? this.ARR_SCHED_DT,
-      SLOT_TIME_ACTUAL: SLOT_TIME_ACTUAL ?? this.SLOT_TIME_ACTUAL,
-      LEG_TYPE: LEG_TYPE ?? this.LEG_TYPE,
-      STATUS: STATUS ?? this.STATUS,
-      EMPLOYER_COCKPIT: EMPLOYER_COCKPIT ?? this.EMPLOYER_COCKPIT,
-      EMPLOYER_CABIN: EMPLOYER_CABIN ?? this.EMPLOYER_CABIN,
-      CYCLES: CYCLES ?? this.CYCLES,
-      DELAY_CODE_01: DELAY_CODE_01 ?? this.DELAY_CODE_01,
-      DELAY_CODE_02: DELAY_CODE_02 ?? this.DELAY_CODE_02,
-      DELAY_CODE_03: DELAY_CODE_03 ?? this.DELAY_CODE_03,
-      DELAY_CODE_04: DELAY_CODE_04 ?? this.DELAY_CODE_04,
-      DELAY_TIME_01: DELAY_TIME_01 ?? this.DELAY_TIME_01,
-      DELAY_TIME_02: DELAY_TIME_02 ?? this.DELAY_TIME_02,
-      DELAY_TIME_03: DELAY_TIME_03 ?? this.DELAY_TIME_03,
-      DELAY_TIME_04: DELAY_TIME_04 ?? this.DELAY_TIME_04,
-      SUBDELAY_CODE_01: SUBDELAY_CODE_01 ?? this.SUBDELAY_CODE_01,
-      SUBDELAY_CODE_02: SUBDELAY_CODE_02 ?? this.SUBDELAY_CODE_02,
-      SUBDELAY_CODE_03: SUBDELAY_CODE_03 ?? this.SUBDELAY_CODE_03,
-      SUBDELAY_CODE_04: SUBDELAY_CODE_04 ?? this.SUBDELAY_CODE_04,
-      PAX_BOOKED_C: PAX_BOOKED_C ?? this.PAX_BOOKED_C,
-      PAX_BOOKED_Y: PAX_BOOKED_Y ?? this.PAX_BOOKED_Y,
-      PAX_BOOKED_TRS_C: PAX_BOOKED_TRS_C ?? this.PAX_BOOKED_TRS_C,
-      PAX_BOOKED_TRS_Y: PAX_BOOKED_TRS_Y ?? this.PAX_BOOKED_TRS_Y,
-      PAD_BOOKED_C: PAD_BOOKED_C ?? this.PAD_BOOKED_C,
-      PAD_BOOKED_Y: PAD_BOOKED_Y ?? this.PAD_BOOKED_Y,
-      OFFBLOCK_DT_A: OFFBLOCK_DT_A ?? this.OFFBLOCK_DT_A,
-      AIRBORNE_DT_A: AIRBORNE_DT_A ?? this.AIRBORNE_DT_A,
-      LANDING_DT_A: LANDING_DT_A ?? this.LANDING_DT_A,
-      ONBLOCK_DT_A: ONBLOCK_DT_A ?? this.ONBLOCK_DT_A,
-      OFFBLOCK_DT_F: OFFBLOCK_DT_F ?? this.OFFBLOCK_DT_F,
-      AIRBORNE_DT_F: AIRBORNE_DT_F ?? this.AIRBORNE_DT_F,
-      LANDING_DT_F: LANDING_DT_F ?? this.LANDING_DT_F,
-      ONBLOCK_DT_F: ONBLOCK_DT_F ?? this.ONBLOCK_DT_F,
-      OFFBLOCK_DT_M: OFFBLOCK_DT_M ?? this.OFFBLOCK_DT_M,
-      AIRBORNE_DT_M: AIRBORNE_DT_M ?? this.AIRBORNE_DT_M,
-      LANDING_DT_M: LANDING_DT_M ?? this.LANDING_DT_M,
-      ONBLOCK_DT_M: ONBLOCK_DT_M ?? this.ONBLOCK_DT_M,
-      EET: EET ?? this.EET,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return <String, dynamic>{
-      'LEG_NO': LEG_NO,
-      'FN_CARRIER': FN_CARRIER,
-      'FN_NUMBER': FN_NUMBER,
-      'FN_SUFFIX': FN_SUFFIX,
-      'DAY_OF_ORIGIN': DAY_OF_ORIGIN,
-      'AC_OWNER': AC_OWNER,
-      'AC_SUBTYPE': AC_SUBTYPE,
-      'AC_VERSION': AC_VERSION,
-      'AC_REGISTRATION': AC_REGISTRATION,
-      'DEP_AP_ACTUAL': DEP_AP_ACTUAL,
-      'DEP_AP_SCHED': DEP_AP_SCHED,
-      'DEP_DT_EST': DEP_DT_EST,
-      'DEP_SCHED_DT': DEP_SCHED_DT,
-      'ARR_AP_ACTUAL': ARR_AP_ACTUAL,
-      'ARR_AP_SCHED': ARR_AP_SCHED,
-      'ARR_DT_EST': ARR_DT_EST,
-      'ARR_SCHED_DT': ARR_SCHED_DT,
-      'SLOT_TIME_ACTUAL': SLOT_TIME_ACTUAL,
-      'LEG_TYPE': LEG_TYPE,
-      'STATUS': STATUS,
-      'EMPLOYER_COCKPIT': EMPLOYER_COCKPIT,
-      'EMPLOYER_CABIN': EMPLOYER_CABIN,
-      'CYCLES': CYCLES,
-      'DELAY_CODE_01': DELAY_CODE_01,
-      'DELAY_CODE_02': DELAY_CODE_02,
-      'DELAY_CODE_03': DELAY_CODE_03,
-      'DELAY_CODE_04': DELAY_CODE_04,
-      'DELAY_TIME_01': DELAY_TIME_01,
-      'DELAY_TIME_02': DELAY_TIME_02,
-      'DELAY_TIME_03': DELAY_TIME_03,
-      'DELAY_TIME_04': DELAY_TIME_04,
-      'SUBDELAY_CODE_01': SUBDELAY_CODE_01,
-      'SUBDELAY_CODE_02': SUBDELAY_CODE_02,
-      'SUBDELAY_CODE_03': SUBDELAY_CODE_03,
-      'SUBDELAY_CODE_04': SUBDELAY_CODE_04,
-      'PAX_BOOKED_C': PAX_BOOKED_C,
-      'PAX_BOOKED_Y': PAX_BOOKED_Y,
-      'PAX_BOOKED_TRS_C': PAX_BOOKED_TRS_C,
-      'PAX_BOOKED_TRS_Y': PAX_BOOKED_TRS_Y,
-      'PAD_BOOKED_C': PAD_BOOKED_C,
-      'PAD_BOOKED_Y': PAD_BOOKED_Y,
-      'OFFBLOCK_DT_A': OFFBLOCK_DT_A,
-      'AIRBORNE_DT_A': AIRBORNE_DT_A,
-      'LANDING_DT_A': LANDING_DT_A,
-      'ONBLOCK_DT_A': ONBLOCK_DT_A,
-      'OFFBLOCK_DT_F': OFFBLOCK_DT_F,
-      'AIRBORNE_DT_F': AIRBORNE_DT_F,
-      'LANDING_DT_F': LANDING_DT_F,
-      'ONBLOCK_DT_F': ONBLOCK_DT_F,
-      'OFFBLOCK_DT_M': OFFBLOCK_DT_M,
-      'AIRBORNE_DT_M': AIRBORNE_DT_M,
-      'LANDING_DT_M': LANDING_DT_M,
-      'ONBLOCK_DT_M': ONBLOCK_DT_M,
-      'EET': EET,
-    };
-  }
-
-  factory Acleg.fromList(List datalist) {
-    //print(datalist);
-    if (datalist.length >= 54) {
-      return Acleg(
-          LEG_NO: datalist[0],
-          FN_CARRIER: datalist[1],
-          FN_NUMBER: datalist[2],
-          FN_SUFFIX: datalist[3],
-          DAY_OF_ORIGIN: datalist[4],
-          AC_OWNER: datalist[5],
-          AC_SUBTYPE: datalist[6],
-          AC_VERSION: datalist[7],
-          AC_REGISTRATION: datalist[8],
-          DEP_AP_ACTUAL: datalist[9],
-          DEP_AP_SCHED: datalist[10],
-          DEP_DT_EST: datalist[11],
-          DEP_SCHED_DT: datalist[12],
-          ARR_AP_ACTUAL: datalist[13],
-          ARR_AP_SCHED: datalist[14],
-          ARR_DT_EST: datalist[15],
-          ARR_SCHED_DT: datalist[16],
-          SLOT_TIME_ACTUAL: datalist[17],
-          LEG_TYPE: datalist[18],
-          STATUS: datalist[19],
-          EMPLOYER_COCKPIT: datalist[20],
-          EMPLOYER_CABIN: datalist[21],
-          CYCLES: datalist[22],
-          DELAY_CODE_01: datalist[23],
-          DELAY_CODE_02: datalist[24],
-          DELAY_CODE_03: datalist[25],
-          DELAY_CODE_04: datalist[26],
-          DELAY_TIME_01: datalist[27],
-          DELAY_TIME_02: datalist[28],
-          DELAY_TIME_03: datalist[29],
-          DELAY_TIME_04: datalist[30],
-          SUBDELAY_CODE_01: datalist[31],
-          SUBDELAY_CODE_02: datalist[32],
-          SUBDELAY_CODE_03: datalist[33],
-          SUBDELAY_CODE_04: datalist[34],
-          PAX_BOOKED_C: datalist[35],
-          PAX_BOOKED_Y: datalist[36],
-          PAX_BOOKED_TRS_C: datalist[37],
-          PAX_BOOKED_TRS_Y: datalist[38],
-          PAD_BOOKED_C: datalist[39],
-          PAD_BOOKED_Y: datalist[40],
-          OFFBLOCK_DT_A: datalist[41],
-          AIRBORNE_DT_A: datalist[42],
-          LANDING_DT_A: datalist[43],
-          ONBLOCK_DT_A: datalist[44],
-          OFFBLOCK_DT_F: datalist[45],
-          AIRBORNE_DT_F: datalist[46],
-          LANDING_DT_F: datalist[47],
-          ONBLOCK_DT_F: datalist[48],
-          OFFBLOCK_DT_M: datalist[49],
-          AIRBORNE_DT_M: datalist[50],
-          LANDING_DT_M: datalist[51],
-          ONBLOCK_DT_M: datalist[52],
-          EET: datalist[53]);
-    } else {
-      return Acleg();
-    }
-  }
-
-  factory Acleg.fromMap(Map<String, dynamic> map) {
-    return Acleg(
-      LEG_NO: map['LEG_NO'] != null ? map['LEG_NO'] as String : null,
-      FN_CARRIER:
-          map['FN_CARRIER'] != null ? map['FN_CARRIER'] as String : null,
-      FN_NUMBER: map['FN_NUMBER'] != null ? map['FN_NUMBER'] as String : null,
-      FN_SUFFIX: map['FN_SUFFIX'] != null ? map['FN_SUFFIX'] as String : null,
-      DAY_OF_ORIGIN:
-          map['DAY_OF_ORIGIN'] != null ? map['DAY_OF_ORIGIN'] as String : null,
-      AC_OWNER: map['AC_OWNER'] != null ? map['AC_OWNER'] as String : null,
-      AC_SUBTYPE:
-          map['AC_SUBTYPE'] != null ? map['AC_SUBTYPE'] as String : null,
-      AC_VERSION:
-          map['AC_VERSION'] != null ? map['AC_VERSION'] as String : null,
-      AC_REGISTRATION: map['AC_REGISTRATION'] != null
-          ? map['AC_REGISTRATION'] as String
-          : null,
-      DEP_AP_ACTUAL:
-          map['DEP_AP_ACTUAL'] != null ? map['DEP_AP_ACTUAL'] as String : null,
-      DEP_AP_SCHED:
-          map['DEP_AP_SCHED'] != null ? map['DEP_AP_SCHED'] as String : null,
-      DEP_DT_EST:
-          map['DEP_DT_EST'] != null ? map['DEP_DT_EST'] as String : null,
-      DEP_SCHED_DT:
-          map['DEP_SCHED_DT'] != null ? map['DEP_SCHED_DT'] as String : null,
-      ARR_AP_ACTUAL:
-          map['ARR_AP_ACTUAL'] != null ? map['ARR_AP_ACTUAL'] as String : null,
-      ARR_AP_SCHED:
-          map['ARR_AP_SCHED'] != null ? map['ARR_AP_SCHED'] as String : null,
-      ARR_DT_EST:
-          map['ARR_DT_EST'] != null ? map['ARR_DT_EST'] as String : null,
-      ARR_SCHED_DT:
-          map['ARR_SCHED_DT'] != null ? map['ARR_SCHED_DT'] as String : null,
-      SLOT_TIME_ACTUAL: map['SLOT_TIME_ACTUAL'] != null
-          ? map['SLOT_TIME_ACTUAL'] as String
-          : null,
-      LEG_TYPE: map['LEG_TYPE'] != null ? map['LEG_TYPE'] as String : null,
-      EMPLOYER_COCKPIT: map['EMPLOYER_COCKPIT'] != null
-          ? map['EMPLOYER_COCKPIT'] as String
-          : null,
-      EMPLOYER_CABIN: map['EMPLOYER_CABIN'] != null
-          ? map['EMPLOYER_CABIN'] as String
-          : null,
-//      CYCLES: map['CYCLES'] != null ? map['CYCLES'] as String : null,
-      DELAY_CODE_01:
-          map['DELAY_CODE_01'] != null ? map['DELAY_CODE_01'] as String : null,
-      DELAY_CODE_02:
-          map['DELAY_CODE_02'] != null ? map['DELAY_CODE_02'] as String : null,
-      DELAY_CODE_03:
-          map['DELAY_CODE_03'] != null ? map['DELAY_CODE_03'] as String : null,
-      DELAY_CODE_04:
-          map['DELAY_CODE_04'] != null ? map['DELAY_CODE_04'] as String : null,
-      DELAY_TIME_01:
-          map['DELAY_TIME_01'] != null ? map['DELAY_TIME_01'] as String : null,
-      DELAY_TIME_02:
-          map['DELAY_TIME_02'] != null ? map['DELAY_TIME_02'] as String : null,
-      DELAY_TIME_03:
-          map['DELAY_TIME_03'] != null ? map['DELAY_TIME_03'] as String : null,
-      DELAY_TIME_04:
-          map['DELAY_TIME_04'] != null ? map['DELAY_TIME_04'] as String : null,
-      SUBDELAY_CODE_01: map['SUBDELAY_CODE_01'] != null
-          ? map['SUBDELAY_CODE_01'] as String
-          : null,
-      SUBDELAY_CODE_02: map['SUBDELAY_CODE_02'] != null
-          ? map['SUBDELAY_CODE_02'] as String
-          : null,
-      SUBDELAY_CODE_03: map['SUBDELAY_CODE_03'] != null
-          ? map['SUBDELAY_CODE_03'] as String
-          : null,
-      SUBDELAY_CODE_04: map['SUBDELAY_CODE_04'] != null
-          ? map['SUBDELAY_CODE_04'] as String
-          : null,
-      PAX_BOOKED_C:
-          map['PAX_BOOKED_C'] != null ? map['PAX_BOOKED_C'] as String : null,
-      PAX_BOOKED_Y:
-          map['PAX_BOOKED_Y'] != null ? map['PAX_BOOKED_Y'] as String : null,
-      PAX_BOOKED_TRS_C: map['PAX_BOOKED_TRS_C'] != null
-          ? map['PAX_BOOKED_TRS_C'] as String
-          : null,
-      PAX_BOOKED_TRS_Y: map['PAX_BOOKED_TRS_Y'] != null
-          ? map['PAX_BOOKED_TRS_Y'] as String
-          : null,
-      PAD_BOOKED_C:
-          map['PAD_BOOKED_C'] != null ? map['PAD_BOOKED_C'] as String : null,
-      PAD_BOOKED_Y:
-          map['PAD_BOOKED_Y'] != null ? map['PAD_BOOKED_Y'] as String : null,
-      OFFBLOCK_DT_A:
-          map['OFFBLOCK_DT_A'] != null ? map['OFFBLOCK_DT_A'] as String : null,
-      AIRBORNE_DT_A:
-          map['AIRBORNE_DT_A'] != null ? map['AIRBORNE_DT_A'] as String : null,
-      LANDING_DT_A:
-          map['LANDING_DT_A'] != null ? map['LANDING_DT_A'] as String : null,
-      ONBLOCK_DT_A:
-          map['ONBLOCK_DT_A'] != null ? map['ONBLOCK_DT_A'] as String : null,
-      OFFBLOCK_DT_F:
-          map['OFFBLOCK_DT_F'] != null ? map['OFFBLOCK_DT_F'] as String : null,
-      AIRBORNE_DT_F:
-          map['AIRBORNE_DT_F'] != null ? map['AIRBORNE_DT_F'] as String : null,
-      LANDING_DT_F:
-          map['LANDING_DT_F'] != null ? map['LANDING_DT_F'] as String : null,
-      ONBLOCK_DT_F:
-          map['ONBLOCK_DT_F'] != null ? map['ONBLOCK_DT_F'] as String : null,
-      OFFBLOCK_DT_M:
-          map['OFFBLOCK_DT_M'] != null ? map['OFFBLOCK_DT_M'] as String : null,
-      AIRBORNE_DT_M:
-          map['AIRBORNE_DT_M'] != null ? map['AIRBORNE_DT_M'] as String : null,
-      LANDING_DT_M:
-          map['LANDING_DT_M'] != null ? map['LANDING_DT_M'] as String : null,
-      ONBLOCK_DT_M:
-          map['ONBLOCK_DT_M'] != null ? map['ONBLOCK_DT_M'] as String : null,
-      EET: map['EET'] != null ? map['EET'] as String : null,
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory Acleg.fromJson(String source) =>
-      Acleg.fromMap(json.decode(source) as Map<String, dynamic>);
-
-  @override
-  String toString() {
-    return 'Acleg(LEG_NO: $LEG_NO, FN_CARRIER: $FN_CARRIER, FN_NUMBER: $FN_NUMBER, FN_SUFFIX: $FN_SUFFIX, DAY_OF_ORIGIN: $DAY_OF_ORIGIN, AC_OWNER: $AC_OWNER, AC_SUBTYPE: $AC_SUBTYPE, AC_VERSION: $AC_VERSION, AC_REGISTRATION: $AC_REGISTRATION, DEP_AP_ACTUAL: $DEP_AP_ACTUAL, DEP_AP_SCHED: $DEP_AP_SCHED, DEP_DT_EST: $DEP_DT_EST, DEP_SCHED_DT: $DEP_SCHED_DT, ARR_AP_ACTUAL: $ARR_AP_ACTUAL, ARR_AP_SCHED: $ARR_AP_SCHED, ARR_DT_EST: $ARR_DT_EST, ARR_SCHED_DT: $ARR_SCHED_DT, SLOT_TIME_ACTUAL: $SLOT_TIME_ACTUAL, LEG_TYPE: $LEG_TYPE, EMPLOYER_COCKPIT: $EMPLOYER_COCKPIT, EMPLOYER_CABIN: $EMPLOYER_CABIN, CYCLES: $CYCLES, DELAY_CODE_01: $DELAY_CODE_01, DELAY_CODE_02: $DELAY_CODE_02, DELAY_CODE_03: $DELAY_CODE_03, DELAY_CODE_04: $DELAY_CODE_04, DELAY_TIME_01: $DELAY_TIME_01, DELAY_TIME_02: $DELAY_TIME_02, DELAY_TIME_03: $DELAY_TIME_03, DELAY_TIME_04: $DELAY_TIME_04, SUBDELAY_CODE_01: $SUBDELAY_CODE_01, SUBDELAY_CODE_02: $SUBDELAY_CODE_02, SUBDELAY_CODE_03: $SUBDELAY_CODE_03, SUBDELAY_CODE_04: $SUBDELAY_CODE_04, PAX_BOOKED_C: $PAX_BOOKED_C, PAX_BOOKED_Y: $PAX_BOOKED_Y, PAX_BOOKED_TRS_C: $PAX_BOOKED_TRS_C, PAX_BOOKED_TRS_Y: $PAX_BOOKED_TRS_Y, PAD_BOOKED_C: $PAD_BOOKED_C, PAD_BOOKED_Y: $PAD_BOOKED_Y, OFFBLOCK_DT_A: $OFFBLOCK_DT_A, AIRBORNE_DT_A: $AIRBORNE_DT_A, LANDING_DT_A: $LANDING_DT_A, ONBLOCK_DT_A: $ONBLOCK_DT_A, OFFBLOCK_DT_F: $OFFBLOCK_DT_F, AIRBORNE_DT_F: $AIRBORNE_DT_F, LANDING_DT_F: $LANDING_DT_F, ONBLOCK_DT_F: $ONBLOCK_DT_F, OFFBLOCK_DT_M: $OFFBLOCK_DT_M, AIRBORNE_DT_M: $AIRBORNE_DT_M, LANDING_DT_M: $LANDING_DT_M, ONBLOCK_DT_M: $ONBLOCK_DT_M, EET: $EET)';
-  }
-
-  @override
-  bool operator ==(covariant Acleg other) {
-    if (identical(this, other)) return true;
-
-    return other.LEG_NO == LEG_NO &&
-        other.FN_CARRIER == FN_CARRIER &&
-        other.FN_NUMBER == FN_NUMBER &&
-        other.FN_SUFFIX == FN_SUFFIX &&
-        other.DAY_OF_ORIGIN == DAY_OF_ORIGIN &&
-        other.AC_OWNER == AC_OWNER &&
-        other.AC_SUBTYPE == AC_SUBTYPE &&
-        other.AC_VERSION == AC_VERSION &&
-        other.AC_REGISTRATION == AC_REGISTRATION &&
-        other.DEP_AP_ACTUAL == DEP_AP_ACTUAL &&
-        other.DEP_AP_SCHED == DEP_AP_SCHED &&
-        other.DEP_DT_EST == DEP_DT_EST &&
-        other.DEP_SCHED_DT == DEP_SCHED_DT &&
-        other.ARR_AP_ACTUAL == ARR_AP_ACTUAL &&
-        other.ARR_AP_SCHED == ARR_AP_SCHED &&
-        other.ARR_DT_EST == ARR_DT_EST &&
-        other.ARR_SCHED_DT == ARR_SCHED_DT &&
-        other.SLOT_TIME_ACTUAL == SLOT_TIME_ACTUAL &&
-        other.LEG_TYPE == LEG_TYPE &&
-        other.EMPLOYER_COCKPIT == EMPLOYER_COCKPIT &&
-        other.EMPLOYER_CABIN == EMPLOYER_CABIN &&
-        other.CYCLES == CYCLES &&
-        other.DELAY_CODE_01 == DELAY_CODE_01 &&
-        other.DELAY_CODE_02 == DELAY_CODE_02 &&
-        other.DELAY_CODE_03 == DELAY_CODE_03 &&
-        other.DELAY_CODE_04 == DELAY_CODE_04 &&
-        other.DELAY_TIME_01 == DELAY_TIME_01 &&
-        other.DELAY_TIME_02 == DELAY_TIME_02 &&
-        other.DELAY_TIME_03 == DELAY_TIME_03 &&
-        other.DELAY_TIME_04 == DELAY_TIME_04 &&
-        other.SUBDELAY_CODE_01 == SUBDELAY_CODE_01 &&
-        other.SUBDELAY_CODE_02 == SUBDELAY_CODE_02 &&
-        other.SUBDELAY_CODE_03 == SUBDELAY_CODE_03 &&
-        other.SUBDELAY_CODE_04 == SUBDELAY_CODE_04 &&
-        other.PAX_BOOKED_C == PAX_BOOKED_C &&
-        other.PAX_BOOKED_Y == PAX_BOOKED_Y &&
-        other.PAX_BOOKED_TRS_C == PAX_BOOKED_TRS_C &&
-        other.PAX_BOOKED_TRS_Y == PAX_BOOKED_TRS_Y &&
-        other.PAD_BOOKED_C == PAD_BOOKED_C &&
-        other.PAD_BOOKED_Y == PAD_BOOKED_Y &&
-        other.OFFBLOCK_DT_A == OFFBLOCK_DT_A &&
-        other.AIRBORNE_DT_A == AIRBORNE_DT_A &&
-        other.LANDING_DT_A == LANDING_DT_A &&
-        other.ONBLOCK_DT_A == ONBLOCK_DT_A &&
-        other.OFFBLOCK_DT_F == OFFBLOCK_DT_F &&
-        other.AIRBORNE_DT_F == AIRBORNE_DT_F &&
-        other.LANDING_DT_F == LANDING_DT_F &&
-        other.ONBLOCK_DT_F == ONBLOCK_DT_F &&
-        other.OFFBLOCK_DT_M == OFFBLOCK_DT_M &&
-        other.AIRBORNE_DT_M == AIRBORNE_DT_M &&
-        other.LANDING_DT_M == LANDING_DT_M &&
-        other.ONBLOCK_DT_M == ONBLOCK_DT_M &&
-        other.EET == EET;
-  }
-
-  @override
-  int get hashCode {
-    return LEG_NO.hashCode ^
-        FN_CARRIER.hashCode ^
-        FN_NUMBER.hashCode ^
-        FN_SUFFIX.hashCode ^
-        DAY_OF_ORIGIN.hashCode ^
-        AC_OWNER.hashCode ^
-        AC_SUBTYPE.hashCode ^
-        AC_VERSION.hashCode ^
-        AC_REGISTRATION.hashCode ^
-        DEP_AP_ACTUAL.hashCode ^
-        DEP_AP_SCHED.hashCode ^
-        DEP_DT_EST.hashCode ^
-        DEP_SCHED_DT.hashCode ^
-        ARR_AP_ACTUAL.hashCode ^
-        ARR_AP_SCHED.hashCode ^
-        ARR_DT_EST.hashCode ^
-        ARR_SCHED_DT.hashCode ^
-        SLOT_TIME_ACTUAL.hashCode ^
-        LEG_TYPE.hashCode ^
-        EMPLOYER_COCKPIT.hashCode ^
-        EMPLOYER_CABIN.hashCode ^
-        CYCLES.hashCode ^
-        DELAY_CODE_01.hashCode ^
-        DELAY_CODE_02.hashCode ^
-        DELAY_CODE_03.hashCode ^
-        DELAY_CODE_04.hashCode ^
-        DELAY_TIME_01.hashCode ^
-        DELAY_TIME_02.hashCode ^
-        DELAY_TIME_03.hashCode ^
-        DELAY_TIME_04.hashCode ^
-        SUBDELAY_CODE_01.hashCode ^
-        SUBDELAY_CODE_02.hashCode ^
-        SUBDELAY_CODE_03.hashCode ^
-        SUBDELAY_CODE_04.hashCode ^
-        PAX_BOOKED_C.hashCode ^
-        PAX_BOOKED_Y.hashCode ^
-        PAX_BOOKED_TRS_C.hashCode ^
-        PAX_BOOKED_TRS_Y.hashCode ^
-        PAD_BOOKED_C.hashCode ^
-        PAD_BOOKED_Y.hashCode ^
-        OFFBLOCK_DT_A.hashCode ^
-        AIRBORNE_DT_A.hashCode ^
-        LANDING_DT_A.hashCode ^
-        ONBLOCK_DT_A.hashCode ^
-        OFFBLOCK_DT_F.hashCode ^
-        AIRBORNE_DT_F.hashCode ^
-        LANDING_DT_F.hashCode ^
-        ONBLOCK_DT_F.hashCode ^
-        OFFBLOCK_DT_M.hashCode ^
-        AIRBORNE_DT_M.hashCode ^
-        LANDING_DT_M.hashCode ^
-        ONBLOCK_DT_M.hashCode ^
-        EET.hashCode;
-  }
-}

+ 0 - 1717
lib/csv/data.bak

@@ -1,1717 +0,0 @@
-// ignore_for_file: non_constant_identifier_names
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-
-import 'package:collection/collection.dart';
-import 'package:flutter/foundation.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:supabase_flutter/supabase_flutter.dart';
-//import 'package:supabase_flutter/supabase_flutter.dart';
-
-import "package:tp5/core/utils.dart";
-import "package:tp5/csv/csv_data.dart";
-
-class CrewFilter {
-  String? college;
-  String? ac;
-  String? tlc;
-  String? fname;
-  String? lname;
-  String? searchname;
-  CrewFilter({
-    this.college,
-    this.ac,
-    this.tlc,
-    this.fname,
-    this.lname,
-    this.searchname,
-  });
-
-  CrewFilter copyWith({
-    ValueGetter<String?>? college,
-    ValueGetter<String?>? ac,
-    ValueGetter<String?>? tlc,
-    ValueGetter<String?>? fname,
-    ValueGetter<String?>? lname,
-    ValueGetter<String?>? searchname,
-  }) {
-    return CrewFilter(
-      college: college != null ? college() : this.college,
-      ac: ac != null ? ac() : this.ac,
-      tlc: tlc != null ? tlc() : this.tlc,
-      fname: fname != null ? fname() : this.fname,
-      lname: lname != null ? lname() : this.lname,
-      searchname: searchname != null ? searchname() : this.searchname,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'college': college,
-      'ac': ac,
-      'tlc': tlc,
-      'fname': fname,
-      'lname': lname,
-      'searchname': searchname,
-    };
-  }
-
-  factory CrewFilter.fromMap(Map<String, dynamic> map) {
-    return CrewFilter(
-      college: map['college'],
-      ac: map['ac'],
-      tlc: map['tlc'],
-      fname: map['fname'],
-      lname: map['lname'],
-      searchname: map['searchname'],
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory CrewFilter.fromJson(String source) =>
-      CrewFilter.fromMap(json.decode(source));
-
-  @override
-  String toString() {
-    return 'CrewFilter(college: $college, ac: $ac, tlc: $tlc, fname: $fname, lname: $lname, searchname: $searchname)';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-
-    return other is CrewFilter &&
-        other.college == college &&
-        other.ac == ac &&
-        other.tlc == tlc &&
-        other.fname == fname &&
-        other.lname == lname &&
-        other.searchname == searchname;
-  }
-
-  @override
-  int get hashCode {
-    return college.hashCode ^
-        ac.hashCode ^
-        tlc.hashCode ^
-        fname.hashCode ^
-        lname.hashCode ^
-        searchname.hashCode;
-  }
-}
-
-class FlightFilter {
-  String? al;
-  String? fnum;
-  String? date;
-  String? dep;
-  String? arr;
-  Jiffy? jdep;
-  Jiffy? jarr;
-  String? tlc;
-  String? reg;
-  FlightFilter(
-      {this.al,
-      this.fnum,
-      this.date,
-      this.dep,
-      this.arr,
-      this.jdep,
-      this.jarr,
-      this.tlc,
-      this.reg});
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-
-    return other is FlightFilter &&
-        other.al == al &&
-        other.fnum == fnum &&
-        other.date == date &&
-        other.dep == dep &&
-        other.arr == arr &&
-        other.jdep == jdep &&
-        other.jarr == jarr &&
-        other.tlc == tlc &&
-        other.reg == reg;
-  }
-
-  FlightFilter copyWith({
-    ValueGetter<String?>? al,
-    ValueGetter<String?>? fnum,
-    ValueGetter<String?>? date,
-    ValueGetter<String?>? dep,
-    ValueGetter<String?>? arr,
-    ValueGetter<Jiffy?>? jdep,
-    ValueGetter<Jiffy?>? jarr,
-    ValueGetter<String?>? tlc,
-    ValueGetter<String?>? reg,
-  }) {
-    return FlightFilter(
-      al: al != null ? al() : this.al,
-      fnum: fnum != null ? fnum() : this.fnum,
-      date: date != null ? date() : this.date,
-      dep: dep != null ? dep() : this.dep,
-      arr: arr != null ? arr() : this.arr,
-      jdep: jdep != null ? jdep() : this.jdep,
-      jarr: jarr != null ? jarr() : this.jarr,
-      tlc: tlc != null ? tlc() : this.tlc,
-      reg: reg != null ? reg() : this.reg,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'al': al,
-      'fnum': fnum,
-      'date': date,
-      'dep': dep,
-      'arr': arr,
-      'jdep': jdep?.toString(),
-      'jarr': jarr?.toString(),
-      'tlc': tlc,
-      'reg': reg,
-    };
-  }
-
-  factory FlightFilter.fromMap(Map<String, dynamic> map) {
-    return FlightFilter(
-      al: map['al'],
-      fnum: map['fnum'],
-      date: map['date'],
-      dep: map['dep'],
-      arr: map['arr'],
-      jdep: map['jdep'] != null ? Jiffy.parse(map['jdep']) : null,
-      jarr: map['jarr'] != null ? Jiffy.parse(map['jarr']) : null,
-      tlc: map['tlc'],
-      reg: map['reg'],
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory FlightFilter.fromJson(String source) =>
-      FlightFilter.fromMap(json.decode(source));
-
-  @override
-  String toString() {
-    return 'FlightFilter(al: $al, fnum: $fnum, date: $date, dep: $dep, arr: $arr, jdep: $jdep, jarr: $jarr, tlc: $tlc, reg: $reg)';
-  }
-
-  @override
-  int get hashCode {
-    return al.hashCode ^
-        fnum.hashCode ^
-        date.hashCode ^
-        dep.hashCode ^
-        arr.hashCode ^
-        jdep.hashCode ^
-        jarr.hashCode ^
-        tlc.hashCode ^
-        reg.hashCode;
-  }
-}
-
-final pnlegByTlcProvider =
-    Provider. /*autoDispose.*/ family<List<Pnleg>, String>((ref, tlc) => ref
-        .watch(dataProvider)
-        .pnleg
-        .where((leg) => leg.tlc == tlc)
-        .sortedBy((e) =>
-            e.jdep?.dateTime ??
-            Jiffy.parse(e.depdate ?? "01/01/2001",
-                    pattern: "dd/MM/yyyy", isUtc: true)
-                .dateTime)
-        .toList());
-
-final pnlegProvider = Provider. /*autoDispose.*/ family<List<Pnleg>, FlightFilter>(
-    (ref, flightFilter) => ref
-        .watch(dataProvider)
-        .pnleg
-        .where((leg) =>
-            (leg.al == (flightFilter.al ?? leg.al)) &&
-            (leg.fnum == (flightFilter.fnum ?? leg.fnum)) &&
-            // (leg.jdep?.yMd ==
-            //     (flightFilter.date ?? leg.jdep?.yMd)) && //format yyyy-MM-dd
-            (leg.dep == (flightFilter.dep ?? leg.dep)) &&
-            (leg.arr == (flightFilter.arr ?? leg.arr)) &&
-            (flightFilter.jdep == null ||
-                (leg.jdep != null &&
-                    flightFilter.jdep != null &&
-                    flightFilter.jdep!.isBetween(leg.jdep!.subtract(hours: 5),
-                        leg.jdep!.add(hours: 5)))) &&
-            (flightFilter.jarr == null ||
-                (leg.jarr != null &&
-                    flightFilter.jarr != null &&
-                    flightFilter.jarr!.isBetween(leg.jarr!.subtract(hours: 5),
-                        leg.jarr!.add(hours: 5)))) &&
-            (leg.tlc == (flightFilter.tlc ?? leg.tlc)))
-        .toList());
-
-/*
-final pnlegInterval = Provider((ref) {
-  final pnleg = ref.watch(dataProvider).pnleg;
-  return pnleg.where((leg) => leg.jdep != null && leg.jarr != null).toList();
-});
-
-
-final pnlegDates = Provider((ref) {
-  final pnleg = ref.watch(dataProvider).pnleg;
-  return pnleg.fold(
-      <Jiffy?>{},
-      (t, e) => [...t, e.jdep?.startOf(Unit.day)]
-          .nonNulls
-          .sortedBy((k) => k.millisecondsSinceEpoch.toString())
-          .toSet());
-});
-
-final pnlegTlcs = Provider((ref) {
-  final data = ref.watch(dataProvider);
-  final pnleg = data.pnleg;
-  final qualif = data.qualif;
-
-  return pnleg.fold(<String?>{}, (t, e) => {...t, e.tlc}).sortedBy((k) =>
-      qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
-});
-*/
-
-final aclegProvider = Provider.autoDispose.family<List<Acleg>, FlightFilter>(
-    (ref, flightFilter) => ref
-        .watch(dataProvider)
-        .acleg
-        .where((leg) =>
-            (leg.FN_CARRIER == (flightFilter.al ?? leg.FN_CARRIER)) &&
-            (leg.FN_NUMBER == (flightFilter.fnum ?? leg.FN_NUMBER)) &&
-//            (leg.jdep?.yMd ==
-//                (flightFilter.date ?? leg.jdep?.yMd)) && //format yyyy-MM-dd
-            (leg.DEP_AP_ACTUAL == (flightFilter.dep ?? leg.DEP_AP_ACTUAL)) &&
-            (leg.DEP_AP_SCHED == (flightFilter.dep ?? leg.DEP_AP_SCHED)) &&
-            (leg.ARR_AP_ACTUAL == (flightFilter.arr ?? leg.ARR_AP_ACTUAL)) &&
-            (leg.ARR_AP_SCHED == (flightFilter.arr ?? leg.ARR_AP_SCHED)) &&
-            (flightFilter.jdep == null ||
-                (leg.jdep != null &&
-                    flightFilter.jdep != null &&
-                    flightFilter.jdep!.isBetween(leg.jdep!.subtract(hours: 5),
-                        leg.jdep!.add(hours: 5)))) &&
-            (flightFilter.jarr == null ||
-                (leg.jarr != null &&
-                    flightFilter.jarr != null &&
-                    flightFilter.jarr!.isBetween(leg.jarr!.subtract(hours: 5),
-                        leg.jarr!.add(hours: 5)))) &&
-            (leg.AC_REGISTRATION == (flightFilter.reg ?? leg.AC_REGISTRATION)))
-        .toList());
-
-final qualifProvider = Provider.family<List<Qualif>, CrewFilter>(
-    (ref, crewFilter) => ref
-        .watch(dataProvider)
-        .qualif
-        .where((x) => (((crewFilter.tlc ?? x.tlc) == x.tlc &&
-            (crewFilter.college ?? x.college) == x.college &&
-            (crewFilter.ac ?? x.ac) == x.ac &&
-            (crewFilter.lname ?? x.lname ?? "").capitalize() ==
-                (x.lname ?? "").capitalize() &&
-            (crewFilter.fname ?? x.fname ?? "").capitalize() ==
-                (x.fname ?? "").capitalize() &&
-            //search like
-            (crewFilter.searchname == null ||
-                (x.fname ?? "")
-                    .capitalize()
-                    .contains(crewFilter.searchname!.capitalize())) &&
-            (crewFilter.searchname == null ||
-                (x.lname ?? "")
-                    .capitalize()
-                    .contains(crewFilter.searchname!.capitalize())))))
-        .toList());
-
-final dataProvider = StateNotifierProvider<DataNotifier, DataState>((ref) {
-  return DataNotifier();
-});
-
-class DataState {
-  List<Qualif> qualif;
-
-  List<Pnleg> pnleg;
-
-  List<Acleg> acleg;
-
-  Jiffy? qualifupdate;
-  Jiffy? pnlegupdate;
-  Jiffy? aclegupdate;
-
-  List<Jiffy> get pnleg_dates => pnleg.fold(
-      <Jiffy>{},
-      (t, e) => {
-            ...t,
-            e.jdep?.startOf(Unit.day) ??
-                Jiffy.parse(e.date ?? "01/01/1970",
-                    pattern: "dd/MM/yyyy", isUtc: true)
-          }).sortedBy((e) => e.dateTime);
-
-  List<String> get pnleg_tlcs =>
-      pnleg.fold(<String>{}, (t, e) => {...t, e.tlc ?? ""}).sortedBy((e) {
-        final pn = qualif.firstWhereOrNull((q) => q.tlc == e);
-        return "${pn?.lname} ${pn?.fname}";
-      });
-
-  // PnlegMeta get pnleg_tlcs_dates {
-  //   Set<String> tlcs = {};
-  //   Set<Jiffy> dates = {};
-  //   for (Pnleg leg in pnleg) {
-  //     tlcs.add(leg.tlc ?? "");
-  //     dates.add(leg.jdep?.startOf(Unit.day) ??
-  //         Jiffy.parse(leg.date ?? "01/01/1970",
-  //             pattern: "dd/MM/yyyy", isUtc: true));
-  //   }
-  //   // final restlcs = tlcs.sortedBy((k) =>qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
-  //   final restlcs = tlcs.sortedBy((e) =>
-  //       "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
-  //   final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
-  //   return PnlegMeta(tlcs: restlcs, dates: resdates);
-  // }
-
-  DataState({
-    this.qualif = const [],
-    this.pnleg = const [],
-    this.acleg = const [],
-    this.qualifupdate,
-    this.pnlegupdate,
-    this.aclegupdate,
-  });
-
-  DataState copyWith({
-    List<Qualif>? qualif,
-    List<Pnleg>? pnleg,
-    List<Acleg>? acleg,
-    Jiffy? qualifupdate,
-    Jiffy? pnlegupdate,
-    Jiffy? aclegupdate,
-  }) {
-    return DataState(
-      qualif: qualif ?? this.qualif,
-      pnleg: pnleg ?? this.pnleg,
-      acleg: acleg ?? this.acleg,
-      qualifupdate: qualifupdate ?? this.qualifupdate,
-      pnlegupdate: pnlegupdate ?? this.pnlegupdate,
-      aclegupdate: aclegupdate ?? this.aclegupdate,
-    );
-  }
-
-  @override
-  String toString() {
-    return 'DataState(qualif: $qualif, pnleg: $pnleg, acleg: $acleg, qualifupdate: $qualifupdate, pnlegupdate: $pnlegupdate, aclegupdate: $aclegupdate)';
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-
-    return other is DataState &&
-        listEquals(other.qualif, qualif) &&
-        listEquals(other.pnleg, pnleg) &&
-        listEquals(other.acleg, acleg) &&
-        other.qualifupdate == qualifupdate &&
-        other.pnlegupdate == pnlegupdate &&
-        other.aclegupdate == aclegupdate;
-  }
-
-  @override
-  int get hashCode {
-    return qualif.hashCode ^
-        pnleg.hashCode ^
-        acleg.hashCode ^
-        qualifupdate.hashCode ^
-        pnlegupdate.hashCode ^
-        aclegupdate.hashCode;
-  }
-}
-
-class DataNotifier extends StateNotifier<DataState> {
-  Timer? _timer;
-
-  DataNotifier() : super(DataState()) {
-    final subscription = Supabase.instance.client
-        .from('publications')
-        .on(SupabaseEventTypes.all, (payload) {
-      print('Change received!');
-      print(payload);
-      setState(() {
-        // Update your UI or state based on the payload
-      });
-    }).subscribe();
-    Future.delayed(Duration.zero).then((x) async {
-      await loadAll();
-      // await downloadModifiedFiles();
-      _timer = Timer.periodic(const Duration(seconds: 15), (timer) async {
-        await downloadModifiedFiles();
-      });
-    });
-  }
-
-  @override
-  void dispose() {
-    if (_timer != null) _timer!.cancel();
-    super.dispose();
-  }
-
-  // void calculPnlegMeta() {
-  //   final now = Jiffy.now();
-  //   final data = state;
-  //   final pnlegs = data.pnleg;
-  //   final qualif = data.qualif;
-  //   Set<String> tlcs = {};
-  //   Set<Jiffy> dates = {};
-  //   for (Pnleg pnleg in pnlegs) {
-  //     tlcs.add(pnleg.tlc ?? "");
-  //     dates.add(pnleg.jdep?.startOf(Unit.day) ??
-  //         Jiffy.parse(pnleg.date ?? "01/01/1970",
-  //             pattern: "dd/MM/yyyy", isUtc: true));
-  //   }
-  //   // final restlcs = tlcs.sortedBy((k) =>qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
-  //   final restlcs = tlcs.sortedBy((e) =>
-  //       "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
-  //   final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
-  //   print(
-  //       "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
-  //   pnlegmeta = PnlegMeta(tlcs: restlcs, dates: resdates);
-  // }
-
-  Future<void> downloadModifiedFiles() async {
-    final supabaseClient = Supabase.instance.client;
-    //print("data: downloadmodifiedfiles");
-    // Get the local download directory
-    final String downloadPath = PathTo().subd("download").path;
-
-    // Create the download directory if it doesn't exist
-    final Directory directory = Directory(downloadPath);
-    if (!await directory.exists()) {
-      await directory.create(recursive: true);
-    }
-
-    try {
-      // List files in the "csv" bucket
-      final filelist = await supabaseClient.storage.from('csv').list();
-      // Iterate through the files and check for modifications
-      for (final file in filelist) {
-        final fileName = file.name;
-        final modifiedAt = file.updatedAt;
-
-        // Check if the file exists locally
-        final localFile = File(PathTo().downloadFile(fileName));
-        DateTime? localModifiedAt;
-
-        if (await localFile.exists()) {
-          localModifiedAt = await localFile.lastModified();
-        }
-
-        // Download the file if it has been modified
-        if (localModifiedAt == null ||
-            (modifiedAt != null &&
-                DateTime.parse(modifiedAt).isAfter(localModifiedAt))) {
-          final fileBytes =
-              await supabaseClient.storage.from('csv').download(fileName);
-          if (fileBytes.isNotEmpty) {
-            await localFile.writeAsBytes(fileBytes);
-            print('Downloaded modified file: $fileName');
-            await localFile.copy(PathTo().csvFile(fileName));
-            await loadAll();
-          } else {
-            print('Failed to download file: $fileName');
-          }
-        } else {
-          //print('File $fileName is up to date.');
-        }
-      }
-    } catch (e) {
-      print(
-          "data: downloadmodified files: unable to list files on supabase bucket");
-    }
-  }
-
-  loadAll() async {
-    if (qualiftime != qualifupdate) await loadQualif();
-    if (aclegtime != aclegupdate) await loadAclegs();
-    if (pnleg3time != pnleg3update) await loadPnlegs3();
-    if (pnlegmoistime != pnlegmoisupdate) await loadPnlegsmois();
-  }
-
-  Jiffy? qualifupdate;
-  String get qualiffile => PathTo().csvFile("exportlicence.txt");
-  Jiffy? get qualiftime => File(qualiffile).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("exportlicence.txt")).lastModifiedSync())
-      : null;
-  List<Qualif> qualif = [];
-  loadQualif() async {
-    print("data: qualif update ${qualiftime?.dateTime}");
-    final txt = await File(qualiffile).readAsString();
-    qualifupdate = qualiftime;
-
-    qualif =
-        await compute(csvqualiftolist, txt, debugLabel: "convert qualif csv");
-
-    state = state.copyWith(qualifupdate: qualifupdate, qualif: qualif);
-  }
-
-  static List<Qualif> csvqualiftolist(txt) {
-    return CsvData.csv2list(txt).map((e) => Qualif.fromList(e)).toList();
-  }
-
-  Jiffy? aclegupdate;
-  String get aclegfile => PathTo().csvFile("secondprgtype.zip");
-  Jiffy? get aclegtime => File(aclegfile).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("secondprgtype.zip")).lastModifiedSync())
-      : null;
-  List<Acleg> acleg = [];
-  loadAclegs() async {
-    print("data: acleg update ${aclegtime?.dateTime}");
-
-    final txt =
-        await CsvData.extractTextFileFromZip(aclegfile, "secondprgtype.txt");
-    aclegupdate = aclegtime;
-    acleg =
-        await compute(csvaclegtolist, txt, debugLabel: "convert aclegs csv");
-
-    state = state.copyWith(aclegupdate: aclegupdate, acleg: acleg);
-
-    //print(acleg);
-  }
-
-  static List<Acleg> csvaclegtolist(txt) {
-    return CsvData.csv2list(txt)
-        .map((e) => Acleg.fromList(e))
-        .where((leg) =>
-            //only flights of Tunisair
-            (leg.FN_CARRIER == "TU" ||
-                leg.EMPLOYER_CABIN == "TU" ||
-                leg.EMPLOYER_COCKPIT == "TU" ||
-                leg.AC_OWNER == "TU"))
-        .sortedBy((e) => e.jdep!.dateTime)
-        .toList();
-  }
-
-  List<Pnleg> pnleg = [];
-
-  static List<Pnleg> calculpnleg(Map data) {
-    print(data.keys);
-    final pnlegmoistime = data["pnlegmoistime"] as Jiffy?;
-    final pnleg3time = data["pnleg3time"] as Jiffy?;
-    final pnlegmois = data["pnlegmois"] as List<Pnleg>;
-    final pnleg3 = data["pnleg3"] as List<Pnleg>;
-    if (pnlegmoistime != null &&
-        pnleg3time != null &&
-        pnlegmoistime.isSameOrAfter(pnleg3time)) {
-      return pnlegmois;
-    } else if (pnlegmoistime != null &&
-        pnleg3time != null &&
-        pnlegmoistime.isBefore(pnleg3time)) {
-      final dates3tlc3 =
-          pnleg3.fold(<String>{}, (p, e) => {...p, "${e.date},${e.tlc}"});
-      return (pnlegmois
-          .where((x) => !(dates3tlc3.contains("${x.date},${x.tlc}")))
-          .toList())
-        ..addAll(pnleg3); //pnleg3 dabord
-    } else if (pnlegmoistime == null && pnleg3time != null) {
-      return pnleg3;
-    } else if (pnlegmoistime != null && pnleg3time == null) {
-      return pnlegmois;
-    } else {
-      return <Pnleg>[];
-    }
-  }
-
-  Jiffy? pnlegmoisupdate;
-  static String get pnlegmoisfile => PathTo().csvFile("ExportPGRGPNmois.zip");
-  Jiffy? get pnlegmoistime => File(pnlegmoisfile).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("ExportPGRGPNmois.zip")).lastModifiedSync())
-      : null;
-  List<Pnleg> pnlegmois = [];
-  loadPnlegsmois() async {
-    print("data: pnlegmois update ${pnlegmoistime?.dateTime}");
-
-    final txt = await CsvData.extractTextFileFromZip(
-        pnlegmoisfile, "ExportPGRGPNmois.txt");
-    // pnlegmois = CsvData.csv2list(txt).map((e) => Pnleg.fromList(e)).toList();
-    pnlegmoisupdate = pnlegmoistime;
-
-    pnlegmois =
-        await compute(csvpnlegtolist, txt, debugLabel: "convert pnlegmois csv");
-    pnleg = await compute(
-        calculpnleg,
-        {
-          "pnlegmois": pnlegmois,
-          "pnlegmoistime": pnlegmoistime,
-          "pnleg3": pnleg3,
-          "pnleg3time": pnleg3time,
-        },
-        debugLabel: "recalculate pnleg");
-    //calculPnlegMeta();
-    state = state.copyWith(pnlegupdate: pnlegmoisupdate, pnleg: pnleg);
-  }
-
-  static List<Pnleg> csvpnlegtolist(txt) {
-    return CsvData.csv2list(txt).map((e) => Pnleg.fromList(e)).toList();
-  }
-
-  Jiffy? pnleg3update;
-  String get pnleg3file => PathTo().csvFile("exportPGRGPN.zip");
-  Jiffy? get pnleg3time => File(pnleg3file).existsSync()
-      ? Jiffy.parseFromDateTime(
-          File(PathTo().csvFile("exportPGRGPN.zip")).lastModifiedSync())
-      : null;
-  List<Pnleg> pnleg3 = [];
-  loadPnlegs3() async {
-    print("data: pnleg3 update ${pnleg3time?.dateTime}");
-
-    final txt =
-        await CsvData.extractTextFileFromZip(pnleg3file, "exportPGRGPN.txt");
-    pnleg3 =
-        await compute(csvpnlegtolist, txt, debugLabel: "convert pnleg3 csv");
-    pnleg3update = pnleg3time;
-    pnleg = await compute(
-        calculpnleg,
-        {
-          "pnlegmois": pnlegmois,
-          "pnlegmoistime": pnlegmoistime,
-          "pnleg3": pnleg3,
-          "pnleg3time": pnleg3time,
-        },
-        debugLabel: "recalculating pnleg");
-
-    state = state.copyWith(pnlegupdate: pnleg3update, pnleg: pnleg);
-
-    //print(pnleg3);
-  }
-}
-
-class Qualif {
-  String? tlc;
-  String? lname;
-  String? mname;
-  String? fname;
-  String? date;
-  String? ac;
-  String? college;
-  String? base;
-  Qualif({
-    this.tlc,
-    this.lname,
-    this.mname,
-    this.fname,
-    this.date,
-    this.ac,
-    this.college,
-    this.base,
-  });
-
-  Qualif copyWith({
-    String? tlc,
-    String? lname,
-    String? mname,
-    String? fname,
-    String? date,
-    String? ac,
-    String? college,
-    String? base,
-  }) {
-    return Qualif(
-      tlc: tlc ?? this.tlc,
-      lname: lname ?? this.lname,
-      mname: mname ?? this.mname,
-      fname: fname ?? this.fname,
-      date: date ?? this.date,
-      ac: ac ?? this.ac,
-      college: college ?? this.college,
-      base: base ?? this.base,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return <String, dynamic>{
-      'tlc': tlc,
-      'lname': lname,
-      'mname': mname,
-      'fname': fname,
-      'date': date,
-      'ac': ac,
-      'college': college,
-      'base': base,
-    };
-  }
-
-  factory Qualif.fromList(List datalist) {
-    return Qualif(
-        tlc: datalist[0],
-        lname: datalist[1],
-        mname: datalist[2],
-        fname: datalist[3],
-        date: datalist[4],
-        ac: datalist[5],
-        college: datalist[6],
-        base: datalist[7]);
-  }
-
-  factory Qualif.fromMap(Map<String, dynamic> map) {
-    return Qualif(
-      tlc: map['tlc'] != null ? map['tlc'] as String : null,
-      lname: map['lname'] != null ? map['lname'] as String : null,
-      mname: map['mname'] != null ? map['mname'] as String : null,
-      fname: map['fname'] != null ? map['fname'] as String : null,
-      date: map['date'] != null ? map['date'] as String : null,
-      ac: map['ac'] != null ? map['ac'] as String : null,
-      college: map['college'] != null ? map['college'] as String : null,
-      base: map['base'] != null ? map['base'] as String : null,
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory Qualif.fromJson(String source) =>
-      Qualif.fromMap(json.decode(source) as Map<String, dynamic>);
-
-  @override
-  String toString() {
-    return 'Qualif(tlc: $tlc, lname: $lname, mname: $mname, fname: $fname, date: $date, ac: $ac, college: $college, base: $base)';
-  }
-
-  @override
-  bool operator ==(covariant Qualif other) {
-    if (identical(this, other)) return true;
-
-    return other.tlc == tlc &&
-        other.lname == lname &&
-        other.mname == mname &&
-        other.fname == fname &&
-        other.date == date &&
-        other.ac == ac &&
-        other.college == college &&
-        other.base == base;
-  }
-
-  @override
-  int get hashCode {
-    return tlc.hashCode ^
-        lname.hashCode ^
-        mname.hashCode ^
-        fname.hashCode ^
-        date.hashCode ^
-        ac.hashCode ^
-        college.hashCode ^
-        base.hashCode;
-  }
-}
-
-class Pnleg {
-  String? date;
-  Jiffy? get jdate => date != null
-      ? Jiffy.parse(date ?? "01/01/1970", pattern: "dd/MM/yyyy", isUtc: true)
-      : null;
-
-  String? tlc;
-  String? actype;
-  String? al;
-  String? fnum;
-  String? depdate;
-  String? deptime;
-  String? arrdate;
-  String? arrtime;
-  String? dep;
-  String? arr;
-  String? label;
-  String? type;
-  Jiffy? get jdep =>
-      deptime != null ? "$depdate $deptime".parseddmmyyyyhhmm() : null;
-  Jiffy? get jarr =>
-      arrtime != null ? "$arrdate $arrtime".parseddmmyyyyhhmm() : null;
-
-  String get dutytype {
-    if (type == "L") {
-      return "flight";
-    } else if ((type == "G")) {
-      return "dhlimo";
-    } else if ((type == "F") || ((dep ?? "") != "" && (arr ?? "") != "")) {
-      return "dhflight";
-    } else if ((label?.startsWith("SBY") ?? false) || (label == "R0")) {
-      return "standby";
-    } else if ((!["OFF", "CM", "CA", "PP"].contains(label)) &&
-        (jarr != null &&
-            jdep != null &&
-            DTInterval(jdep!, jarr!).duration.inHours < 18)) {
-      return "ground";
-    } else {
-      return "day";
-    }
-  }
-
-  Pnleg({
-    this.date,
-    this.tlc,
-    this.actype,
-    this.al,
-    this.fnum,
-    this.depdate,
-    this.deptime,
-    this.arrdate,
-    this.arrtime,
-    this.dep,
-    this.arr,
-    this.label,
-    this.type,
-  });
-
-  Pnleg copyWith({
-    String? date,
-    String? tlc,
-    String? actype,
-    String? al,
-    String? fnum,
-    String? depdate,
-    String? deptime,
-    String? arrdate,
-    String? arrtime,
-    String? dep,
-    String? arr,
-    String? label,
-    String? type,
-  }) {
-    return Pnleg(
-      date: date ?? this.date,
-      tlc: tlc ?? this.tlc,
-      actype: actype ?? this.actype,
-      al: al ?? this.al,
-      fnum: fnum ?? this.fnum,
-      depdate: depdate ?? this.depdate,
-      deptime: deptime ?? this.deptime,
-      arrdate: arrdate ?? this.arrdate,
-      arrtime: arrtime ?? this.arrtime,
-      dep: dep ?? this.dep,
-      arr: arr ?? this.arr,
-      label: label ?? this.label,
-      type: type ?? this.type,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return <String, dynamic>{
-      'date': date,
-      'tlc': tlc,
-      'actype': actype,
-      'al': al,
-      'fnum': fnum,
-      'depdate': depdate,
-      'deptime': deptime,
-      'arrdate': arrdate,
-      'arrtime': arrtime,
-      'dep': dep,
-      'arr': arr,
-      'label': label,
-      'type': type,
-    };
-  }
-
-  factory Pnleg.fromList(List datalist) {
-    return Pnleg(
-        date: datalist[0],
-        tlc: datalist[1],
-        actype: datalist[2],
-        al: datalist[3],
-        fnum: datalist[4],
-        depdate: datalist[5],
-        deptime: datalist[6],
-        arrdate: datalist[7],
-        arrtime: datalist[8],
-        dep: datalist[9],
-        arr: datalist[10],
-        label: datalist[11],
-        type: datalist[12]);
-  }
-
-  factory Pnleg.fromMap(Map<String, dynamic> map) {
-    return Pnleg(
-      date: map['date'] != null ? map['date'] as String : null,
-      tlc: map['tlc'] != null ? map['tlc'] as String : null,
-      actype: map['actype'] != null ? map['actype'] as String : null,
-      al: map['al'] != null ? map['al'] as String : null,
-      fnum: map['fnum'] != null ? map['fnum'] as String : null,
-      depdate: map['depdate'] != null ? map['depdate'] as String : null,
-      deptime: map['deptime'] != null ? map['deptime'] as String : null,
-      arrdate: map['arrdate'] != null ? map['arrdate'] as String : null,
-      arrtime: map['arrtime'] != null ? map['arrtime'] as String : null,
-      dep: map['dep'] != null ? map['dep'] as String : null,
-      arr: map['arr'] != null ? map['arr'] as String : null,
-      label: map['label'] != null ? map['label'] as String : null,
-      type: map['type'] != null ? map['type'] as String : null,
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory Pnleg.fromJson(String source) =>
-      Pnleg.fromMap(json.decode(source) as Map<String, dynamic>);
-
-  @override
-  String toString() {
-    return 'Pnleg(date: $date, tlc: $tlc, actype: $actype, al: $al, fnum: $fnum, depdate: $depdate, deptime: $deptime, arrdate: $arrdate, arrtime: $arrtime, dep: $dep, arr: $arr, label: $label, type: $type)';
-  }
-
-  @override
-  bool operator ==(covariant Pnleg other) {
-    if (identical(this, other)) return true;
-
-    return other.date == date &&
-        other.tlc == tlc &&
-        other.actype == actype &&
-        other.al == al &&
-        other.fnum == fnum &&
-        other.depdate == depdate &&
-        other.deptime == deptime &&
-        other.arrdate == arrdate &&
-        other.arrtime == arrtime &&
-        other.dep == dep &&
-        other.arr == arr &&
-        other.label == label &&
-        other.type == type;
-  }
-
-  @override
-  int get hashCode {
-    return date.hashCode ^
-        tlc.hashCode ^
-        actype.hashCode ^
-        al.hashCode ^
-        fnum.hashCode ^
-        depdate.hashCode ^
-        deptime.hashCode ^
-        arrdate.hashCode ^
-        arrtime.hashCode ^
-        dep.hashCode ^
-        arr.hashCode ^
-        label.hashCode ^
-        type.hashCode;
-  }
-}
-
-//enum flt_status { sched, delayed, taxiout, enroute, landed, arrived }
-
-class Acleg {
-  String? LEG_NO;
-  String? FN_CARRIER;
-  String? FN_NUMBER;
-  String? FN_SUFFIX;
-  String? DAY_OF_ORIGIN;
-  String? AC_OWNER;
-  String? AC_SUBTYPE;
-  String? AC_VERSION;
-  String? AC_REGISTRATION;
-  String? DEP_AP_ACTUAL;
-  String? DEP_AP_SCHED;
-  String? DEP_DT_EST;
-  Jiffy? get jdepest =>
-      (DEP_DT_EST == null) ? null : DEP_DT_EST!.parseyyyymmddhhmm();
-  String? DEP_SCHED_DT;
-  Jiffy? get jdepsched =>
-      (DEP_SCHED_DT == null) ? null : DEP_SCHED_DT!.parseyyyymmddhhmm();
-  String? ARR_AP_ACTUAL;
-  String? ARR_AP_SCHED;
-  String? ARR_DT_EST;
-  Jiffy? get jarrest =>
-      (ARR_DT_EST == null) ? null : ARR_DT_EST!.parseyyyymmddhhmm();
-  String? ARR_SCHED_DT;
-  Jiffy? get jarrsched =>
-      (ARR_SCHED_DT == null) ? null : ARR_SCHED_DT!.parseyyyymmddhhmm();
-  String? SLOT_TIME_ACTUAL;
-  Jiffy? get slot =>
-      (SLOT_TIME_ACTUAL == null) ? null : SLOT_TIME_ACTUAL!.parseyyyymmddhhmm();
-  String? LEG_TYPE;
-  String? STATUS;
-  String? EMPLOYER_COCKPIT;
-  String? EMPLOYER_CABIN;
-  String? CYCLES;
-  String? DELAY_CODE_01;
-  String? DELAY_CODE_02;
-  String? DELAY_CODE_03;
-  String? DELAY_CODE_04;
-  String? DELAY_TIME_01;
-  String? DELAY_TIME_02;
-  String? DELAY_TIME_03;
-  String? DELAY_TIME_04;
-  String? SUBDELAY_CODE_01;
-  String? SUBDELAY_CODE_02;
-  String? SUBDELAY_CODE_03;
-  String? SUBDELAY_CODE_04;
-  List<List> get dla => [
-        [
-          SUBDELAY_CODE_01 ?? DELAY_CODE_01,
-          DELAY_TIME_01 == null
-              ? null
-              : Duration(minutes: int.parse(DELAY_TIME_01!))
-        ],
-        [
-          SUBDELAY_CODE_02 ?? DELAY_CODE_02,
-          DELAY_TIME_02 == null
-              ? null
-              : Duration(minutes: int.parse(DELAY_TIME_02!))
-        ],
-        [
-          SUBDELAY_CODE_03 ?? DELAY_CODE_03,
-          DELAY_TIME_03 == null
-              ? null
-              : Duration(minutes: int.parse(DELAY_TIME_03!))
-        ],
-        [
-          SUBDELAY_CODE_04 ?? DELAY_CODE_04,
-          DELAY_TIME_04 == null
-              ? null
-              : Duration(minutes: int.parse(DELAY_TIME_04!))
-        ],
-      ].where((e) => e.every((f) => f != null)).toList();
-  List<String> get delaycode => [
-        DELAY_CODE_01,
-        DELAY_CODE_02,
-        DELAY_CODE_03,
-        DELAY_CODE_04
-      ].nonNulls.toList();
-  List<String> get delaysubcode => [
-        SUBDELAY_CODE_01,
-        SUBDELAY_CODE_02,
-        SUBDELAY_CODE_03,
-        SUBDELAY_CODE_04
-      ].nonNulls.toList();
-  List<Duration?> get delaytime => [
-        DELAY_TIME_01 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_01!)),
-        DELAY_TIME_02 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_02!)),
-        DELAY_TIME_03 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_03!)),
-        DELAY_TIME_04 == null
-            ? null
-            : Duration(minutes: int.parse(DELAY_TIME_04!))
-      ].nonNulls.toList();
-
-  String? PAX_BOOKED_C;
-  String? PAX_BOOKED_Y;
-  String? get pax_booked => (PAX_BOOKED_C != null || PAX_BOOKED_Y != null)
-      ? "${(AC_VERSION != null && AC_VERSION!.contains("C")) ? "C${PAX_BOOKED_C ?? 0}." : ""}Y${PAX_BOOKED_Y ?? 0}"
-      : null;
-  String? PAX_BOOKED_TRS_C;
-  String? PAX_BOOKED_TRS_Y;
-  String? get pax_trs => (PAX_BOOKED_TRS_C != null || PAX_BOOKED_TRS_Y != null)
-      ? "C${PAX_BOOKED_TRS_C ?? 0}/Y${PAX_BOOKED_TRS_Y ?? 0}"
-      : null;
-  String? PAD_BOOKED_C;
-  String? PAD_BOOKED_Y;
-  String? get pad_booked => (PAD_BOOKED_C != null || PAD_BOOKED_Y != null)
-      ? "C${PAD_BOOKED_C ?? 0}/Y${PAD_BOOKED_Y ?? 0}"
-      : null;
-  String? OFFBLOCK_DT_A;
-  String? AIRBORNE_DT_A;
-  String? LANDING_DT_A;
-  String? ONBLOCK_DT_A;
-  List<Jiffy?> get blocks_a => [
-        (OFFBLOCK_DT_A ?? "").parseyyyymmddhhmm(),
-        (AIRBORNE_DT_A ?? "").parseyyyymmddhhmm(),
-        (LANDING_DT_A ?? "").parseyyyymmddhhmm(),
-        (ONBLOCK_DT_A ?? "").parseyyyymmddhhmm()
-      ];
-  String get flt_status {
-    if (blocks[3] != null) {
-      return "Arrived";
-    } else if (blocks[2] != null) {
-      return "Landed";
-    } else if (blocks[1] != null) {
-      return "Inflight";
-    } else if (blocks[0] != null) {
-      return "Taxiout";
-    } else if (jdepest != null &&
-        jarrsched != null &&
-        jdepest!.isAfter(jdepsched!)) {
-      return "Delayed";
-    } else {
-      return "Sched";
-    }
-  }
-
-  String? OFFBLOCK_DT_F;
-  String? AIRBORNE_DT_F;
-  String? LANDING_DT_F;
-  String? ONBLOCK_DT_F;
-  List<Jiffy?> get blocks_f => [
-        (OFFBLOCK_DT_F ?? "").parseyyyymmddhhmm(),
-        (AIRBORNE_DT_F ?? "").parseyyyymmddhhmm(),
-        (LANDING_DT_F ?? "").parseyyyymmddhhmm(),
-        (ONBLOCK_DT_F ?? "").parseyyyymmddhhmm()
-      ];
-
-  String? OFFBLOCK_DT_M;
-  String? AIRBORNE_DT_M;
-  String? LANDING_DT_M;
-  String? ONBLOCK_DT_M;
-  List<Jiffy?> get blocks_m => [
-        (OFFBLOCK_DT_M ?? "").parseyyyymmddhhmm(),
-        (AIRBORNE_DT_M ?? "").parseyyyymmddhhmm(),
-        (LANDING_DT_M ?? "").parseyyyymmddhhmm(),
-        (ONBLOCK_DT_M ?? "").parseyyyymmddhhmm()
-      ];
-  List<Jiffy?> get blocks => [
-        blocks_m[0] ?? blocks_a[0] ?? blocks_f[0],
-        blocks_m[1] ?? blocks_a[1] ?? blocks_f[1],
-        blocks_m[2] ?? blocks_a[2] ?? blocks_f[2],
-        blocks_m[3] ?? blocks_a[3] ?? blocks_f[3]
-      ];
-  Jiffy? get jdep => blocks[0] ?? jdepest ?? jdepsched;
-  Jiffy? get jarr =>
-      blocks[3] ??
-      blocks[2]?.add(minutes: 5) ??
-      (eet == null ? null : blocks[1]?.addDuration(eet!).add(minutes: 8)) ??
-      (eet == null
-          ? null
-          : blocks[0]?.add(minutes: 5).addDuration(eet!).add(minutes: 8)) ??
-      (eet == null
-          ? null
-          : jdep?.addDuration(eet!).add(minutes: 8).add(minutes: 5)) ??
-      jarrest ??
-      jarrsched;
-  String? EET;
-  Duration? get eet => EET == null ? null : Duration(minutes: int.parse(EET!));
-  Acleg({
-    this.LEG_NO,
-    this.FN_CARRIER,
-    this.FN_NUMBER,
-    this.FN_SUFFIX,
-    this.DAY_OF_ORIGIN,
-    this.AC_OWNER,
-    this.AC_SUBTYPE,
-    this.AC_VERSION,
-    this.AC_REGISTRATION,
-    this.DEP_AP_ACTUAL,
-    this.DEP_AP_SCHED,
-    this.DEP_DT_EST,
-    this.DEP_SCHED_DT,
-    this.ARR_AP_ACTUAL,
-    this.ARR_AP_SCHED,
-    this.ARR_DT_EST,
-    this.ARR_SCHED_DT,
-    this.SLOT_TIME_ACTUAL,
-    this.LEG_TYPE,
-    this.STATUS,
-    this.EMPLOYER_COCKPIT,
-    this.EMPLOYER_CABIN,
-    this.CYCLES,
-    this.DELAY_CODE_01,
-    this.DELAY_CODE_02,
-    this.DELAY_CODE_03,
-    this.DELAY_CODE_04,
-    this.DELAY_TIME_01,
-    this.DELAY_TIME_02,
-    this.DELAY_TIME_03,
-    this.DELAY_TIME_04,
-    this.SUBDELAY_CODE_01,
-    this.SUBDELAY_CODE_02,
-    this.SUBDELAY_CODE_03,
-    this.SUBDELAY_CODE_04,
-    this.PAX_BOOKED_C,
-    this.PAX_BOOKED_Y,
-    this.PAX_BOOKED_TRS_C,
-    this.PAX_BOOKED_TRS_Y,
-    this.PAD_BOOKED_C,
-    this.PAD_BOOKED_Y,
-    this.OFFBLOCK_DT_A,
-    this.AIRBORNE_DT_A,
-    this.LANDING_DT_A,
-    this.ONBLOCK_DT_A,
-    this.OFFBLOCK_DT_F,
-    this.AIRBORNE_DT_F,
-    this.LANDING_DT_F,
-    this.ONBLOCK_DT_F,
-    this.OFFBLOCK_DT_M,
-    this.AIRBORNE_DT_M,
-    this.LANDING_DT_M,
-    this.ONBLOCK_DT_M,
-    this.EET,
-  });
-
-  Acleg copyWith({
-    String? LEG_NO,
-    String? FN_CARRIER,
-    String? FN_NUMBER,
-    String? FN_SUFFIX,
-    String? DAY_OF_ORIGIN,
-    String? AC_OWNER,
-    String? AC_SUBTYPE,
-    String? AC_VERSION,
-    String? AC_REGISTRATION,
-    String? DEP_AP_ACTUAL,
-    String? DEP_AP_SCHED,
-    String? DEP_DT_EST,
-    String? DEP_SCHED_DT,
-    String? ARR_AP_ACTUAL,
-    String? ARR_AP_SCHED,
-    String? ARR_DT_EST,
-    String? ARR_SCHED_DT,
-    String? SLOT_TIME_ACTUAL,
-    String? LEG_TYPE,
-    String? STATUS,
-    String? EMPLOYER_COCKPIT,
-    String? EMPLOYER_CABIN,
-    String? CYCLES,
-    String? DELAY_CODE_01,
-    String? DELAY_CODE_02,
-    String? DELAY_CODE_03,
-    String? DELAY_CODE_04,
-    String? DELAY_TIME_01,
-    String? DELAY_TIME_02,
-    String? DELAY_TIME_03,
-    String? DELAY_TIME_04,
-    String? SUBDELAY_CODE_01,
-    String? SUBDELAY_CODE_02,
-    String? SUBDELAY_CODE_03,
-    String? SUBDELAY_CODE_04,
-    String? PAX_BOOKED_C,
-    String? PAX_BOOKED_Y,
-    String? PAX_BOOKED_TRS_C,
-    String? PAX_BOOKED_TRS_Y,
-    String? PAD_BOOKED_C,
-    String? PAD_BOOKED_Y,
-    String? OFFBLOCK_DT_A,
-    String? AIRBORNE_DT_A,
-    String? LANDING_DT_A,
-    String? ONBLOCK_DT_A,
-    String? OFFBLOCK_DT_F,
-    String? AIRBORNE_DT_F,
-    String? LANDING_DT_F,
-    String? ONBLOCK_DT_F,
-    String? OFFBLOCK_DT_M,
-    String? AIRBORNE_DT_M,
-    String? LANDING_DT_M,
-    String? ONBLOCK_DT_M,
-    String? EET,
-  }) {
-    return Acleg(
-      LEG_NO: LEG_NO ?? this.LEG_NO,
-      FN_CARRIER: FN_CARRIER ?? this.FN_CARRIER,
-      FN_NUMBER: FN_NUMBER ?? this.FN_NUMBER,
-      FN_SUFFIX: FN_SUFFIX ?? this.FN_SUFFIX,
-      DAY_OF_ORIGIN: DAY_OF_ORIGIN ?? this.DAY_OF_ORIGIN,
-      AC_OWNER: AC_OWNER ?? this.AC_OWNER,
-      AC_SUBTYPE: AC_SUBTYPE ?? this.AC_SUBTYPE,
-      AC_VERSION: AC_VERSION ?? this.AC_VERSION,
-      AC_REGISTRATION: AC_REGISTRATION ?? this.AC_REGISTRATION,
-      DEP_AP_ACTUAL: DEP_AP_ACTUAL ?? this.DEP_AP_ACTUAL,
-      DEP_AP_SCHED: DEP_AP_SCHED ?? this.DEP_AP_SCHED,
-      DEP_DT_EST: DEP_DT_EST ?? this.DEP_DT_EST,
-      DEP_SCHED_DT: DEP_SCHED_DT ?? this.DEP_SCHED_DT,
-      ARR_AP_ACTUAL: ARR_AP_ACTUAL ?? this.ARR_AP_ACTUAL,
-      ARR_AP_SCHED: ARR_AP_SCHED ?? this.ARR_AP_SCHED,
-      ARR_DT_EST: ARR_DT_EST ?? this.ARR_DT_EST,
-      ARR_SCHED_DT: ARR_SCHED_DT ?? this.ARR_SCHED_DT,
-      SLOT_TIME_ACTUAL: SLOT_TIME_ACTUAL ?? this.SLOT_TIME_ACTUAL,
-      LEG_TYPE: LEG_TYPE ?? this.LEG_TYPE,
-      STATUS: STATUS ?? this.STATUS,
-      EMPLOYER_COCKPIT: EMPLOYER_COCKPIT ?? this.EMPLOYER_COCKPIT,
-      EMPLOYER_CABIN: EMPLOYER_CABIN ?? this.EMPLOYER_CABIN,
-      CYCLES: CYCLES ?? this.CYCLES,
-      DELAY_CODE_01: DELAY_CODE_01 ?? this.DELAY_CODE_01,
-      DELAY_CODE_02: DELAY_CODE_02 ?? this.DELAY_CODE_02,
-      DELAY_CODE_03: DELAY_CODE_03 ?? this.DELAY_CODE_03,
-      DELAY_CODE_04: DELAY_CODE_04 ?? this.DELAY_CODE_04,
-      DELAY_TIME_01: DELAY_TIME_01 ?? this.DELAY_TIME_01,
-      DELAY_TIME_02: DELAY_TIME_02 ?? this.DELAY_TIME_02,
-      DELAY_TIME_03: DELAY_TIME_03 ?? this.DELAY_TIME_03,
-      DELAY_TIME_04: DELAY_TIME_04 ?? this.DELAY_TIME_04,
-      SUBDELAY_CODE_01: SUBDELAY_CODE_01 ?? this.SUBDELAY_CODE_01,
-      SUBDELAY_CODE_02: SUBDELAY_CODE_02 ?? this.SUBDELAY_CODE_02,
-      SUBDELAY_CODE_03: SUBDELAY_CODE_03 ?? this.SUBDELAY_CODE_03,
-      SUBDELAY_CODE_04: SUBDELAY_CODE_04 ?? this.SUBDELAY_CODE_04,
-      PAX_BOOKED_C: PAX_BOOKED_C ?? this.PAX_BOOKED_C,
-      PAX_BOOKED_Y: PAX_BOOKED_Y ?? this.PAX_BOOKED_Y,
-      PAX_BOOKED_TRS_C: PAX_BOOKED_TRS_C ?? this.PAX_BOOKED_TRS_C,
-      PAX_BOOKED_TRS_Y: PAX_BOOKED_TRS_Y ?? this.PAX_BOOKED_TRS_Y,
-      PAD_BOOKED_C: PAD_BOOKED_C ?? this.PAD_BOOKED_C,
-      PAD_BOOKED_Y: PAD_BOOKED_Y ?? this.PAD_BOOKED_Y,
-      OFFBLOCK_DT_A: OFFBLOCK_DT_A ?? this.OFFBLOCK_DT_A,
-      AIRBORNE_DT_A: AIRBORNE_DT_A ?? this.AIRBORNE_DT_A,
-      LANDING_DT_A: LANDING_DT_A ?? this.LANDING_DT_A,
-      ONBLOCK_DT_A: ONBLOCK_DT_A ?? this.ONBLOCK_DT_A,
-      OFFBLOCK_DT_F: OFFBLOCK_DT_F ?? this.OFFBLOCK_DT_F,
-      AIRBORNE_DT_F: AIRBORNE_DT_F ?? this.AIRBORNE_DT_F,
-      LANDING_DT_F: LANDING_DT_F ?? this.LANDING_DT_F,
-      ONBLOCK_DT_F: ONBLOCK_DT_F ?? this.ONBLOCK_DT_F,
-      OFFBLOCK_DT_M: OFFBLOCK_DT_M ?? this.OFFBLOCK_DT_M,
-      AIRBORNE_DT_M: AIRBORNE_DT_M ?? this.AIRBORNE_DT_M,
-      LANDING_DT_M: LANDING_DT_M ?? this.LANDING_DT_M,
-      ONBLOCK_DT_M: ONBLOCK_DT_M ?? this.ONBLOCK_DT_M,
-      EET: EET ?? this.EET,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return <String, dynamic>{
-      'LEG_NO': LEG_NO,
-      'FN_CARRIER': FN_CARRIER,
-      'FN_NUMBER': FN_NUMBER,
-      'FN_SUFFIX': FN_SUFFIX,
-      'DAY_OF_ORIGIN': DAY_OF_ORIGIN,
-      'AC_OWNER': AC_OWNER,
-      'AC_SUBTYPE': AC_SUBTYPE,
-      'AC_VERSION': AC_VERSION,
-      'AC_REGISTRATION': AC_REGISTRATION,
-      'DEP_AP_ACTUAL': DEP_AP_ACTUAL,
-      'DEP_AP_SCHED': DEP_AP_SCHED,
-      'DEP_DT_EST': DEP_DT_EST,
-      'DEP_SCHED_DT': DEP_SCHED_DT,
-      'ARR_AP_ACTUAL': ARR_AP_ACTUAL,
-      'ARR_AP_SCHED': ARR_AP_SCHED,
-      'ARR_DT_EST': ARR_DT_EST,
-      'ARR_SCHED_DT': ARR_SCHED_DT,
-      'SLOT_TIME_ACTUAL': SLOT_TIME_ACTUAL,
-      'LEG_TYPE': LEG_TYPE,
-      'STATUS': STATUS,
-      'EMPLOYER_COCKPIT': EMPLOYER_COCKPIT,
-      'EMPLOYER_CABIN': EMPLOYER_CABIN,
-      'CYCLES': CYCLES,
-      'DELAY_CODE_01': DELAY_CODE_01,
-      'DELAY_CODE_02': DELAY_CODE_02,
-      'DELAY_CODE_03': DELAY_CODE_03,
-      'DELAY_CODE_04': DELAY_CODE_04,
-      'DELAY_TIME_01': DELAY_TIME_01,
-      'DELAY_TIME_02': DELAY_TIME_02,
-      'DELAY_TIME_03': DELAY_TIME_03,
-      'DELAY_TIME_04': DELAY_TIME_04,
-      'SUBDELAY_CODE_01': SUBDELAY_CODE_01,
-      'SUBDELAY_CODE_02': SUBDELAY_CODE_02,
-      'SUBDELAY_CODE_03': SUBDELAY_CODE_03,
-      'SUBDELAY_CODE_04': SUBDELAY_CODE_04,
-      'PAX_BOOKED_C': PAX_BOOKED_C,
-      'PAX_BOOKED_Y': PAX_BOOKED_Y,
-      'PAX_BOOKED_TRS_C': PAX_BOOKED_TRS_C,
-      'PAX_BOOKED_TRS_Y': PAX_BOOKED_TRS_Y,
-      'PAD_BOOKED_C': PAD_BOOKED_C,
-      'PAD_BOOKED_Y': PAD_BOOKED_Y,
-      'OFFBLOCK_DT_A': OFFBLOCK_DT_A,
-      'AIRBORNE_DT_A': AIRBORNE_DT_A,
-      'LANDING_DT_A': LANDING_DT_A,
-      'ONBLOCK_DT_A': ONBLOCK_DT_A,
-      'OFFBLOCK_DT_F': OFFBLOCK_DT_F,
-      'AIRBORNE_DT_F': AIRBORNE_DT_F,
-      'LANDING_DT_F': LANDING_DT_F,
-      'ONBLOCK_DT_F': ONBLOCK_DT_F,
-      'OFFBLOCK_DT_M': OFFBLOCK_DT_M,
-      'AIRBORNE_DT_M': AIRBORNE_DT_M,
-      'LANDING_DT_M': LANDING_DT_M,
-      'ONBLOCK_DT_M': ONBLOCK_DT_M,
-      'EET': EET,
-    };
-  }
-
-  factory Acleg.fromList(List datalist) {
-    //print(datalist);
-    if (datalist.length >= 54) {
-      return Acleg(
-          LEG_NO: datalist[0],
-          FN_CARRIER: datalist[1],
-          FN_NUMBER: datalist[2],
-          FN_SUFFIX: datalist[3],
-          DAY_OF_ORIGIN: datalist[4],
-          AC_OWNER: datalist[5],
-          AC_SUBTYPE: datalist[6],
-          AC_VERSION: datalist[7],
-          AC_REGISTRATION: datalist[8],
-          DEP_AP_ACTUAL: datalist[9],
-          DEP_AP_SCHED: datalist[10],
-          DEP_DT_EST: datalist[11],
-          DEP_SCHED_DT: datalist[12],
-          ARR_AP_ACTUAL: datalist[13],
-          ARR_AP_SCHED: datalist[14],
-          ARR_DT_EST: datalist[15],
-          ARR_SCHED_DT: datalist[16],
-          SLOT_TIME_ACTUAL: datalist[17],
-          LEG_TYPE: datalist[18],
-          STATUS: datalist[19],
-          EMPLOYER_COCKPIT: datalist[20],
-          EMPLOYER_CABIN: datalist[21],
-          CYCLES: datalist[22],
-          DELAY_CODE_01: datalist[23],
-          DELAY_CODE_02: datalist[24],
-          DELAY_CODE_03: datalist[25],
-          DELAY_CODE_04: datalist[26],
-          DELAY_TIME_01: datalist[27],
-          DELAY_TIME_02: datalist[28],
-          DELAY_TIME_03: datalist[29],
-          DELAY_TIME_04: datalist[30],
-          SUBDELAY_CODE_01: datalist[31],
-          SUBDELAY_CODE_02: datalist[32],
-          SUBDELAY_CODE_03: datalist[33],
-          SUBDELAY_CODE_04: datalist[34],
-          PAX_BOOKED_C: datalist[35],
-          PAX_BOOKED_Y: datalist[36],
-          PAX_BOOKED_TRS_C: datalist[37],
-          PAX_BOOKED_TRS_Y: datalist[38],
-          PAD_BOOKED_C: datalist[39],
-          PAD_BOOKED_Y: datalist[40],
-          OFFBLOCK_DT_A: datalist[41],
-          AIRBORNE_DT_A: datalist[42],
-          LANDING_DT_A: datalist[43],
-          ONBLOCK_DT_A: datalist[44],
-          OFFBLOCK_DT_F: datalist[45],
-          AIRBORNE_DT_F: datalist[46],
-          LANDING_DT_F: datalist[47],
-          ONBLOCK_DT_F: datalist[48],
-          OFFBLOCK_DT_M: datalist[49],
-          AIRBORNE_DT_M: datalist[50],
-          LANDING_DT_M: datalist[51],
-          ONBLOCK_DT_M: datalist[52],
-          EET: datalist[53]);
-    } else {
-      return Acleg();
-    }
-  }
-
-  factory Acleg.fromMap(Map<String, dynamic> map) {
-    return Acleg(
-      LEG_NO: map['LEG_NO'] != null ? map['LEG_NO'] as String : null,
-      FN_CARRIER:
-          map['FN_CARRIER'] != null ? map['FN_CARRIER'] as String : null,
-      FN_NUMBER: map['FN_NUMBER'] != null ? map['FN_NUMBER'] as String : null,
-      FN_SUFFIX: map['FN_SUFFIX'] != null ? map['FN_SUFFIX'] as String : null,
-      DAY_OF_ORIGIN:
-          map['DAY_OF_ORIGIN'] != null ? map['DAY_OF_ORIGIN'] as String : null,
-      AC_OWNER: map['AC_OWNER'] != null ? map['AC_OWNER'] as String : null,
-      AC_SUBTYPE:
-          map['AC_SUBTYPE'] != null ? map['AC_SUBTYPE'] as String : null,
-      AC_VERSION:
-          map['AC_VERSION'] != null ? map['AC_VERSION'] as String : null,
-      AC_REGISTRATION: map['AC_REGISTRATION'] != null
-          ? map['AC_REGISTRATION'] as String
-          : null,
-      DEP_AP_ACTUAL:
-          map['DEP_AP_ACTUAL'] != null ? map['DEP_AP_ACTUAL'] as String : null,
-      DEP_AP_SCHED:
-          map['DEP_AP_SCHED'] != null ? map['DEP_AP_SCHED'] as String : null,
-      DEP_DT_EST:
-          map['DEP_DT_EST'] != null ? map['DEP_DT_EST'] as String : null,
-      DEP_SCHED_DT:
-          map['DEP_SCHED_DT'] != null ? map['DEP_SCHED_DT'] as String : null,
-      ARR_AP_ACTUAL:
-          map['ARR_AP_ACTUAL'] != null ? map['ARR_AP_ACTUAL'] as String : null,
-      ARR_AP_SCHED:
-          map['ARR_AP_SCHED'] != null ? map['ARR_AP_SCHED'] as String : null,
-      ARR_DT_EST:
-          map['ARR_DT_EST'] != null ? map['ARR_DT_EST'] as String : null,
-      ARR_SCHED_DT:
-          map['ARR_SCHED_DT'] != null ? map['ARR_SCHED_DT'] as String : null,
-      SLOT_TIME_ACTUAL: map['SLOT_TIME_ACTUAL'] != null
-          ? map['SLOT_TIME_ACTUAL'] as String
-          : null,
-      LEG_TYPE: map['LEG_TYPE'] != null ? map['LEG_TYPE'] as String : null,
-      EMPLOYER_COCKPIT: map['EMPLOYER_COCKPIT'] != null
-          ? map['EMPLOYER_COCKPIT'] as String
-          : null,
-      EMPLOYER_CABIN: map['EMPLOYER_CABIN'] != null
-          ? map['EMPLOYER_CABIN'] as String
-          : null,
-//      CYCLES: map['CYCLES'] != null ? map['CYCLES'] as String : null,
-      DELAY_CODE_01:
-          map['DELAY_CODE_01'] != null ? map['DELAY_CODE_01'] as String : null,
-      DELAY_CODE_02:
-          map['DELAY_CODE_02'] != null ? map['DELAY_CODE_02'] as String : null,
-      DELAY_CODE_03:
-          map['DELAY_CODE_03'] != null ? map['DELAY_CODE_03'] as String : null,
-      DELAY_CODE_04:
-          map['DELAY_CODE_04'] != null ? map['DELAY_CODE_04'] as String : null,
-      DELAY_TIME_01:
-          map['DELAY_TIME_01'] != null ? map['DELAY_TIME_01'] as String : null,
-      DELAY_TIME_02:
-          map['DELAY_TIME_02'] != null ? map['DELAY_TIME_02'] as String : null,
-      DELAY_TIME_03:
-          map['DELAY_TIME_03'] != null ? map['DELAY_TIME_03'] as String : null,
-      DELAY_TIME_04:
-          map['DELAY_TIME_04'] != null ? map['DELAY_TIME_04'] as String : null,
-      SUBDELAY_CODE_01: map['SUBDELAY_CODE_01'] != null
-          ? map['SUBDELAY_CODE_01'] as String
-          : null,
-      SUBDELAY_CODE_02: map['SUBDELAY_CODE_02'] != null
-          ? map['SUBDELAY_CODE_02'] as String
-          : null,
-      SUBDELAY_CODE_03: map['SUBDELAY_CODE_03'] != null
-          ? map['SUBDELAY_CODE_03'] as String
-          : null,
-      SUBDELAY_CODE_04: map['SUBDELAY_CODE_04'] != null
-          ? map['SUBDELAY_CODE_04'] as String
-          : null,
-      PAX_BOOKED_C:
-          map['PAX_BOOKED_C'] != null ? map['PAX_BOOKED_C'] as String : null,
-      PAX_BOOKED_Y:
-          map['PAX_BOOKED_Y'] != null ? map['PAX_BOOKED_Y'] as String : null,
-      PAX_BOOKED_TRS_C: map['PAX_BOOKED_TRS_C'] != null
-          ? map['PAX_BOOKED_TRS_C'] as String
-          : null,
-      PAX_BOOKED_TRS_Y: map['PAX_BOOKED_TRS_Y'] != null
-          ? map['PAX_BOOKED_TRS_Y'] as String
-          : null,
-      PAD_BOOKED_C:
-          map['PAD_BOOKED_C'] != null ? map['PAD_BOOKED_C'] as String : null,
-      PAD_BOOKED_Y:
-          map['PAD_BOOKED_Y'] != null ? map['PAD_BOOKED_Y'] as String : null,
-      OFFBLOCK_DT_A:
-          map['OFFBLOCK_DT_A'] != null ? map['OFFBLOCK_DT_A'] as String : null,
-      AIRBORNE_DT_A:
-          map['AIRBORNE_DT_A'] != null ? map['AIRBORNE_DT_A'] as String : null,
-      LANDING_DT_A:
-          map['LANDING_DT_A'] != null ? map['LANDING_DT_A'] as String : null,
-      ONBLOCK_DT_A:
-          map['ONBLOCK_DT_A'] != null ? map['ONBLOCK_DT_A'] as String : null,
-      OFFBLOCK_DT_F:
-          map['OFFBLOCK_DT_F'] != null ? map['OFFBLOCK_DT_F'] as String : null,
-      AIRBORNE_DT_F:
-          map['AIRBORNE_DT_F'] != null ? map['AIRBORNE_DT_F'] as String : null,
-      LANDING_DT_F:
-          map['LANDING_DT_F'] != null ? map['LANDING_DT_F'] as String : null,
-      ONBLOCK_DT_F:
-          map['ONBLOCK_DT_F'] != null ? map['ONBLOCK_DT_F'] as String : null,
-      OFFBLOCK_DT_M:
-          map['OFFBLOCK_DT_M'] != null ? map['OFFBLOCK_DT_M'] as String : null,
-      AIRBORNE_DT_M:
-          map['AIRBORNE_DT_M'] != null ? map['AIRBORNE_DT_M'] as String : null,
-      LANDING_DT_M:
-          map['LANDING_DT_M'] != null ? map['LANDING_DT_M'] as String : null,
-      ONBLOCK_DT_M:
-          map['ONBLOCK_DT_M'] != null ? map['ONBLOCK_DT_M'] as String : null,
-      EET: map['EET'] != null ? map['EET'] as String : null,
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory Acleg.fromJson(String source) =>
-      Acleg.fromMap(json.decode(source) as Map<String, dynamic>);
-
-  @override
-  String toString() {
-    return 'Acleg(LEG_NO: $LEG_NO, FN_CARRIER: $FN_CARRIER, FN_NUMBER: $FN_NUMBER, FN_SUFFIX: $FN_SUFFIX, DAY_OF_ORIGIN: $DAY_OF_ORIGIN, AC_OWNER: $AC_OWNER, AC_SUBTYPE: $AC_SUBTYPE, AC_VERSION: $AC_VERSION, AC_REGISTRATION: $AC_REGISTRATION, DEP_AP_ACTUAL: $DEP_AP_ACTUAL, DEP_AP_SCHED: $DEP_AP_SCHED, DEP_DT_EST: $DEP_DT_EST, DEP_SCHED_DT: $DEP_SCHED_DT, ARR_AP_ACTUAL: $ARR_AP_ACTUAL, ARR_AP_SCHED: $ARR_AP_SCHED, ARR_DT_EST: $ARR_DT_EST, ARR_SCHED_DT: $ARR_SCHED_DT, SLOT_TIME_ACTUAL: $SLOT_TIME_ACTUAL, LEG_TYPE: $LEG_TYPE, EMPLOYER_COCKPIT: $EMPLOYER_COCKPIT, EMPLOYER_CABIN: $EMPLOYER_CABIN, CYCLES: $CYCLES, DELAY_CODE_01: $DELAY_CODE_01, DELAY_CODE_02: $DELAY_CODE_02, DELAY_CODE_03: $DELAY_CODE_03, DELAY_CODE_04: $DELAY_CODE_04, DELAY_TIME_01: $DELAY_TIME_01, DELAY_TIME_02: $DELAY_TIME_02, DELAY_TIME_03: $DELAY_TIME_03, DELAY_TIME_04: $DELAY_TIME_04, SUBDELAY_CODE_01: $SUBDELAY_CODE_01, SUBDELAY_CODE_02: $SUBDELAY_CODE_02, SUBDELAY_CODE_03: $SUBDELAY_CODE_03, SUBDELAY_CODE_04: $SUBDELAY_CODE_04, PAX_BOOKED_C: $PAX_BOOKED_C, PAX_BOOKED_Y: $PAX_BOOKED_Y, PAX_BOOKED_TRS_C: $PAX_BOOKED_TRS_C, PAX_BOOKED_TRS_Y: $PAX_BOOKED_TRS_Y, PAD_BOOKED_C: $PAD_BOOKED_C, PAD_BOOKED_Y: $PAD_BOOKED_Y, OFFBLOCK_DT_A: $OFFBLOCK_DT_A, AIRBORNE_DT_A: $AIRBORNE_DT_A, LANDING_DT_A: $LANDING_DT_A, ONBLOCK_DT_A: $ONBLOCK_DT_A, OFFBLOCK_DT_F: $OFFBLOCK_DT_F, AIRBORNE_DT_F: $AIRBORNE_DT_F, LANDING_DT_F: $LANDING_DT_F, ONBLOCK_DT_F: $ONBLOCK_DT_F, OFFBLOCK_DT_M: $OFFBLOCK_DT_M, AIRBORNE_DT_M: $AIRBORNE_DT_M, LANDING_DT_M: $LANDING_DT_M, ONBLOCK_DT_M: $ONBLOCK_DT_M, EET: $EET)';
-  }
-
-  @override
-  bool operator ==(covariant Acleg other) {
-    if (identical(this, other)) return true;
-
-    return other.LEG_NO == LEG_NO &&
-        other.FN_CARRIER == FN_CARRIER &&
-        other.FN_NUMBER == FN_NUMBER &&
-        other.FN_SUFFIX == FN_SUFFIX &&
-        other.DAY_OF_ORIGIN == DAY_OF_ORIGIN &&
-        other.AC_OWNER == AC_OWNER &&
-        other.AC_SUBTYPE == AC_SUBTYPE &&
-        other.AC_VERSION == AC_VERSION &&
-        other.AC_REGISTRATION == AC_REGISTRATION &&
-        other.DEP_AP_ACTUAL == DEP_AP_ACTUAL &&
-        other.DEP_AP_SCHED == DEP_AP_SCHED &&
-        other.DEP_DT_EST == DEP_DT_EST &&
-        other.DEP_SCHED_DT == DEP_SCHED_DT &&
-        other.ARR_AP_ACTUAL == ARR_AP_ACTUAL &&
-        other.ARR_AP_SCHED == ARR_AP_SCHED &&
-        other.ARR_DT_EST == ARR_DT_EST &&
-        other.ARR_SCHED_DT == ARR_SCHED_DT &&
-        other.SLOT_TIME_ACTUAL == SLOT_TIME_ACTUAL &&
-        other.LEG_TYPE == LEG_TYPE &&
-        other.EMPLOYER_COCKPIT == EMPLOYER_COCKPIT &&
-        other.EMPLOYER_CABIN == EMPLOYER_CABIN &&
-        other.CYCLES == CYCLES &&
-        other.DELAY_CODE_01 == DELAY_CODE_01 &&
-        other.DELAY_CODE_02 == DELAY_CODE_02 &&
-        other.DELAY_CODE_03 == DELAY_CODE_03 &&
-        other.DELAY_CODE_04 == DELAY_CODE_04 &&
-        other.DELAY_TIME_01 == DELAY_TIME_01 &&
-        other.DELAY_TIME_02 == DELAY_TIME_02 &&
-        other.DELAY_TIME_03 == DELAY_TIME_03 &&
-        other.DELAY_TIME_04 == DELAY_TIME_04 &&
-        other.SUBDELAY_CODE_01 == SUBDELAY_CODE_01 &&
-        other.SUBDELAY_CODE_02 == SUBDELAY_CODE_02 &&
-        other.SUBDELAY_CODE_03 == SUBDELAY_CODE_03 &&
-        other.SUBDELAY_CODE_04 == SUBDELAY_CODE_04 &&
-        other.PAX_BOOKED_C == PAX_BOOKED_C &&
-        other.PAX_BOOKED_Y == PAX_BOOKED_Y &&
-        other.PAX_BOOKED_TRS_C == PAX_BOOKED_TRS_C &&
-        other.PAX_BOOKED_TRS_Y == PAX_BOOKED_TRS_Y &&
-        other.PAD_BOOKED_C == PAD_BOOKED_C &&
-        other.PAD_BOOKED_Y == PAD_BOOKED_Y &&
-        other.OFFBLOCK_DT_A == OFFBLOCK_DT_A &&
-        other.AIRBORNE_DT_A == AIRBORNE_DT_A &&
-        other.LANDING_DT_A == LANDING_DT_A &&
-        other.ONBLOCK_DT_A == ONBLOCK_DT_A &&
-        other.OFFBLOCK_DT_F == OFFBLOCK_DT_F &&
-        other.AIRBORNE_DT_F == AIRBORNE_DT_F &&
-        other.LANDING_DT_F == LANDING_DT_F &&
-        other.ONBLOCK_DT_F == ONBLOCK_DT_F &&
-        other.OFFBLOCK_DT_M == OFFBLOCK_DT_M &&
-        other.AIRBORNE_DT_M == AIRBORNE_DT_M &&
-        other.LANDING_DT_M == LANDING_DT_M &&
-        other.ONBLOCK_DT_M == ONBLOCK_DT_M &&
-        other.EET == EET;
-  }
-
-  @override
-  int get hashCode {
-    return LEG_NO.hashCode ^
-        FN_CARRIER.hashCode ^
-        FN_NUMBER.hashCode ^
-        FN_SUFFIX.hashCode ^
-        DAY_OF_ORIGIN.hashCode ^
-        AC_OWNER.hashCode ^
-        AC_SUBTYPE.hashCode ^
-        AC_VERSION.hashCode ^
-        AC_REGISTRATION.hashCode ^
-        DEP_AP_ACTUAL.hashCode ^
-        DEP_AP_SCHED.hashCode ^
-        DEP_DT_EST.hashCode ^
-        DEP_SCHED_DT.hashCode ^
-        ARR_AP_ACTUAL.hashCode ^
-        ARR_AP_SCHED.hashCode ^
-        ARR_DT_EST.hashCode ^
-        ARR_SCHED_DT.hashCode ^
-        SLOT_TIME_ACTUAL.hashCode ^
-        LEG_TYPE.hashCode ^
-        EMPLOYER_COCKPIT.hashCode ^
-        EMPLOYER_CABIN.hashCode ^
-        CYCLES.hashCode ^
-        DELAY_CODE_01.hashCode ^
-        DELAY_CODE_02.hashCode ^
-        DELAY_CODE_03.hashCode ^
-        DELAY_CODE_04.hashCode ^
-        DELAY_TIME_01.hashCode ^
-        DELAY_TIME_02.hashCode ^
-        DELAY_TIME_03.hashCode ^
-        DELAY_TIME_04.hashCode ^
-        SUBDELAY_CODE_01.hashCode ^
-        SUBDELAY_CODE_02.hashCode ^
-        SUBDELAY_CODE_03.hashCode ^
-        SUBDELAY_CODE_04.hashCode ^
-        PAX_BOOKED_C.hashCode ^
-        PAX_BOOKED_Y.hashCode ^
-        PAX_BOOKED_TRS_C.hashCode ^
-        PAX_BOOKED_TRS_Y.hashCode ^
-        PAD_BOOKED_C.hashCode ^
-        PAD_BOOKED_Y.hashCode ^
-        OFFBLOCK_DT_A.hashCode ^
-        AIRBORNE_DT_A.hashCode ^
-        LANDING_DT_A.hashCode ^
-        ONBLOCK_DT_A.hashCode ^
-        OFFBLOCK_DT_F.hashCode ^
-        AIRBORNE_DT_F.hashCode ^
-        LANDING_DT_F.hashCode ^
-        ONBLOCK_DT_F.hashCode ^
-        OFFBLOCK_DT_M.hashCode ^
-        AIRBORNE_DT_M.hashCode ^
-        LANDING_DT_M.hashCode ^
-        ONBLOCK_DT_M.hashCode ^
-        EET.hashCode;
-  }
-}

+ 0 - 175
lib/flightslist/flightslist_page.dart.bak2

@@ -1,175 +0,0 @@
-import 'package:collection/collection.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:go_router/go_router.dart';
-import 'package:tp5/core/basic_page.dart';
-import 'package:tp5/core/utils.dart';
-import 'package:tp5/csv/data.dart';
-import 'package:tp5/fltinfo/view/fltinfo_page.dart';
-import 'package:tp5/widgets/my_col.dart';
-
-class FlightslistPage extends ConsumerStatefulWidget {
-  const FlightslistPage({super.key});
-
-  @override
-  ConsumerState<ConsumerStatefulWidget> createState() =>
-      _FlightslistPageState();
-}
-
-class _FlightslistPageState extends ConsumerState<FlightslistPage> {
-  bool showAllLegs = false;
-  _acLegs() {
-    final aclegs = ref.watch(dataProvider).acleg;
-    final now = ref.watch(clockProvider);
-    final firstlegafternow =
-        aclegs.firstWhereOrNull((l) => l.jdep!.isSameOrAfter(now)) ?? Acleg();
-    return Container(
-      child: aclegs.isEmpty
-          ? const Text("No leg found !")
-          : SingleChildScrollView(
-              scrollDirection: Axis.horizontal,
-              child: MyCol(
-                children: [
-                  if (!showAllLegs)
-                    TextButton(
-                        onPressed: () => setState(() {
-                              showAllLegs = true;
-                            }),
-                        child: const Text("Show all legs")),
-                  DataTable(
-                      showCheckboxColumn: false,
-                      border: TableBorder.all(width: 2),
-                      headingRowHeight: 5,
-                      columnSpacing: 20,
-                      dataRowMaxHeight: 31,
-                      dataRowMinHeight: 30,
-                      columns: [
-                        "Time",
-                        "Dep-Arr",
-                        "FNum",
-                        "Reg",
-                        "Status",
-                        "Delay"
-                      ].map((e) => DataColumn(label: Text(e))).toList(),
-                      rows: aclegs
-                          .whereIndexed((i, leg) =>
-                              showAllLegs ||
-                              (i >= aclegs.indexOf(firstlegafternow) - 10))
-                          .map(
-                            (Acleg x) => DataRow(
-                                onSelectChanged: (s) => context.push("/fltinfo",
-                                    extra: FltinfoParams(
-                                        al: x.FN_CARRIER,
-                                        fnum: x.FN_NUMBER,
-                                        jdep: x.jdep,
-                                        jdes: x.jarr,
-                                        dep: x.DEP_AP_ACTUAL,
-                                        des: x.ARR_AP_SCHED)),
-                                color: WidgetStateProperty.all(
-                                    (x == firstlegafternow)
-                                        ? Colors.purple[900]
-                                        : ((x.jdep!.isBefore(now))
-                                            ? Colors.black
-                                            : const Color.fromARGB(
-                                                255, 2, 21, 30))),
-                                cells: [
-                                  DataCell(Column(
-                                    children: [
-                                      Text(
-                                        "${x.jdep?.format(pattern: "dd MMM'yy")}",
-                                        style: TextStyle(
-                                            color: Colors.blueGrey[200],
-                                            fontWeight: FontWeight.w700,
-                                            fontSize: 10),
-                                      ),
-                                      Text(
-                                        "${x.jdep?.Hm ?? ""} ${x.jarr?.Hm ?? ""}",
-                                        style: const TextStyle(
-                                            color: Colors.blueGrey,
-                                            fontWeight: FontWeight.w600,
-                                            fontSize: 12),
-                                      ),
-                                    ],
-                                  )),
-                                  DataCell(Text(
-                                    " ${x.DEP_AP_ACTUAL ?? ""}-${x.ARR_AP_ACTUAL ?? ""}",
-                                  )),
-                                  DataCell(Text(
-                                    " ${x.FN_CARRIER ?? ""}${x.FN_NUMBER ?? ""}${x.FN_SUFFIX ?? ""}",
-                                    style: const TextStyle(fontSize: 12),
-                                  )),
-                                  DataCell(Text(x.flt_status,
-                                      style: TextStyle(
-                                          fontSize: 10,
-                                          fontWeight: FontWeight.bold,
-                                          color: x.flt_status == "Arrived"
-                                              ? Colors.cyan
-                                              : Colors.amber))),
-                                  DataCell(Text(x.AC_REGISTRATION ?? "-----",
-                                      style: TextStyle(
-                                          fontSize: 10,
-                                          fontWeight: FontWeight.bold,
-                                          color: x.EMPLOYER_COCKPIT == "TU"
-                                              ? Colors.green
-                                              : Colors.red))),
-                                  DataCell(
-                                      placeholder: true,
-                                      (x.jdep!.isAfter(x.jdepsched!))
-                                          ? Text(x.jdep!.dateTime
-                                              .difference(x.jdepsched!.dateTime)
-                                              .tohhmm)
-                                          : const Text("")),
-                                ]),
-                          )
-                          .toList()),
-                ],
-              ),
-            ),
-    );
-  }
-
-
-  final bottomnavstyle = ElevatedButton.styleFrom(
-      shape: RoundedRectangleBorder(
-        borderRadius: BorderRadius.circular(5.0),
-      ),
-      backgroundColor:
-          const Color.fromARGB(255, 0, 36, 53) //elevated btton background color
-      );
-
-  @override
-  Widget build(BuildContext context) {
-    return BasicPage(
-      appBar: AppBar(
-        title: Text('Flights List'),
-      ),      bottomNavigationBar: Container(
-        padding: const EdgeInsets.all(8),
-        // color: Colors.black,
-        decoration: BoxDecoration(
-            gradient: LinearGradient(
-          begin: Alignment.topCenter,
-          end: Alignment.bottomCenter,
-          colors: [
-            Colors.grey[700]!,
-            Colors.black,
-          ],
-        )),
-        child: Row(
-          mainAxisAlignment: MainAxisAlignment.spaceAround,
-          children: [
-            ElevatedButton.icon(
-              onPressed: () {
-                _showMonths(context);
-              },
-              icon: const Icon(
-                  Icons.calendar_month), //icon data for elevated button
-              label: const Text("Change\nMonth"), //label text
-              style: bottomnavstyle,
-            ),
-
-      body: Center(
-        child: _acLegs(),
-      ),
-    );
-  }
-}

+ 0 - 37
lib/fltinfo/view/datatable.dart.bak

@@ -1,37 +0,0 @@
-DataTable _createDataTable() {
-    return DataTable(
-      columns: _createColumns(),
-      rows: _createRows(),
-      sortColumnIndex: _currentSortColumn,
-      sortAscending: _isSortAsc,
-    );
-  }
-List<DataColumn> _createColumns() {
-    return [
-      DataColumn(
-        label: Text('ID'),
-        onSort: (columnIndex, _) {
-          setState(() {
-            _currentSortColumn = columnIndex;
-            if (_isSortAsc) {
-              _books.sort((a, b) => b['id'].compareTo(a['id']));
-            } else {
-              _books.sort((a, b) => a['id'].compareTo(b['id']));
-            }
-            _isSortAsc = !_isSortAsc;
-          });
-        },
-      ),
-      DataColumn(label: Text('Book')),
-      DataColumn(label: Text('Author'))
-    ];
-  }
-List<DataRow> _createRows() {
-    return _books
-        .map((book) => DataRow(cells: [
-              DataCell(Text('#' + book['id'].toString())),
-              DataCell(Text(book['title'])),
-              DataCell(Text(book['author']))
-            ]))
-        .toList();
-  }

+ 13 - 20
lib/fltinfo/view/dutyinfo_page.dart

@@ -56,7 +56,7 @@ class _DutyinfoPageState extends ConsumerState<DutyinfoPage> {
 
   @override
   Widget build(BuildContext context) {
-    final data = ref.watch(dataProvider);
+    //final data = ref.watch(dataProvider);
     //final pnleg = data.pnleg;
     // final _dateNotifiedcrew = data.pnlegupdate;
 
@@ -70,7 +70,7 @@ class _DutyinfoPageState extends ConsumerState<DutyinfoPage> {
           // mainAxisAlignment: MainAxisAlignment.spaceBetween,
           children: [
             Text(
-                '${widget.params.dutytype ?? ""} ${widget.params.label} ${widget.params.dep}${widget.params.des != null ? "-${widget.params.des}" : ""}'),
+                '${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)),
@@ -100,6 +100,16 @@ class _DutyinfoPageState extends ConsumerState<DutyinfoPage> {
             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,
@@ -189,7 +199,7 @@ class _DutyinfoPageState extends ConsumerState<DutyinfoPage> {
                   fontSize: 10, fontWeight: FontWeight.w300))
           : null,
       child: crewPnleg.isEmpty
-          ? const Text("No Flights found !")
+          ? const Text("No data found !")
           : Column(
               children: [
                 Padding(
@@ -224,23 +234,6 @@ class _DutyinfoPageState extends ConsumerState<DutyinfoPage> {
                     );
                   }).toList()),
                 )
-
-                // Padding(
-                //   padding: const EdgeInsets.all(8.0),
-                //   child: Column(
-                //       children: crewPnleg[
-                //               crewPnleg.keys.elementAt(crewPosPnleg)]!
-                //           .map<Widget>((x) {
-                //     final pn =
-                //         qualif.firstWhereOrNull((e) => e.tlc == x.tlc);
-                //     return WCrew(
-                //       college: pn?.college,
-                //       mle: x.tlc,
-                //       base: pn?.base,
-                //       name: "${pn?.lname}, ${pn?.fname}",
-                //     );
-                //   }).toList()),
-                // )
               ],
             ),
     );

+ 11 - 4
lib/fltinfo/view/fltinfo_page.dart

@@ -83,13 +83,11 @@ class _FltinfoPageState extends ConsumerState<FltinfoPage> {
     // crew = crew.where((leg)=>);
     crew = crew
         .where((leg) =>
-            jiffyfromddmmmyyhhmm(leg[2] + " " + leg[4])
+            jiffyfromddmmmyyhhmm("${leg[2]} ${leg[4]}")
                 .diff(widget.params.jdep!, unit: Unit.hour)
                 .abs() <
             5)
         .toList();
-    print(
-        "------ ${jiffyfromddmmmyyhhmm(crew.first[2] + " " + crew.first[4]).Hm}");
 
     if (crew.isNotEmpty) _dateCrewbox = Jiffy.now().toUtc();
     //print(_crewList);
@@ -256,6 +254,7 @@ class _FltinfoPageState extends ConsumerState<FltinfoPage> {
 
   Jiffy? _dateCrewbox;
   _crewBox() {
+    final crewlinkCredsaved = ref.watch(crewlinkapiProvider).credSaved();
     return WCadre(
       title: "Crew",
       titleright: _loadingCrew
@@ -275,7 +274,15 @@ class _FltinfoPageState extends ConsumerState<FltinfoPage> {
                   fontSize: 10, fontWeight: FontWeight.w300))
           : null,
       child: crew.isEmpty
-          ? const Text("No Flights found on Crewlink!")
+          ? (!crewlinkCredsaved
+              ? ElevatedButton.icon(
+                  label: const Text("Activate Crewlink",
+                      style: TextStyle(fontSize: 9)),
+                  onPressed: () {
+                    context.push("/crewlink/settings");
+                  },
+                  icon: const Icon(Icons.update))
+              : const Text("No Flights found on Crewlink!"))
           : Column(
               children: [
                 Column(children: [

+ 0 - 1441
lib/ftl/provider/ftl copy.dart.bak

@@ -1,1441 +0,0 @@
-import 'dart:developer';
-
-import 'package:collection/collection.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:tp5/core/core.dart';
-import 'package:tp5/providers/airports.dart';
-import 'package:tp5/roster/models/duty.dart';
-
-import 'package:timezone/timezone.dart' as tz;
-
-class Ftl {
-  Duration minimumrest(String? station) =>
-      Duration(hours: station == base ? 12 : 12, minutes: 0, seconds: 0);
-  static Duration postflight = const Duration(minutes: 30);
-  static Duration preflight = const Duration(minutes: 60);
-  static Duration maxdutylast7 = const Duration(hours: 60);
-  static Duration maxdutylast14 = const Duration(hours: 110);
-  static Duration maxdutylast28 = const Duration(hours: 190);
-  static Duration maxfltlast28 = const Duration(hours: 100);
-  static Duration maxfltlastyear = const Duration(hours: 900);
-  static Duration maxfltlast12 = const Duration(hours: 1000);
-  Duration travelling(String station) {
-    if (base == station) return Duration.zero;
-    switch (station) {
-      case "DSS":
-        return const Duration(minutes: 60);
-      case "ORY":
-        return const Duration(minutes: 5);
-      default:
-        return const Duration(minutes: 30);
-    }
-  }
-
-  String base;
-
-  List<FtlDutyDetails> dutiesDetails = [];
-  List<Duty> clDuties = [];
-  List<FtlDuty> duties = [];
-
-  // List<FtlDutyTotal> dutiesLength = [];
-
-  List<DTInterval> get dutiesAsInterval => duties
-      .map((e) =>
-          (e.type != FtlDutyType.other) ? DTInterval(e.start!, e.end!) : null)
-      .whereNotNull()
-      .toList();
-  List<DTInterval> get stdbyAsInterval => dutiesDetails
-      .map((e) => (e.type == FtlDutyDetailsType.standby)
-          ? DTInterval(e.start!, e.end!)
-          : null)
-      .whereNotNull()
-      .toList();
-  List<DTInterval> get fltsAsInterval => dutiesDetails
-      .map((e) => (e.type == FtlDutyDetailsType.flight)
-          ? DTInterval(e.start!, e.end!)
-          : null)
-      .whereNotNull()
-      .toList();
-  bool frms;
-  Ftl({required this.dutiesDetails, required this.base, this.frms = false});
-  Ftl.fromCrewlink(
-      {required this.clDuties, required this.base, this.frms = false}) {
-    for (Duty one in clDuties) {
-      switch (one.type) {
-        case "flight":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.flight,
-              label: one.data["label"],
-            ),
-          );
-        case "dhflight":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.dhflight,
-              label: one.data["label"],
-            ),
-          );
-        case "dhlimo":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.dhlimo,
-              label: one.data["label"],
-            ),
-          );
-        case "ground":
-          if (["SBY1", "SBY2", "SBY3"].contains(one.data["label"])) {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.standby,
-                label: one.data["label"],
-              ),
-            );
-          } else if (["R0"].contains(one.data["label"])) {
-            //reserve is not duty
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.reserve,
-                label: one.data["label"],
-              ),
-            );
-          } else if ((one.data["actype"] ?? "") != "") {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.sim,
-                label: one.data["label"],
-              ),
-            );
-          } else if (one.start != null &&
-              one.end != null &&
-              one.end!.diff(one.start!, unit: Unit.hour).abs() < 12) {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.ground,
-                label: one.data["label"],
-              ),
-            );
-          } else {
-            // print("ftl: constr: unknown ${one.date} ${one.type} ${one.data}");
-          }
-        case "checkin":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              // placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.preflight,
-            ),
-          );
-
-        case "checkout":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              // placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.postflight,
-            ),
-          );
-        case "credit":
-        case "wholeday":
-          break;
-        default:
-        // print("ftl: unk: ${one.date} ${one.type} ${one.data}");
-      }
-    }
-  }
-
-  Jiffy? _calcPostflight(FtlDutyDetails xduty) {
-    if (xduty.end != null &&
-        [FtlDutyDetailsType.flight, FtlDutyDetailsType.dhflight]
-            .contains(xduty.type)) {
-      return xduty.end!.addDuration(postflight);
-    } else {
-      return xduty.end;
-    }
-  }
-
-  Jiffy? _calcPreflight(FtlDutyDetails xduty) {
-    if (xduty.start != null &&
-        [
-          FtlDutyDetailsType.flight,
-          FtlDutyDetailsType.dhflight,
-          FtlDutyDetailsType.dhlimo,
-          FtlDutyDetailsType.sim,
-        ].contains(xduty.type)) {
-      return (base == (xduty.placeStart ?? ""))
-          ? xduty.start!.subtractDuration(const Duration(minutes: 60))
-          : (xduty.start!.subtractDuration(preflight));
-    } else {
-      return xduty.start;
-    }
-  }
-
-  final List<FtlDutyDetailsType> _fdpList = [
-    FtlDutyDetailsType.flight,
-    FtlDutyDetailsType.dhflight,
-    FtlDutyDetailsType.dhlimo
-  ];
-
-  //calcul duties
-  calcduties({Jiffy? date}) {
-    log("FTL: start calcduties");
-    duties.clear();
-
-    final t1 = Jiffy.now();
-    _calcDuty();
-
-    log("FTL: start _calcfdpmax");
-    _calcfdpmax();
-
-    log("FTL: start _clacdutytotal");
-    // _calcDutyTotal();
-
-    log("FTL: start calclegal");
-    _calcLegal(date: date);
-
-    final t4 = Jiffy.now();
-    print(
-        "ftl: calcduties calculation :  ${t4.diff(t1, unit: Unit.second, asFloat: true)} ms");
-
-    log("FTL: finish calcduties");
-
-    // return [duties, dutiesDetails, dutiesLength];
-    return [duties, dutiesDetails];
-  }
-
-  _calcDuty() {
-    for (int i = 0; i < dutiesDetails.length; i++) {
-      var last = i > 0 ? dutiesDetails[i - 1] : null;
-
-      final checkin = ((last?.type == FtlDutyDetailsType.preflight)
-          ? dutiesDetails[i - 1].start
-          : null);
-
-      final newduty =
-          _addDutyDetail(index: i, duty: FtlDuty(), checkin: checkin);
-      //print("${dutiesDetails[i].type} $newduty");
-      if (newduty != null) {
-        if (duties.isEmpty) {
-          //first duty
-          duties.add(newduty);
-        } else if ((newduty.start!.isAfter(duties.last.end!)) &&
-            (duties.last.type == FtlDutyType.other ||
-                newduty.type == FtlDutyType.other)) {
-          //last and new are not duty nor fdp (other=>stdby or rsrv)
-          duties.add(newduty);
-        } else if ((newduty.start!
-                .subtractDuration(travelling(newduty.placeStart ?? base))
-                .isAfter(
-                  duties.last.end!
-                      .addDuration(travelling(duties.last.placeEnd ?? base)),
-                )) &&
-            // duties.last.type == FtlDutyType.duty &&
-            newduty.type == FtlDutyType.duty) {
-          //last is duty
-          duties.add(newduty);
-        } else if (newduty.start!.diff(duties.last.end!, unit: Unit.minute) <
-            minimumrest(duties.last.placeEnd).inMinutes) {
-          //diff < minimumrest
-          //ilhim
-          final mergedduty = _addDutyDetail(
-              index: i,
-              duty: duties.isNotEmpty ? duties.last : FtlDuty(),
-              checkin: checkin);
-          duties[duties.length - 1] = mergedduty!;
-        } else {
-          //jdida
-          duties.add(newduty);
-        }
-      }
-    }
-  }
-
-  _calcfdpmax() {
-    for (var i = 0; i < duties.length; i++) {
-      FtlDuty duty = duties[i];
-      FtlDuty? lastduty = i == 0 ? null : duties[i - 1];
-      if (duty.type == FtlDutyType.fdp) {
-        String acclim = _acclimatized(
-            tzoffset: tzDiff(duty.placeStart!, lastduty?.placeEnd ?? base,
-                duty.start!.dateTime),
-            timeElapsed:
-                lastduty?.end!.dateTime.difference(duty.start!.dateTime) ??
-                    const Duration());
-        duties[i].acclim = acclim;
-        duties[i].reftime = changeTz(duty.start!, duty.placeStart ?? base).Hm;
-
-        Jiffy reftime = duty.start!;
-        if (duty.reportdelay2 != null && duty.reportdelay1 != null) {
-          if (duty.start!.dateTime
-                  .difference(duty.reportdelay2!.dateTime)
-                  .inMinutes <
-              (4 * 60)) {
-            reftime = duty.start!;
-            duty.start =
-                duty.notification2!.add(hours: 1).min(duty.reportdelay1!);
-          } else {
-            reftime = duty.reportdelay2!;
-            duty.start = duty.reportdelay2!;
-          }
-        } else if (duty.reportdelay1 != null) {
-          if (duty.start!.dateTime
-                  .difference(duty.reportdelay1!.dateTime)
-                  .inMinutes <
-              (4 * 60)) {
-            reftime = duty.start!;
-            duty.start = duty.reportdelay1!;
-          } else {
-            reftime = duty.reportdelay1!;
-            duty.start = duty.reportdelay1!;
-          }
-        }
-
-        switch (acclim) {
-          case "D":
-            // print("${duty.start?.yMMMd} ${duty.start?.toUtc().Hm}");
-            duties[i].fdpMax = fdpMaxBasic(
-                reftime: reftime, iata: duty.placeStart, sectors: duty.sectors);
-            duties[i].fdpExtMax = fdpMaxExtBasic(
-                reftime: reftime, iata: duty.placeStart, sectors: duty.sectors);
-          case "B":
-            duties[i].fdpMax = fdpMaxBasic(
-                reftime: reftime,
-                iata: lastduty?.placeEnd ?? lastduty?.placeStart ?? base,
-                sectors: duty.sectors);
-            duties[i].fdpExtMax = fdpMaxExtBasic(
-                reftime: reftime,
-                iata: lastduty?.placeEnd ?? lastduty?.placeStart ?? base,
-                sectors: duty.sectors);
-          case "X":
-            if (frms) {
-              duties[i].fdpMax = fdpMaxUnk(
-                  reftime: reftime,
-                  iata: duty.placeStart,
-                  sectors: duty.sectors);
-            } else {
-              duties[i].fdpMax = fdpMaxUnkFrms(
-                  reftime: reftime,
-                  iata: duty.placeStart,
-                  sectors: duty.sectors);
-            }
-            break;
-          default:
-        }
-      }
-    }
-  }
-
-  _calcLegal({Jiffy? date}) {
-    if (date == null) {
-      for (var i = 0; i < duties.length; i++) {
-        _checklegal(index: i);
-      }
-    } else {
-      duties.forEachIndexed((i, e) {
-        if (duties[i]
-            .start!
-            .isSameOrAfter(date.startOf(Unit.day).subtract(days: 1))) {
-          _checklegal(index: i);
-        }
-      });
-    }
-  }
-
-  Duration _sumDuration(List<DTInterval> x) =>
-      Duration(milliseconds: x.map((e) => e.duration.inMilliseconds).sum);
-
-  List<DTInterval> breaks(FtlDuty duty) {
-    List<DTInterval> out = [];
-    for (var e in duty.dutiesDetailsIndex) {
-      final dutydetail = dutiesDetails[e];
-      final deptravel = (base == (dutydetail.placeStart ?? ""))
-          ? Duration.zero
-          : travelling(dutydetail.placeStart ?? "");
-      final destravel = (base == (dutydetail.placeEnd ?? ""))
-          ? Duration.zero
-          : travelling(dutydetail.placeEnd ?? dutydetail.placeStart ?? "");
-      final start = _calcPreflight(dutydetail)!.subtractDuration(deptravel);
-      final finish = _calcPostflight(dutydetail)!.addDuration(destravel);
-      if (finish.isAfter(start)) {
-        out.add(DTInterval(start, finish));
-      }
-    }
-    return duty.interval.minusmany(out);
-  }
-
-  _checklegal({required int index}) {
-    FtlDuty duty = duties[index];
-
-    final date = changeTz(duty.start!, base).endOf(Unit.day);
-    // log("ftl: dutylenght date=${date.format(pattern: "ddMMMyy HHmm")} \n date-7=${date.subtract(days: 7 - 1).startOf(Unit.day).format(pattern: "ddMMMyy HHmm")}");
-    // print("${date.yMEd}");
-    final dutyLength = FtlDutyTotal(
-        date: date, dutyLength: Duration.zero, fltLength: Duration.zero)
-      ..dutylast7 = _sumDuration(
-              DTInterval(date.subtract(days: 7 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(
-                  DTInterval(date.subtract(days: 7 - 1).startOf(Unit.day), date)
-                      .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..dutylast14 = _sumDuration(
-              DTInterval(date.subtract(days: 14 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(DTInterval(
-                      date.subtract(days: 14 - 1).startOf(Unit.day), date)
-                  .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..dutylast28 = _sumDuration(
-              DTInterval(date.subtract(days: 28 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(DTInterval(
-                      date.subtract(days: 28 - 1).startOf(Unit.day), date)
-                  .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..fltlast28 = _sumDuration(
-          DTInterval(date.subtract(days: 28 - 1).startOf(Unit.day), date)
-              .intersectionmany(fltsAsInterval))
-      ..fltlast12 = _sumDuration(DTInterval(
-              date.endOf(Unit.month).subtract(months: 12).startOf(Unit.month),
-              date)
-          .intersectionmany(fltsAsInterval))
-      ..fltyear = _sumDuration(DTInterval(date.startOf(Unit.year), date)
-          .intersectionmany(fltsAsInterval));
-    duty.dutyTotal = dutyLength;
-    // print("${date.yMEd} ${dutyLength.fltyear?.tohhmm}");
-
-    // dutylast7,
-    if ((dutyLength.dutylast7?.inMinutes ?? 0) > maxdutylast7.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast7,
-          legalCauseMsg:
-              "Max duty in 7 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast7?.tohhmm} / ${maxdutylast7.inHours}h"));
-    }
-    // dutylast14,
-    if ((dutyLength.dutylast14?.inMinutes ?? 0) > maxdutylast14.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast14,
-          legalCauseMsg:
-              "Max duty in 14 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast14?.tohhmm} / ${maxdutylast14.inHours}h"));
-    }
-    // dutylast28,
-    if ((dutyLength.dutylast28?.inMinutes ?? 0) > maxdutylast28.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast28,
-          legalCauseMsg:
-              "Max duty in 28 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast28?.tohhmm} / ${maxdutylast28.inHours}h"));
-    }
-    // fltlast28,
-    if ((dutyLength.fltlast28?.inMinutes ?? 0) > maxfltlast28.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltlast28,
-          legalCauseMsg:
-              "Max flight hours in 28 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.fltlast28?.tohhmm} / ${maxfltlast28.inHours}h"));
-    }
-
-    // fltyear,
-    if ((dutyLength.fltyear?.inMinutes ?? 0) > maxfltlastyear.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltyear,
-          legalCauseMsg:
-              "Max flight hours in calendar year ${duty.start?.format(pattern: "yyyy")} exceeded: ${dutyLength.fltyear?.tohhmm} / ${maxfltlastyear.inHours}h"));
-    }
-    // fltlast12,
-    if ((dutyLength.fltlast12?.inMinutes ?? 0) > maxfltlast12.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltlast12,
-          legalCauseMsg:
-              "Max flight hours in 12 months ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.fltlast12?.tohhmm} / ${maxfltlast12.inHours}h"));
-    }
-
-    // fdpmax,
-    if (duty.type == FtlDutyType.fdp && duty.fdpMax != null) {
-      if (duty.fdpLength.inMinutes <= duty.fdpMax!.inMinutes) {
-      } else if (duty.fdpExtMax != null &&
-          duty.fdpLength.inMinutes <= duty.fdpExtMax!.inMinutes) {
-        int nbFdpExt = 0;
-        for (var i = index;
-            i >= 0 &&
-                DTInterval(
-                        changeTz(duty.start!, base)
-                            .startOf(Unit.day)
-                            .subtract(days: 7),
-                        changeTz(duty.end!, base))
-                    .isOverlap(DTInterval(duties[i].start!, duties[i].end!));
-            i--) {
-          if (duties[i].fdpExt) nbFdpExt++;
-        }
-
-        if (nbFdpExt < 2) {
-          duty.fdpExt = true;
-          duties[index] = duty;
-        } else {
-          //nbext more than2 in 7days
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              legalCauseMsg:
-                  "FDP Ext used more than twice in 7 days. ${duty.fdpLength.tohhmm} / ${duty.fdpMax?.tohhmm} / ext${duty.fdpExtMax?.tohhmm}"));
-        }
-      } else if (breaks(duty).any((e) => (e.duration.inHours > 3)
-          //&&
-          // ((duty.fdpLength.inMinutes) <=
-          //     (e.duration
-          //         .multiply(0.5)
-          //         .add(duty.fdpMax ?? Duration.zero)
-          //         .inMinutes)))) {
-          )) {
-        //split duty check
-        final fdpmaxbreak = breaks(duty)
-            .map((e) => ((e.duration.inHours > 3)
-                ? ((e.duration.multiply(0.5).add(duty.fdpMax ?? Duration.zero)))
-                : null))
-            .whereNotNull();
-        if (fdpmaxbreak.isNotEmpty && duty.fdpLength < fdpmaxbreak.first) {
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              condition:
-                  "A break on ground must be considered to extend FDP Max to ${fdpmaxbreak.first.tohhmm}, ",
-              legalCauseMsg: "FDP is: ${duty.fdpLength.tohhmm}"));
-        } else {
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              legalCauseMsg:
-                  "FDP Max is excedeed even with ground break of ${breaks(duty).map((e) => ((e.duration.inHours > 3) ? (e.duration) : null)).whereNotNull().first.tohhmm}.  FDP:${duty.fdpLength.tohhmm}/Max:${fdpmaxbreak.first.tohhmm}"));
-        }
-      } else {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.fdpmax,
-            legalCauseMsg:
-                "FDP is ${duty.fdpLength.tohhmm}/Max:${duty.fdpMax?.tohhmm}"));
-      }
-    }
-    // restfdp without ext,
-    final FtlDuty? lastduty = (index > 0) ? duties[index - 1] : null;
-    // log("ftl: checking duty <${duty}> lastduty ended <${lastduty}>");
-
-    if (lastduty != null &&
-        duty.type == FtlDutyType.fdp &&
-        (lastduty.type == FtlDutyType.fdp ||
-            lastduty.type == FtlDutyType.duty ||
-            lastduty.dutiesDetailsIndex.any(
-                (e) => dutiesDetails[e].type == FtlDutyDetailsType.standby))) {
-      final rest = minimumrest(lastduty.placeEnd)
-          .max(duty.end!.dateTime.difference(duty.start!.dateTime));
-      duties[index - 1].restends = lastduty.end!.addDuration(rest);
-
-      if (lastduty.restends!.isAfter(duty.start!)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restfdp,
-            legalCauseMsg:
-                "Need more rest before starting FDP. rest: ${duty.start!.dateTime.difference(lastduty.end!.dateTime).tohhmm} / ${rest.tohhmm}"));
-      }
-    }
-    // restfdp with ext,
-    duty = duties[index];
-    FtlDuty? nextduty = (index < duties.length - 1) ? duties[index + 1] : null;
-    if (duty.fdpExt) {
-      final restbefore = (lastduty == null)
-          ? null
-          : minimumrest(lastduty.placeEnd)
-              .max(lastduty.end!.dateTime.difference(lastduty.start!.dateTime));
-      final restafter = (nextduty == null)
-          ? null
-          : minimumrest(duty.placeEnd)
-              .max(duty.end!.dateTime.difference(duty.start!.dateTime));
-//+2h rest before && 2h rest after
-      if ((lastduty == null ||
-              duty.start!.dateTime
-                      .difference(lastduty.end!.dateTime)
-                      .inMinutes >=
-                  (restbefore?.inMinutes ?? 0) + (2 * 60)) &&
-          (nextduty == null ||
-              nextduty.start!.dateTime
-                      .difference(duty.end!.dateTime)
-                      .inMinutes >=
-                  (restafter?.inMinutes ?? 0) + (60 * 2))) {
-      }
-//+4h rest after
-      else if ((nextduty == null ||
-          nextduty.start!.dateTime.difference(duty.end!.dateTime).inMinutes >=
-              (restafter?.inMinutes ?? 0) + (60 * 4))) {
-      }
-//not enough rest
-      else {
-        duty.restends = duty.end!.addDuration(restafter!).add(hours: 4);
-        duties[index] = duty;
-        nextduty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restfdp,
-            legalCauseMsg:
-                "Need more rest after ExtFDP before starting FDP on ${nextduty.start?.format(pattern: "ddMMMyy HH:mm")} rest: ${nextduty.start?.dateTime.difference(duty.end!.dateTime).tohhmm} / ${restafter.tohhmm}"));
-        duties[index + 1] = nextduty;
-      }
-    }
-    // restrecurrent,
-
-    //   36h inc 2 local nights or (60h if 4 disruptive)
-    Duration maxdutyrecrest = const Duration(hours: 168);
-    Duration minrecrest = const Duration(hours: 36);
-
-    DTInterval rest = DTInterval(duty.start!, duty.start!);
-    var i = index;
-
-    int nbdisruptive = 0;
-
-    while (i >= 1 &&
-        !(rest.duration.inMinutes >= const Duration(hours: 36).inMinutes &&
-            rest.contains(DTInterval.fromHm(
-                apartir: changeTz(rest.start, duties[i].placeStart!),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 7, minutes: 59))) &&
-            rest.contains(DTInterval.fromHm(
-                apartir:
-                    changeTz(rest.start.add(hours: 24), duties[i].placeStart!),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 7, minutes: 59))))) {
-      final thisduty = duties[i];
-
-      if (_isEarlyStart(thisduty) ||
-          _isLateFinish(thisduty) ||
-          _isNightDuty(thisduty)) {
-        // log("${thisduty}");
-        nbdisruptive++;
-        if (nbdisruptive == 4) {
-          minrecrest = const Duration(hours: 60);
-        }
-      }
-      i--;
-      rest = DTInterval(duties[i].end!, duties[i + 1].start!);
-    }
-
-    if (DTInterval(rest.end, duty.end!).duration.inMinutes >
-        maxdutyrecrest.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.restrecurrent,
-          legalCauseMsg:
-              "Before duty, need ${minrecrest.inHours}h rest including 2 local nights. from: ${rest.end.format(pattern: "ddMMMyy HH:mm")} ${DTInterval(rest.end, duty.end!).duration.tohhmm}/${maxdutyrecrest.tohhmm} "));
-    }
-
-    //   48h inc 2 local days
-
-    final startmonth = changeTz(duty.start!.startOf(Unit.month), base);
-    final endmonth = startmonth.endOf(Unit.month);
-    if (duty.interval.isOverlap(
-        DTInterval(endmonth.subtract(days: 4).add(minutes: 1), endmonth))) {
-      int nb48inmonth = 0;
-      List<FtlDuty> dutiesmonth = duties
-          .where((e) => DTInterval(startmonth, endmonth)
-              .isOverlap(DTInterval(e.start!, e.end!)))
-          .toList();
-
-      List<DTInterval> restmonth = DTInterval(startmonth, endmonth).minusmany(
-          dutiesmonth
-              .map((e) => DTInterval(changeTz(e.start!, e.placeStart!),
-                  changeTz(e.end!, e.placeStart!)))
-              .toList());
-      // print(restmonth);
-
-      while (restmonth.isNotEmpty) {
-        final e = restmonth.removeAt(0);
-
-        final localdays = DTInterval.fromHm(
-            apartir: e.start,
-            h: 0,
-            m: 0,
-            duration: const Duration(hours: 47, minutes: 59));
-        if (e.contains(localdays)) {
-          nb48inmonth++;
-          // print(
-          //     "2localdays: ${localdays.start.format(pattern: "ddMMMyy HH:mm")} ${localdays.end.format(pattern: "ddMMMyy HH:mm")}");
-          // print(
-          //     "in rest ${e.start.format(pattern: "ddMMMyy HH:mm")} ${e.end.format(pattern: "ddMMMyy HH:mm")}");
-          restmonth = [...e.minus(localdays), ...restmonth];
-        }
-      }
-
-      if (nb48inmonth == 0) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      } else if (nb48inmonth == 1 &&
-          DTInterval(endmonth.subtract(days: 2).add(minutes: 1), endmonth)
-              .isOverlap(duty.interval)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      } else if (nb48inmonth == 1 &&
-          DTInterval(endmonth.subtract(days: 4).add(minutes: 1),
-                  endmonth.subtract(days: 2))
-              .isOverlap(duty.interval) &&
-          DTInterval(endmonth.subtract(days: 4).add(minutes: 1),
-                  endmonth.subtract(days: 2))
-              .intersectionmany(
-                  [...dutiesAsInterval, ...stdbyAsInterval]).isEmpty) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      }
-    }
-    // disruptive
-    duty.lateFinish = _isLateFinish(duty);
-    duty.earlyStart = _isEarlyStart(duty);
-    duty.nightDuty = _isNightDuty(duty);
-    if (duty.fdpStart != null &&
-        lastduty != null &&
-        base == lastduty.placeEnd &&
-        (_isLateFinish(lastduty) || _isNightDuty(lastduty)) &&
-        _isEarlyStart(duty)) {
-      // log("ftl: found late finish or nighty <${duty.start!.format(pattern: "ddMMMyy HH:mm")}");
-      if (!DTInterval(lastduty.end!, duty.start!).contains(DTInterval.fromHm(
-          apartir: changeTz(lastduty.end!, lastduty.placeEnd!),
-          h: 23,
-          m: 0,
-          duration: const Duration(hours: 7, minutes: 59)))) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            legalCauseMsg:
-                "Disruptive duty; one local night of rest is required before early departure."));
-      }
-    }
-
-    //consecutive night duty
-    if (_isConsecutiveNight(duty, lastduty)) {
-      var i = index;
-      final monthint = DTInterval(
-          changeTz(duty.start!.startOf(Unit.month), base),
-          changeTz(duty.start!.endOf(Unit.month), base));
-      int nbconsnight = 0;
-      while (i > 0 && duties[i].interval.isOverlap(monthint)) {
-        if (_isConsecutiveNight(duties[i], duties[i - 1])) {
-          nbconsnight++;
-        }
-        i--;
-      }
-      if (nbconsnight > 1) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            legalCauseMsg:
-                "Consecutive nights is allowed only once per civil month."));
-      } else {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            condition:
-                "Two consecutive night duties; crew member agreement is required.",
-            legalCauseMsg: ""));
-      }
-    }
-
-    //local day rest if night duty
-    if (lastduty != null && _isNightDuty(lastduty)) {
-      if (DTInterval.fromHm(
-              apartir: changeTz(lastduty.end!, lastduty.placeEnd!),
-              h: 0,
-              m: 0,
-              duration: const Duration(hours: 23, minutes: 59))
-          .isOverlap(duty.interval)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            condition: "You can request a local day off after last night duty.",
-            legalCauseMsg: ""));
-      }
-    }
-
-    // if (duty.legals.isNotEmpty) {
-    //   log("${duty.legals.map((e) => e.legalCauseMsg)}");
-    // }
-    // duties[index] = duty;
-  }
-
-  bool _isConsecutiveNight(FtlDuty duty, FtlDuty? lastduty) =>
-      _isNightDuty(duty) &&
-      lastduty != null &&
-      DTInterval.fromHm(
-              apartir: changeTz(lastduty.end!, lastduty.placeEnd!),
-              h: 2,
-              m: 0,
-              duration: const Duration(hours: 2, minutes: 59))
-          .isOverlap(lastduty.interval);
-
-  FtlDuty? _addDutyDetail(
-      {required int index, required FtlDuty duty, Jiffy? checkin}) {
-    final one = dutiesDetails[index];
-    if (_fdpList.contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeEnd;
-
-      //duty.start = duty.start ?? _calcPreflight(one).latest(checkin);
-      duty.start = duty.start ?? checkin ?? _calcPreflight(one);
-
-      duty.end = _calcPostflight(one);
-      if (one.type == FtlDutyDetailsType.flight) {
-        duty.type = FtlDutyType.fdp;
-        duty.sectors++;
-        duty.fdpStart = duty.start;
-        duty.fdpEnd = one.end;
-      } else {
-        duty.type = duty.type ?? FtlDutyType.duty;
-      }
-      duty.dutiesDetailsIndex.add(index);
-    } else if ([FtlDutyDetailsType.standby, FtlDutyDetailsType.reserve]
-        .contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeStart;
-      duty.start = duty.start ?? _calcPreflight(one);
-      duty.end = one.end;
-      duty.type = FtlDutyType.other;
-      duty.dutiesDetailsIndex.add(index);
-    } else if ([FtlDutyDetailsType.ground, FtlDutyDetailsType.sim]
-        .contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeStart;
-      duty.start = duty.start ?? _calcPreflight(one);
-      duty.end = one.end;
-      duty.type = duty.type ?? FtlDutyType.duty;
-      duty.dutiesDetailsIndex.add(index);
-    } else {
-      return null;
-    }
-    return duty;
-  }
-
-  static bool _isEarlyStart(FtlDuty x) {
-//500 559
-    // print(
-    //     "$x is earlystart: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 5, m: 0, duration: const Duration(minutes: 59)).include(x.start!)}");
-    return (x.fdpStart != null &&
-        DTInterval.fromHm(
-                apartir: changeTz(x.start!.subtract(hours: 24), x.placeStart!),
-                h: 5,
-                m: 0,
-                duration: const Duration(minutes: 59))
-            .include(x.start!));
-  }
-
-  static bool _isLateFinish(FtlDuty x) {
-//2300  159
-    // print(
-    //     "$x is latefinish: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 23, m: 0, duration: const Duration(hours: 2, minutes: 59)).include(x.end!)}");
-    return (x.type != FtlDutyType.other) &&
-        (DTInterval.fromHm(
-                apartir: changeTz(x.start!, x.placeStart!),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 2, minutes: 59))
-            .include(x.end!));
-  }
-
-  static bool _isNightDuty(FtlDuty x) {
-//200  459
-    // print(
-    //     "$x is Night duty: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 2, m: 0, duration: const Duration(hours: 2, minutes: 59)).include(x.end!)}");
-    return (x.type != FtlDutyType.other) &&
-        (DTInterval.fromHm(
-                apartir: changeTz(x.start!, x.placeStart!),
-                h: 2,
-                m: 0,
-                duration: const Duration(hours: 2, minutes: 59)))
-            .isOverlap(x.interval);
-  }
-
-  Duration tzDiff(String iata1, String iata2, DateTime sourceDateTime) {
-    // print(Airports.instance.find(iata1)!.timezoneid);
-    // print(Airports.instance.find(iata2)!.timezoneid);
-    final iata1Location = tz.getLocation(Airports.find(iata1)!.timezoneid);
-    final iata2Location = tz.getLocation(Airports.find(iata2)!.timezoneid);
-    tz.TZDateTime iata1TZDateTime =
-        tz.TZDateTime.from(sourceDateTime, iata1Location);
-    tz.TZDateTime iata2TZDateTime =
-        tz.TZDateTime.from(sourceDateTime, iata2Location);
-    return Duration(
-        minutes: (iata2TZDateTime.timeZoneOffset.inMinutes -
-                iata1TZDateTime.timeZoneOffset.inMinutes)
-            .abs());
-  }
-
-  String _acclimatized(
-      {required Duration tzoffset, required Duration timeElapsed}) {
-    if (tzoffset.inHours <= 2) {
-      return "D";
-    } else if (timeElapsed.inHours < 48) {
-      return "B";
-    } else if (tzoffset.inHours < 4 && timeElapsed.inHours >= 48) {
-      return "D";
-    } else if (tzoffset.inHours <= 6 && timeElapsed.inHours >= 72) {
-      return "D";
-    } else if (tzoffset.inHours <= 9 && timeElapsed.inHours >= 96) {
-      return "D";
-    } else if (tzoffset.inHours <= 12 && timeElapsed.inHours >= 120) {
-      return "D";
-    } else {
-      return "X";
-    }
-  }
-
-  static Jiffy changeTz(Jiffy jiffy, String iata) {
-    return Jiffy.parseFromDateTime(tz.TZDateTime.from(jiffy.dateTime,
-        tz.getLocation(Airports.find(iata)?.timezoneid ?? "UTC")));
-  }
-
-  Duration _fdpMax(
-      {required reftime,
-      String? iata,
-      required int sectors,
-      required Map<String, List<String>> tab}) {
-    Jiffy reftjiffy = Jiffy.now();
-    String reft = "";
-
-    if (reftime is Jiffy && iata != null) {
-      reftjiffy = reftime;
-      reftjiffy = changeTz(reftjiffy, iata);
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else if (reftime is DateTime && iata != null) {
-      reftjiffy = Jiffy.parseFromDateTime(reftime);
-      reftjiffy = changeTz(reftjiffy, iata);
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else if (reftime is String && reftime.length == 4) {
-      reft = reftime;
-    } else if (reftime is String && iata != null) {
-      reftjiffy = Jiffy.parse(reftime);
-      reftjiffy = changeTz(reftjiffy, iata);
-
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else {
-      throw ("_fdpMax type of reftime unrecognized!!!");
-    }
-    // print("$iata  $reft ${reftjiffy.toUtc().Hm}");
-    for (String key in tab.keys) {
-      List<String> intervalle = key.split("-");
-      int cmph1 = reft.compareTo(intervalle[0]);
-      int cmph2 = reft.compareTo(intervalle[1]);
-
-      bool inint = (intervalle[0].compareTo(intervalle[1]) < 0)
-          ? (cmph1 >= 0 && cmph2 <= 0)
-          : ((cmph1 >= 0 || cmph2 <= 0));
-      if (inint) {
-        final List<String>? lres = tab[key];
-        final int nrow = ((sectors == 1) ? 2 : sectors) - 2;
-        final String? res =
-            (lres != null && nrow < lres.length) ? lres[nrow] : null;
-        if (res != null && res != "Not allowed") {
-          return Duration(
-              hours: int.parse(res.split(".")[0]),
-              minutes: int.parse(res.split(".")[1]));
-        }
-      }
-    }
-    return Duration.zero;
-  }
-
-  Duration fdpMaxBasic(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(reftime: reftime, iata: iata, sectors: sectors, tab: _fdpMaxTab);
-
-  Duration fdpMaxExtBasic(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(
-          reftime: reftime, iata: iata, sectors: sectors, tab: _fdpMaxExtTab);
-
-  Duration fdpMaxUnk({required reftime, String? iata, required int sectors}) =>
-      _fdpMax(reftime: reftime, iata: iata, sectors: sectors, tab: _fdpUnkTab);
-
-  Duration fdpMaxUnkFrms(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(
-          reftime: reftime, iata: iata, sectors: sectors, tab: _fdpUnkFrmsTab);
-
-//acclim
-
-  final Map<String, List<String>> _fdpMaxTab = {
-    "0600-1329": [
-      "13.00",
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-    ],
-    "1330-1359": [
-      "12.45",
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-    ],
-    "1400-1429": [
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-    ],
-    "1430-1459": [
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-    ],
-    "1500-1529": [
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1530-1559": [
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1600-1629": [
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1630-1659": [
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1700-0459": [
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "0500-0514": [
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "0515-0529": [
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-    ],
-    "0530-0544": [
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-    ],
-    "0545-0559": [
-      "12.45",
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-    ],
-  };
-  final Map<String, List<String>> _fdpMaxExtTab = {
-    "0600-0614": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0615-0629": [
-      "13.15",
-      "12.45",
-      "12.15",
-      "11.45",
-    ],
-    "0630-0644": [
-      "13.30",
-      "13.00",
-      "12.30",
-      "12.00",
-    ],
-    "0645-0659": [
-      "13.45",
-      "13.15",
-      "12.45",
-      "12.15",
-    ],
-    "0700-1329": [
-      "14.00",
-      "13.30",
-      "13.00",
-      "12.30",
-    ],
-    "1330-1359": [
-      "13.45",
-      "13.15",
-      "12.45",
-      "Not allowed",
-    ],
-    "1400-1429": [
-      "13.30",
-      "13.00",
-      "12.30",
-      "Not allowed",
-    ],
-    "1430-1459": [
-      "13.15",
-      "12.45",
-      "12.15",
-      "Not allowed",
-    ],
-    "1500-1529": [
-      "13.00",
-      "12.30",
-      "12.00",
-      "Not allowed",
-    ],
-    "1530-1559": [
-      "12.45",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1600-1629": [
-      "12.30",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1630-1659": [
-      "12.15",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1700-1729": [
-      "12.00",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1730-1759": [
-      "11.45",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1800-1829": [
-      "11.30",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1830-1859": [
-      "11.15",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1900-0359": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0400-0414": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0415-0429": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0430-0444": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0445-0459": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0500-0514": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0515-0529": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0530-0544": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0545-0559": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ]
-  };
-  final Map<String, List<String>> _fdpUnkTab = {
-    "0000-2359": ["11.00", "10:30", "10.00", "09.30", "09.00", "09.00", "09.00"]
-  };
-  final Map<String, List<String>> _fdpUnkFrmsTab = {
-    "0000-2359": ["12.00", "11.30", "11.00", "10.30", "10.00", "09.30", "09.00"]
-  };
-}
-
-class FtlDuty {
-  FtlDuty({this.start, this.end, this.placeStart, this.placeEnd, this.type});
-  @override
-  String toString() {
-    return "${start?.yMEd} ${start?.Hm} >>> ${end?.Hm} : ${fdpLength.inMinutes > 0 ? "FDP" : "DUTY"} ${dutiesDetailsIndex.length}leg(s)";
-  }
-
-  Jiffy? start;
-  Jiffy? end;
-  DTInterval get interval => DTInterval(start!, end!);
-  String? placeStart;
-  String? placeEnd;
-  FtlDutyType? type;
-  List<int> dutiesDetailsIndex = [];
-  Jiffy? fdpStart;
-  Jiffy? fdpEnd;
-  int sectors = 0;
-  Duration? fdpMax;
-  Duration? fdpExtMax;
-  //Duration? fdpIfRExtMax;//if inflight rest rest
-
-  bool fdpExt = false;
-  List<FtlLegal> legals = [];
-
-  Duration get dutyLength => (start != null && end != null)
-      ? end!.dateTime.difference(start!.dateTime)
-      : Duration.zero;
-  Duration get fdpLength => (fdpStart != null && fdpEnd != null)
-      ? fdpEnd!.dateTime.difference(fdpStart!.dateTime)
-      : Duration.zero;
-
-  // Duration? get rest => (dutyLength.max(Ftl.minimumrest(placeEnd)));
-  Jiffy? restends;
-
-  String? acclim;
-  String? reftime;
-
-  FtlDutyTotal? dutyTotal;
-
-  //Jiffy? report;
-  Jiffy? reportdelay1;
-  Jiffy? notification1;
-  Jiffy? reportdelay2;
-  Jiffy? notification2;
-  bool earlyStart = false;
-  bool lateFinish = false;
-  bool nightDuty = false;
-}
-
-class FtlLegal {
-  FtlLegal(
-      {required this.legalCause,
-      required this.legalCauseMsg,
-      this.legalIndex,
-      this.condition});
-  FtlLegalCause legalCause;
-  String legalCauseMsg;
-  int? legalIndex;
-  String? condition;
-}
-
-enum FtlDutyType { duty, fdp, other }
-
-class FtlDutyDetails {
-  FtlDutyDetails({
-    this.start,
-    this.end,
-    this.placeStart,
-    this.placeEnd,
-    this.type,
-    this.label,
-  });
-
-  Jiffy? start;
-  Jiffy? end;
-  DTInterval get interval => DTInterval(start!, end!);
-
-  Duration get duration => end!.dateTime.difference(start!.dateTime);
-  String? placeStart;
-  String? placeEnd;
-  FtlDutyDetailsType? type;
-  String get typeString {
-    switch (type) {
-      case FtlDutyDetailsType.flight:
-        return "FLT";
-      case FtlDutyDetailsType.dhflight:
-        return "DH-FLT";
-      case FtlDutyDetailsType.dhlimo:
-        return "DH-LIMO";
-      case FtlDutyDetailsType.sim:
-        return "SIM";
-      case FtlDutyDetailsType.standby:
-        return "STBY";
-      case FtlDutyDetailsType.reserve:
-        return "RSRV";
-      case FtlDutyDetailsType.ground:
-        return "GRND";
-
-      default:
-        return "UNK";
-    }
-  }
-
-  String? label;
-}
-
-enum FtlDutyDetailsType {
-  preflight,
-  flight,
-  postflight,
-  dhflight,
-  dhlimo,
-  ground,
-  standby,
-  reserve,
-  sim,
-//  training,
-//  other
-}
-
-class FtlDutyTotal {
-  FtlDutyTotal(
-      {required this.date, required this.dutyLength, required this.fltLength});
-  Jiffy date;
-  Duration dutyLength;
-  Duration fltLength;
-  Duration? dutylast7;
-  Duration? dutylast14;
-  Duration? dutylast28;
-  Duration? fltlast28;
-  Duration? fltyear;
-  Duration? fltlast12;
-}
-
-enum FtlLegalCause {
-  dutylast7,
-  dutylast14,
-  dutylast28,
-  fltlast28,
-  fltyear,
-  fltlast12,
-  fdpmax,
-  restfdp,
-  restrecurrent,
-  disruptive
-  //check duty length && flt length
-
-  //check fdp leength
-
-  //check rest before fdp
-  //check recurrent rest
-  //check disruptive sched
-}

+ 0 - 1467
lib/ftl/provider/ftl copy2.dart.bak

@@ -1,1467 +0,0 @@
-import 'dart:developer';
-
-import 'package:collection/collection.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:tp5/core/core.dart';
-import 'package:tp5/providers/airports.dart';
-import 'package:tp5/roster/models/duty.dart';
-
-import 'package:timezone/timezone.dart' as tz;
-
-class Ftl {
-  Duration minimumrest(String? station) =>
-      Duration(hours: station == base ? 12 : 12, minutes: 0, seconds: 0);
-  static Duration postflight = const Duration(minutes: 30);
-  static Duration preflight = const Duration(minutes: 60);
-  static Duration maxdutylast7 = const Duration(hours: 60);
-  static Duration maxdutylast14 = const Duration(hours: 110);
-  static Duration maxdutylast28 = const Duration(hours: 190);
-  static Duration maxfltlast28 = const Duration(hours: 100);
-  static Duration maxfltlastyear = const Duration(hours: 900);
-  static Duration maxfltlast12 = const Duration(hours: 1000);
-  Duration travelling(String station) {
-    if (base == station) return Duration.zero;
-    switch (station) {
-      case "DSS":
-        return const Duration(minutes: 60);
-      case "ORY":
-        return const Duration(minutes: 5);
-      default:
-        return const Duration(minutes: 30);
-    }
-  }
-
-  String base;
-
-  List<FtlDutyDetails> dutiesDetails = [];
-  List<Duty> clDuties = [];
-  List<FtlDuty> duties = [];
-
-  // List<FtlDutyTotal> dutiesLength = [];
-
-  List<DTInterval> get dutiesAsInterval => duties
-      .map((e) =>
-          (e.type != FtlDutyType.other) ? DTInterval(e.start!, e.end!) : null)
-      .whereNotNull()
-      .toList();
-  List<DTInterval> get stdbyAsInterval => dutiesDetails
-      .map((e) => (e.type == FtlDutyDetailsType.standby)
-          ? DTInterval(e.start!, e.end!)
-          : null)
-      .whereNotNull()
-      .toList();
-  List<DTInterval> get fltsAsInterval => dutiesDetails
-      .map((e) => (e.type == FtlDutyDetailsType.flight)
-          ? DTInterval(e.start!, e.end!)
-          : null)
-      .whereNotNull()
-      .toList();
-  bool frms;
-  Ftl({required this.dutiesDetails, required this.base, this.frms = false});
-  Ftl.fromCrewlink(
-      {required this.clDuties, required this.base, this.frms = false}) {
-    for (Duty one in clDuties) {
-      switch (one.type) {
-        case "flight":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.flight,
-              label: one.data["label"],
-            ),
-          );
-        case "dhflight":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.dhflight,
-              label: one.data["label"],
-            ),
-          );
-        case "dhlimo":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.dhlimo,
-              label: one.data["label"],
-            ),
-          );
-        case "ground":
-          if (["SBY1", "SBY2", "SBY3"].contains(one.data["label"])) {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.standby,
-                label: one.data["label"],
-              ),
-            );
-          } else if (["R0"].contains(one.data["label"])) {
-            //reserve is not duty
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.reserve,
-                label: one.data["label"],
-              ),
-            );
-          } else if ((one.data["actype"] ?? "") != "") {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.sim,
-                label: one.data["label"],
-              ),
-            );
-          } else if (one.start != null &&
-              one.end != null &&
-              one.end!.diff(one.start!, unit: Unit.hour).abs() < 12) {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.ground,
-                label: one.data["label"],
-              ),
-            );
-          } else {
-            // print("ftl: constr: unknown ${one.date} ${one.type} ${one.data}");
-          }
-        case "checkin":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              // placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.preflight,
-            ),
-          );
-
-        case "checkout":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              // placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.postflight,
-            ),
-          );
-        case "credit":
-        case "wholeday":
-          break;
-        default:
-        // print("ftl: unk: ${one.date} ${one.type} ${one.data}");
-      }
-    }
-  }
-
-  Jiffy? _calcPostflight(FtlDutyDetails xduty) {
-    if (xduty.end != null &&
-        [FtlDutyDetailsType.flight, FtlDutyDetailsType.dhflight]
-            .contains(xduty.type)) {
-      return xduty.end!.addDuration(postflight);
-    } else {
-      return xduty.end;
-    }
-  }
-
-  Jiffy? _calcPreflight(FtlDutyDetails xduty) {
-    if (xduty.start != null &&
-        [
-          FtlDutyDetailsType.flight,
-          FtlDutyDetailsType.dhflight,
-          FtlDutyDetailsType.dhlimo,
-          FtlDutyDetailsType.sim,
-        ].contains(xduty.type)) {
-      return (base == (xduty.placeStart ?? ""))
-          ? xduty.start!.subtractDuration(const Duration(minutes: 60))
-          : (xduty.start!.subtractDuration(preflight));
-    } else {
-      return xduty.start;
-    }
-  }
-
-  final List<FtlDutyDetailsType> _fdpList = [
-    FtlDutyDetailsType.flight,
-    FtlDutyDetailsType.dhflight,
-    FtlDutyDetailsType.dhlimo
-  ];
-
-  //calcul duties
-  calcduties({Jiffy? date}) {
-    log("FTL: start calcduties");
-    duties.clear();
-
-    final t1 = Jiffy.now();
-    _calcDuty();
-
-    log("FTL: start _calcfdpmax");
-    _calcfdpmax();
-
-    log("FTL: start _clacdutytotal");
-    // _calcDutyTotal();
-
-    log("FTL: start calclegal");
-    _calcLegal(date: date);
-
-    final t4 = Jiffy.now();
-    print(
-        "ftl: calcduties calculation :  ${t4.diff(t1, unit: Unit.second, asFloat: true)} ms");
-
-    log("FTL: finish calcduties");
-
-    // return [duties, dutiesDetails, dutiesLength];
-    return [duties, dutiesDetails];
-  }
-
-  _calcDuty() {
-    for (int i = 0; i < dutiesDetails.length; i++) {
-      var last = i > 0 ? dutiesDetails[i - 1] : null;
-
-      final checkin = ((last?.type == FtlDutyDetailsType.preflight)
-          ? dutiesDetails[i - 1].start
-          : null);
-
-      final newduty =
-          _addDutyDetail(index: i, duty: FtlDuty(), checkin: checkin);
-      //print("${dutiesDetails[i].type} $newduty");
-      if (newduty != null) {
-        if (duties.isEmpty) {
-          //first duty
-          duties.add(newduty);
-        } else if ((newduty.start!.isAfter(duties.last.end!)) &&
-            (duties.last.type == FtlDutyType.other ||
-                newduty.type == FtlDutyType.other)) {
-          //last and new are not duty nor fdp (other=>stdby or rsrv)
-          duties.add(newduty);
-        } else if ((newduty.start!
-                .subtractDuration(travelling(newduty.placeStart ?? base))
-                .isAfter(
-                  duties.last.end!
-                      .addDuration(travelling(duties.last.placeEnd ?? base)),
-                )) &&
-            // duties.last.type == FtlDutyType.duty &&
-            newduty.type == FtlDutyType.duty) {
-          //last is duty
-          duties.add(newduty);
-        } else if (newduty.start!.diff(duties.last.end!, unit: Unit.minute) <
-            minimumrest(duties.last.placeEnd).inMinutes) {
-          //diff < minimumrest
-          //ilhim
-          final mergedduty = _addDutyDetail(
-              index: i,
-              duty: duties.isNotEmpty ? duties.last : FtlDuty(),
-              checkin: checkin);
-          duties[duties.length - 1] = mergedduty!;
-        } else {
-          //jdida
-          duties.add(newduty);
-        }
-      }
-    }
-  }
-
-  _calcfdpmax() {
-    for (var i = 0; i < duties.length; i++) {
-      FtlDuty duty = duties[i];
-      FtlDuty? lastduty = i == 0 ? null : duties[i - 1];
-      if (duty.type == FtlDutyType.fdp) {
-        String acclim = _acclimatized(
-            tzoffset: tzDiff(duty.placeStart!, lastduty?.placeEnd ?? base,
-                duty.start!.dateTime),
-            timeElapsed:
-                lastduty?.end!.dateTime.difference(duty.start!.dateTime) ??
-                    const Duration());
-        duties[i].acclim = acclim;
-        duties[i].reftime = changeTz(duty.start!, duty.placeStart ?? base).Hm;
-
-        Jiffy reftime = duty.start!;
-        if (duty.reportdelay2 != null && duty.reportdelay1 != null) {
-          if (duty.start!.dateTime
-                  .difference(duty.reportdelay2!.dateTime)
-                  .inMinutes <
-              (4 * 60)) {
-            reftime = duty.start!;
-            duty.start =
-                duty.notification2!.add(hours: 1).min(duty.reportdelay1!);
-          } else {
-            reftime = duty.reportdelay2!;
-            duty.start = duty.reportdelay2!;
-          }
-        } else if (duty.reportdelay1 != null) {
-          if (duty.start!.dateTime
-                  .difference(duty.reportdelay1!.dateTime)
-                  .inMinutes <
-              (4 * 60)) {
-            reftime = duty.start!;
-            duty.start = duty.reportdelay1!;
-          } else {
-            reftime = duty.reportdelay1!;
-            duty.start = duty.reportdelay1!;
-          }
-        }
-
-        switch (acclim) {
-          case "D":
-            // print("${duty.start?.yMMMd} ${duty.start?.toUtc().Hm}");
-            duties[i].fdpMax = fdpMaxBasic(
-                reftime: reftime, iata: duty.placeStart, sectors: duty.sectors);
-            duties[i].fdpExtMax = fdpMaxExtBasic(
-                reftime: reftime, iata: duty.placeStart, sectors: duty.sectors);
-          case "B":
-            duties[i].fdpMax = fdpMaxBasic(
-                reftime: reftime,
-                iata: lastduty?.placeEnd ?? lastduty?.placeStart ?? base,
-                sectors: duty.sectors);
-            duties[i].fdpExtMax = fdpMaxExtBasic(
-                reftime: reftime,
-                iata: lastduty?.placeEnd ?? lastduty?.placeStart ?? base,
-                sectors: duty.sectors);
-          case "X":
-            if (frms) {
-              duties[i].fdpMax = fdpMaxUnk(
-                  reftime: reftime,
-                  iata: duty.placeStart,
-                  sectors: duty.sectors);
-            } else {
-              duties[i].fdpMax = fdpMaxUnkFrms(
-                  reftime: reftime,
-                  iata: duty.placeStart,
-                  sectors: duty.sectors);
-            }
-            break;
-          default:
-        }
-      }
-    }
-  }
-
-  _calcLegal({Jiffy? date}) {
-    if (date == null) {
-      for (var i = 0; i < duties.length; i++) {
-        _checklegal(index: i);
-      }
-    } else {
-      duties.forEachIndexed((i, e) {
-        if (duties[i]
-            .start!
-            .isSameOrAfter(date.startOf(Unit.day).subtract(days: 1))) {
-          _checklegal(index: i);
-        }
-      });
-    }
-  }
-
-  Duration _sumDuration(List<DTInterval> x) =>
-      Duration(milliseconds: x.map((e) => e.duration.inMilliseconds).sum);
-
-  List<DTInterval> breaks(FtlDuty duty) {
-    List<DTInterval> out = [];
-    for (var e in duty.dutiesDetailsIndex) {
-      final dutydetail = dutiesDetails[e];
-      final deptravel = (base == (dutydetail.placeStart ?? ""))
-          ? Duration.zero
-          : travelling(dutydetail.placeStart ?? "");
-      final destravel = (base == (dutydetail.placeEnd ?? ""))
-          ? Duration.zero
-          : travelling(dutydetail.placeEnd ?? dutydetail.placeStart ?? "");
-      final start = _calcPreflight(dutydetail)!.subtractDuration(deptravel);
-      final finish = _calcPostflight(dutydetail)!.addDuration(destravel);
-      if (finish.isAfter(start)) {
-        out.add(DTInterval(start, finish));
-      }
-    }
-    return duty.interval.minusmany(out);
-  }
-
-  _checklegal({required int index}) {
-    FtlDuty duty = duties[index];
-
-    final date = changeTz(duty.start!, base).endOf(Unit.day);
-
-    // log("ftl: dutylenght date=${date.format(pattern: "ddMMMyy HHmm")} \n date-7=${date.subtract(days: 7 - 1).startOf(Unit.day).format(pattern: "ddMMMyy HHmm")}");
-    // print("${date.yMEd}");
-    final dutyLength = FtlDutyTotal(
-        date: date, dutyLength: Duration.zero, fltLength: Duration.zero)
-      ..dutylast7 = _sumDuration(
-              DTInterval(date.subtract(days: 7 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(
-                  DTInterval(date.subtract(days: 7 - 1).startOf(Unit.day), date)
-                      .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..dutylast14 = _sumDuration(
-              DTInterval(date.subtract(days: 14 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(DTInterval(
-                      date.subtract(days: 14 - 1).startOf(Unit.day), date)
-                  .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..dutylast28 = _sumDuration(
-              DTInterval(date.subtract(days: 28 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(DTInterval(
-                      date.subtract(days: 28 - 1).startOf(Unit.day), date)
-                  .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..fltlast28 = _sumDuration(
-          DTInterval(date.subtract(days: 28 - 1).startOf(Unit.day), date)
-              .intersectionmany(fltsAsInterval))
-      ..fltlast12 = _sumDuration(DTInterval(
-              date.endOf(Unit.month).subtract(months: 12).startOf(Unit.month),
-              date)
-          .intersectionmany(fltsAsInterval))
-      ..fltyear = _sumDuration(DTInterval(date.startOf(Unit.year), date)
-          .intersectionmany(fltsAsInterval));
-    duty.dutyTotal = dutyLength;
-    // print("${date.yMEd} ${dutyLength.fltyear?.tohhmm}");
-
-    // dutylast7,
-    if ((dutyLength.dutylast7?.inMinutes ?? 0) > maxdutylast7.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast7,
-          legalCauseMsg:
-              "Max duty in 7 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast7?.tohhmm} / ${maxdutylast7.inHours}h"));
-    }
-    // dutylast14,
-    if ((dutyLength.dutylast14?.inMinutes ?? 0) > maxdutylast14.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast14,
-          legalCauseMsg:
-              "Max duty in 14 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast14?.tohhmm} / ${maxdutylast14.inHours}h"));
-    }
-    // dutylast28,
-    if ((dutyLength.dutylast28?.inMinutes ?? 0) > maxdutylast28.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast28,
-          legalCauseMsg:
-              "Max duty in 28 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast28?.tohhmm} / ${maxdutylast28.inHours}h"));
-    }
-    // fltlast28,
-    if ((dutyLength.fltlast28?.inMinutes ?? 0) > maxfltlast28.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltlast28,
-          legalCauseMsg:
-              "Max flight hours in 28 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.fltlast28?.tohhmm} / ${maxfltlast28.inHours}h"));
-    }
-
-    // fltyear,
-    if ((dutyLength.fltyear?.inMinutes ?? 0) > maxfltlastyear.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltyear,
-          legalCauseMsg:
-              "Max flight hours in calendar year ${duty.start?.format(pattern: "yyyy")} exceeded: ${dutyLength.fltyear?.tohhmm} / ${maxfltlastyear.inHours}h"));
-    }
-    // fltlast12,
-    if ((dutyLength.fltlast12?.inMinutes ?? 0) > maxfltlast12.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltlast12,
-          legalCauseMsg:
-              "Max flight hours in 12 months ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.fltlast12?.tohhmm} / ${maxfltlast12.inHours}h"));
-    }
-
-    // fdpmax,
-    if (duty.type == FtlDutyType.fdp && duty.fdpMax != null) {
-      if (duty.fdpLength.inMinutes <= duty.fdpMax!.inMinutes) {
-      } else if (duty.fdpExtMax != null &&
-          duty.fdpLength.inMinutes <= duty.fdpExtMax!.inMinutes) {
-        int nbFdpExt = 0;
-        for (var i = index;
-            i >= 0 &&
-                DTInterval(
-                        changeTz(duty.start!, base)
-                            .startOf(Unit.day)
-                            .subtract(days: 7),
-                        changeTz(duty.end!, base))
-                    .isOverlap(DTInterval(duties[i].start!, duties[i].end!));
-            i--) {
-          if (duties[i].fdpExt) nbFdpExt++;
-        }
-
-        if (nbFdpExt < 2) {
-          duty.fdpExt = true;
-          duties[index] = duty;
-        } else {
-          //nbext more than2 in 7days
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              legalCauseMsg:
-                  "FDP Ext used more than twice in 7 days. ${duty.fdpLength.tohhmm} / ${duty.fdpMax?.tohhmm} / ext${duty.fdpExtMax?.tohhmm}"));
-        }
-      } else if (breaks(duty).any((e) => (e.duration.inHours > 3)
-          //&&
-          // ((duty.fdpLength.inMinutes) <=
-          //     (e.duration
-          //         .multiply(0.5)
-          //         .add(duty.fdpMax ?? Duration.zero)
-          //         .inMinutes)))) {
-          )) {
-        //split duty check
-        final fdpmaxbreak = breaks(duty)
-            .map((e) => ((e.duration.inHours > 3)
-                ? ((e.duration.multiply(0.5).add(duty.fdpMax ?? Duration.zero)))
-                : null))
-            .whereNotNull();
-        if (fdpmaxbreak.isNotEmpty && duty.fdpLength < fdpmaxbreak.first) {
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              condition:
-                  "A break on ground must be considered to extend FDP Max to ${fdpmaxbreak.first.tohhmm}, ",
-              legalCauseMsg: "FDP is: ${duty.fdpLength.tohhmm}"));
-        } else {
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              legalCauseMsg:
-                  "FDP Max is excedeed even with ground break of ${breaks(duty).map((e) => ((e.duration.inHours > 3) ? (e.duration) : null)).whereNotNull().first.tohhmm}.  FDP:${duty.fdpLength.tohhmm}/Max:${fdpmaxbreak.first.tohhmm}"));
-        }
-      } else {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.fdpmax,
-            legalCauseMsg:
-                "FDP is ${duty.fdpLength.tohhmm}/Max:${duty.fdpMax?.tohhmm}"));
-      }
-    }
-    // restfdp without ext,
-    final FtlDuty? lastduty = (index > 0) ? duties[index - 1] : null;
-    // log("ftl: checking duty <${duty}> lastduty ended <${lastduty}>");
-
-    if (lastduty != null &&
-        duty.type == FtlDutyType.fdp &&
-        (lastduty.type == FtlDutyType.fdp ||
-            lastduty.type == FtlDutyType.duty ||
-            lastduty.dutiesDetailsIndex.any(
-                (e) => dutiesDetails[e].type == FtlDutyDetailsType.standby))) {
-      final rest = minimumrest(lastduty.placeEnd)
-          .max(duty.end!.dateTime.difference(duty.start!.dateTime));
-      duties[index - 1].restends = lastduty.end!.addDuration(rest);
-
-      if (lastduty.restends!.isAfter(duty.start!)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restfdp,
-            legalCauseMsg:
-                "Need more rest before starting FDP. rest: ${duty.start!.dateTime.difference(lastduty.end!.dateTime).tohhmm} / ${rest.tohhmm}"));
-      }
-    }
-    // restfdp with ext,
-    duty = duties[index];
-    FtlDuty? nextduty = (index < duties.length - 1) ? duties[index + 1] : null;
-    if (duty.fdpExt) {
-      final restbefore = (lastduty == null)
-          ? null
-          : minimumrest(lastduty.placeEnd)
-              .max(lastduty.end!.dateTime.difference(lastduty.start!.dateTime));
-      final restafter = (nextduty == null)
-          ? null
-          : minimumrest(duty.placeEnd)
-              .max(duty.end!.dateTime.difference(duty.start!.dateTime));
-//+2h rest before && 2h rest after
-      if ((lastduty == null ||
-              duty.start!.dateTime
-                      .difference(lastduty.end!.dateTime)
-                      .inMinutes >=
-                  (restbefore?.inMinutes ?? 0) + (2 * 60)) &&
-          (nextduty == null ||
-              nextduty.start!.dateTime
-                      .difference(duty.end!.dateTime)
-                      .inMinutes >=
-                  (restafter?.inMinutes ?? 0) + (60 * 2))) {
-      }
-//+4h rest after
-      else if ((nextduty == null ||
-          nextduty.start!.dateTime.difference(duty.end!.dateTime).inMinutes >=
-              (restafter?.inMinutes ?? 0) + (60 * 4))) {
-      }
-//not enough rest
-      else {
-        duty.restends = duty.end!.addDuration(restafter!).add(hours: 4);
-        duties[index] = duty;
-        nextduty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restfdp,
-            legalCauseMsg:
-                "Need more rest after ExtFDP before starting FDP on ${nextduty.start?.format(pattern: "ddMMMyy HH:mm")} rest: ${nextduty.start?.dateTime.difference(duty.end!.dateTime).tohhmm} / ${restafter.add(const Duration(hours: 4)).tohhmm}"));
-        duties[index + 1] = nextduty;
-      }
-    }
-    // restrecurrent,
-
-    //   36h inc 2 local nights or (60h if 4 disruptive)
-    const Duration maxdutyrecrest = Duration(hours: 168);
-    Duration minrecrest = const Duration(hours: 36);
-
-    DTInterval rest = DTInterval(duty.start!, duty.start!);
-    var i = index;
-
-    int nbdisruptive = 0;
-
-    while (i >= 1 &&
-        !(rest.duration.inMinutes >= const Duration(hours: 36).inMinutes &&
-            rest.contains(DTInterval.fromHm(
-                apartir: changeTz(rest.start, duties[i].placeStart!).toUtc(),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 7, minutes: 59),
-                ap: duties[i].placeStart!)) &&
-            rest.contains(DTInterval.fromHm(
-                apartir:
-                    changeTz(rest.start.add(hours: 24), duties[i].placeStart!)
-                        .toUtc(),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 7, minutes: 59),
-                ap: duties[i].placeStart!)))) {
-      final thisduty = duties[i];
-
-      if (_isEarlyStart(thisduty) ||
-          _isLateFinish(thisduty) ||
-          _isNightDuty(thisduty)) {
-        //log("${thisduty}");
-        nbdisruptive++;
-        if (nbdisruptive == 4) {
-          minrecrest = const Duration(hours: 60);
-        }
-      }
-      i--;
-      rest = DTInterval(duties[i].end!, duties[i + 1].start!);
-    }
-
-    if (DTInterval(rest.end, duty.end!).duration.inMinutes >
-        maxdutyrecrest.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.restrecurrent,
-          legalCauseMsg:
-              "Before duty, need ${minrecrest.inHours}h rest including 2 local nights. from: ${rest.end.format(pattern: "ddMMMyy HH:mm")} ${DTInterval(rest.end, duty.end!).duration.tohhmm}/${maxdutyrecrest.tohhmm} "));
-    }
-
-    //   48h inc 2 local days
-
-    final startmonth = changeTz(duty.start!.startOf(Unit.month), base);
-    final endmonth = startmonth.endOf(Unit.month);
-    if (duty.interval.isOverlap(
-        DTInterval(endmonth.subtract(days: 4).add(minutes: 1), endmonth))) {
-      int nb48inmonth = 0;
-      List<FtlDuty> dutiesmonth = duties
-          .where((e) => DTInterval(startmonth, endmonth)
-              .isOverlap(DTInterval(e.start!, e.end!)))
-          .toList();
-
-      List<DTInterval> restmonth = DTInterval(startmonth, endmonth).minusmany(
-          dutiesmonth
-              .map((e) => DTInterval(changeTz(e.start!, e.placeStart!),
-                  changeTz(e.end!, e.placeStart!)))
-              .toList());
-      // print(restmonth);
-
-      while (restmonth.isNotEmpty) {
-        final e = restmonth.removeAt(0);
-
-        final localdays = DTInterval.fromHm(
-            apartir: e.start.toUtc(),
-            h: 0,
-            m: 0,
-            duration: const Duration(hours: 47, minutes: 59),
-            ap: base);
-        if (e.contains(localdays)) {
-          nb48inmonth++;
-          // print(
-          //     "2localdays: ${localdays.start.format(pattern: "ddMMMyy HH:mm")} ${localdays.end.format(pattern: "ddMMMyy HH:mm")}");
-          // print(
-          //     "in rest ${e.start.format(pattern: "ddMMMyy HH:mm")} ${e.end.format(pattern: "ddMMMyy HH:mm")}");
-          restmonth = [...e.minus(localdays), ...restmonth];
-        }
-      }
-
-      if (nb48inmonth == 0) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      } else if (nb48inmonth == 1 &&
-          DTInterval(endmonth.subtract(days: 2).add(minutes: 1), endmonth)
-              .isOverlap(duty.interval)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      } else if (nb48inmonth == 1 &&
-          DTInterval(endmonth.subtract(days: 4).add(minutes: 1),
-                  endmonth.subtract(days: 2))
-              .isOverlap(duty.interval) &&
-          DTInterval(endmonth.subtract(days: 4).add(minutes: 1),
-                  endmonth.subtract(days: 2))
-              .intersectionmany(
-                  [...dutiesAsInterval, ...stdbyAsInterval]).isEmpty) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      }
-    }
-    // disruptive
-    duty.lateFinish = _isLateFinish(duty);
-    duty.earlyStart = _isEarlyStart(duty);
-    duty.nightDuty = _isNightDuty(duty);
-    if (duty.fdpStart != null &&
-        lastduty != null &&
-        base == lastduty.placeEnd &&
-        (_isLateFinish(lastduty) || _isNightDuty(lastduty)) &&
-        _isEarlyStart(duty)) {
-      // log("ftl: found late finish or nighty <${duty.start!.format(pattern: "ddMMMyy HH:mm")}");
-      if (!DTInterval(lastduty.end!, duty.start!).contains(DTInterval.fromHm(
-          apartir: changeTz(lastduty.end!, lastduty.placeEnd!).toUtc(),
-          h: 23,
-          m: 0,
-          duration: const Duration(hours: 7, minutes: 59),
-          ap: duty.placeStart!))) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            legalCauseMsg:
-                "Disruptive duty; one local night of rest is required before early departure."));
-      }
-    }
-
-    //consecutive night duty
-    if (_isConsecutiveNight(duty, lastduty)) {
-      var i = index;
-      final monthint = DTInterval(
-          changeTz(duty.start!.startOf(Unit.month), base),
-          changeTz(duty.start!.endOf(Unit.month), base));
-      int nbconsnight = 0;
-      while (i > 0 &&
-          duties[i]
-              .interval
-              .isOverlap(changeTzDt(monthint, duty.placeStart!))) {
-        if (_isConsecutiveNight(duties[i], duties[i - 1])) {
-          nbconsnight++;
-        }
-        i--;
-      }
-      if (nbconsnight > 1) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            legalCauseMsg:
-                "Consecutive nights is allowed only once per civil month."));
-      } else {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            condition:
-                "Two consecutive night duties; crew member agreement is required.",
-            legalCauseMsg: ""));
-      }
-    }
-
-    //local day rest if night duty
-    if (lastduty != null && _isNightDuty(lastduty)) {
-      if (DTInterval.fromHm(
-              apartir: changeTz(lastduty.end!, lastduty.placeEnd!).toUtc(),
-              h: 0,
-              m: 0,
-              duration: const Duration(hours: 23, minutes: 59),
-              ap: lastduty.placeEnd!)
-          .isOverlap(changeTzDt(duty.interval, duty.placeStart!))) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            condition: "You can request a local day off after last night duty.",
-            legalCauseMsg: ""));
-      }
-    }
-
-    // if (duty.legals.isNotEmpty) {
-    //   log("${duty.legals.map((e) => e.legalCauseMsg)}");
-    // }
-    // duties[index] = duty;
-  }
-
-  bool _isConsecutiveNight(FtlDuty duty, FtlDuty? lastduty) =>
-      _isNightDuty(duty) &&
-      lastduty != null &&
-      DTInterval.fromHm(
-              apartir: changeTz(lastduty.end!, lastduty.placeEnd!).toUtc(),
-              h: 2,
-              m: 0,
-              duration: const Duration(hours: 2, minutes: 59),
-              ap: lastduty.placeEnd!)
-          .isOverlap(lastduty.interval.toUtc());
-
-  FtlDuty? _addDutyDetail(
-      {required int index, required FtlDuty duty, Jiffy? checkin}) {
-    final one = dutiesDetails[index];
-    if (_fdpList.contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeEnd;
-
-      //duty.start = duty.start ?? _calcPreflight(one).latest(checkin);
-      duty.start = duty.start ?? checkin ?? _calcPreflight(one);
-
-      duty.end = _calcPostflight(one);
-      if (one.type == FtlDutyDetailsType.flight) {
-        duty.type = FtlDutyType.fdp;
-        duty.sectors++;
-        duty.fdpStart = duty.start;
-        duty.fdpEnd = one.end;
-      } else {
-        duty.type = duty.type ?? FtlDutyType.duty;
-      }
-      duty.dutiesDetailsIndex.add(index);
-    } else if ([FtlDutyDetailsType.standby, FtlDutyDetailsType.reserve]
-        .contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeStart;
-      duty.start = duty.start ?? _calcPreflight(one);
-      duty.end = one.end;
-      duty.type = FtlDutyType.other;
-      duty.dutiesDetailsIndex.add(index);
-    } else if ([FtlDutyDetailsType.ground, FtlDutyDetailsType.sim]
-        .contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeStart;
-      duty.start = duty.start ?? _calcPreflight(one);
-      duty.end = one.end;
-      duty.type = duty.type ?? FtlDutyType.duty;
-      duty.dutiesDetailsIndex.add(index);
-    } else {
-      return null;
-    }
-    return duty;
-  }
-
-  static bool _isEarlyStart(FtlDuty x) {
-//500 559
-    // print(
-    //     "$x is earlystart: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 5, m: 0, duration: const Duration(minutes: 59)).include(x.start!)}");
-    return (x.fdpStart != null &&
-        DTInterval.fromHm(
-                apartir: changeTz(x.start!.subtract(hours: 24), x.placeStart!)
-                    .toUtc(),
-                h: 5,
-                m: 0,
-                duration: const Duration(minutes: 59),
-                ap: x.placeStart!)
-            .include(changeTz(x.start!, x.placeStart!)));
-  }
-
-  static bool _isLateFinish(FtlDuty x) {
-//2300  159
-    // print(
-    //     "$x is latefinish: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 23, m: 0, duration: const Duration(hours: 2, minutes: 59)).include(x.end!)}");
-    return (x.type != FtlDutyType.other) &&
-        (DTInterval.fromHm(
-                apartir: changeTz(x.start!, x.placeStart!).toUtc(),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 2, minutes: 59),
-                ap: x.placeStart!)
-            .include(changeTz(x.end!, x.placeStart!)));
-  }
-
-  static bool _isNightDuty(FtlDuty x) {
-//200  459
-    // print(
-    //     "$x is Night duty: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 2, m: 0, duration: const Duration(hours: 2, minutes: 59)).include(x.end!)}");
-    return (x.type != FtlDutyType.other) &&
-        ((DTInterval.fromHm(
-                    apartir: x.start!.toUtc(),
-                    h: 2,
-                    m: 0,
-                    duration: const Duration(hours: 2, minutes: 59),
-                    ap: x.placeStart!))
-                .isOverlap(x.interval.toUtc()) ||
-            (DTInterval.fromHm(
-                    apartir: x.start!.subtract(days: 1).toUtc(),
-                    h: 2,
-                    m: 0,
-                    duration: const Duration(hours: 2, minutes: 59),
-                    ap: x.placeStart!))
-                .isOverlap(x.interval.toUtc()));
-  }
-
-  Duration tzDiff(String iata1, String iata2, DateTime sourceDateTime) {
-    // print(Airports.instance.find(iata1)!.timezoneid);
-    // print(Airports.instance.find(iata2)!.timezoneid);
-    final iata1Location = tz.getLocation(Airports.find(iata1)!.timezoneid);
-    final iata2Location = tz.getLocation(Airports.find(iata2)!.timezoneid);
-    tz.TZDateTime iata1TZDateTime =
-        tz.TZDateTime.from(sourceDateTime, iata1Location);
-    tz.TZDateTime iata2TZDateTime =
-        tz.TZDateTime.from(sourceDateTime, iata2Location);
-    return Duration(
-        minutes: (iata2TZDateTime.timeZoneOffset.inMinutes -
-                iata1TZDateTime.timeZoneOffset.inMinutes)
-            .abs());
-  }
-
-  String _acclimatized(
-      {required Duration tzoffset, required Duration timeElapsed}) {
-    if (tzoffset.inHours <= 2) {
-      return "D";
-    } else if (timeElapsed.inHours < 48) {
-      return "B";
-    } else if (tzoffset.inHours < 4 && timeElapsed.inHours >= 48) {
-      return "D";
-    } else if (tzoffset.inHours <= 6 && timeElapsed.inHours >= 72) {
-      return "D";
-    } else if (tzoffset.inHours <= 9 && timeElapsed.inHours >= 96) {
-      return "D";
-    } else if (tzoffset.inHours <= 12 && timeElapsed.inHours >= 120) {
-      return "D";
-    } else {
-      return "X";
-    }
-  }
-
-  static Jiffy changeTz(Jiffy jiffy, String iata) {
-    return Jiffy.parseFromDateTime(tz.TZDateTime.from(jiffy.dateTime,
-        tz.getLocation(Airports.find(iata)?.timezoneid ?? "UTC")));
-  }
-
-  static DTInterval changeTzDt(DTInterval dt, String iata) {
-    return DTInterval(changeTz(dt.start, iata), changeTz(dt.end, iata));
-  }
-
-  Duration _fdpMax(
-      {required reftime,
-      String? iata,
-      required int sectors,
-      required Map<String, List<String>> tab}) {
-    Jiffy reftjiffy = Jiffy.now();
-    String reft = "";
-
-    if (reftime is Jiffy && iata != null) {
-      reftjiffy = reftime;
-      reftjiffy = changeTz(reftjiffy, iata);
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else if (reftime is DateTime && iata != null) {
-      reftjiffy = Jiffy.parseFromDateTime(reftime);
-      reftjiffy = changeTz(reftjiffy, iata);
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else if (reftime is String && reftime.length == 4) {
-      reft = reftime;
-    } else if (reftime is String && iata != null) {
-      reftjiffy = Jiffy.parse(reftime);
-      reftjiffy = changeTz(reftjiffy, iata);
-
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else {
-      throw ("_fdpMax type of reftime unrecognized!!!");
-    }
-    // print("$iata  $reft ${reftjiffy.toUtc().Hm}");
-    for (String key in tab.keys) {
-      List<String> intervalle = key.split("-");
-      int cmph1 = reft.compareTo(intervalle[0]);
-      int cmph2 = reft.compareTo(intervalle[1]);
-
-      bool inint = (intervalle[0].compareTo(intervalle[1]) < 0)
-          ? (cmph1 >= 0 && cmph2 <= 0)
-          : ((cmph1 >= 0 || cmph2 <= 0));
-      if (inint) {
-        final List<String>? lres = tab[key];
-        final int nrow = ((sectors == 1) ? 2 : sectors) - 2;
-        final String? res =
-            (lres != null && nrow < lres.length) ? lres[nrow] : null;
-        if (res != null && res != "Not allowed") {
-          return Duration(
-              hours: int.parse(res.split(".")[0]),
-              minutes: int.parse(res.split(".")[1]));
-        }
-      }
-    }
-    return Duration.zero;
-  }
-
-  Duration fdpMaxBasic(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(reftime: reftime, iata: iata, sectors: sectors, tab: _fdpMaxTab);
-
-  Duration fdpMaxExtBasic(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(
-          reftime: reftime, iata: iata, sectors: sectors, tab: _fdpMaxExtTab);
-
-  Duration fdpMaxUnk({required reftime, String? iata, required int sectors}) =>
-      _fdpMax(reftime: reftime, iata: iata, sectors: sectors, tab: _fdpUnkTab);
-
-  Duration fdpMaxUnkFrms(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(
-          reftime: reftime, iata: iata, sectors: sectors, tab: _fdpUnkFrmsTab);
-
-//acclim
-
-  final Map<String, List<String>> _fdpMaxTab = {
-    "0600-1329": [
-      "13.00",
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-    ],
-    "1330-1359": [
-      "12.45",
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-    ],
-    "1400-1429": [
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-    ],
-    "1430-1459": [
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-    ],
-    "1500-1529": [
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1530-1559": [
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1600-1629": [
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1630-1659": [
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1700-0459": [
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "0500-0514": [
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "0515-0529": [
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-    ],
-    "0530-0544": [
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-    ],
-    "0545-0559": [
-      "12.45",
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-    ],
-  };
-  final Map<String, List<String>> _fdpMaxExtTab = {
-    "0600-0614": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0615-0629": [
-      "13.15",
-      "12.45",
-      "12.15",
-      "11.45",
-    ],
-    "0630-0644": [
-      "13.30",
-      "13.00",
-      "12.30",
-      "12.00",
-    ],
-    "0645-0659": [
-      "13.45",
-      "13.15",
-      "12.45",
-      "12.15",
-    ],
-    "0700-1329": [
-      "14.00",
-      "13.30",
-      "13.00",
-      "12.30",
-    ],
-    "1330-1359": [
-      "13.45",
-      "13.15",
-      "12.45",
-      "Not allowed",
-    ],
-    "1400-1429": [
-      "13.30",
-      "13.00",
-      "12.30",
-      "Not allowed",
-    ],
-    "1430-1459": [
-      "13.15",
-      "12.45",
-      "12.15",
-      "Not allowed",
-    ],
-    "1500-1529": [
-      "13.00",
-      "12.30",
-      "12.00",
-      "Not allowed",
-    ],
-    "1530-1559": [
-      "12.45",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1600-1629": [
-      "12.30",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1630-1659": [
-      "12.15",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1700-1729": [
-      "12.00",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1730-1759": [
-      "11.45",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1800-1829": [
-      "11.30",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1830-1859": [
-      "11.15",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1900-0359": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0400-0414": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0415-0429": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0430-0444": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0445-0459": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0500-0514": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0515-0529": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0530-0544": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0545-0559": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ]
-  };
-  final Map<String, List<String>> _fdpUnkTab = {
-    "0000-2359": ["11.00", "10:30", "10.00", "09.30", "09.00", "09.00", "09.00"]
-  };
-  final Map<String, List<String>> _fdpUnkFrmsTab = {
-    "0000-2359": ["12.00", "11.30", "11.00", "10.30", "10.00", "09.30", "09.00"]
-  };
-}
-
-class FtlDuty {
-  FtlDuty({this.start, this.end, this.placeStart, this.placeEnd, this.type});
-  @override
-  String toString() {
-    return "${start?.yMEd} ${start?.Hm} >>> ${end?.Hm} : ${fdpLength.inMinutes > 0 ? "FDP" : "DUTY"} ${dutiesDetailsIndex.length}leg(s)";
-  }
-
-  Jiffy? start;
-  Jiffy? end;
-  DTInterval get interval => DTInterval(start!, end!);
-  String? placeStart;
-  String? placeEnd;
-  FtlDutyType? type;
-  List<int> dutiesDetailsIndex = [];
-  Jiffy? fdpStart;
-  Jiffy? fdpEnd;
-  int sectors = 0;
-  Duration? fdpMax;
-  Duration? fdpExtMax;
-  //Duration? fdpIfRExtMax;//if inflight rest rest
-
-  bool fdpExt = false;
-  List<FtlLegal> legals = [];
-
-  Duration get dutyLength => (start != null && end != null)
-      ? end!.dateTime.difference(start!.dateTime)
-      : Duration.zero;
-  Duration get fdpLength => (fdpStart != null && fdpEnd != null)
-      ? fdpEnd!.dateTime.difference(fdpStart!.dateTime)
-      : Duration.zero;
-
-  // Duration? get rest => (dutyLength.max(Ftl.minimumrest(placeEnd)));
-  Jiffy? restends;
-
-  String? acclim;
-  String? reftime;
-
-  FtlDutyTotal? dutyTotal;
-
-  //Jiffy? report;
-  Jiffy? reportdelay1;
-  Jiffy? notification1;
-  Jiffy? reportdelay2;
-  Jiffy? notification2;
-  bool earlyStart = false;
-  bool lateFinish = false;
-  bool nightDuty = false;
-}
-
-class FtlLegal {
-  FtlLegal(
-      {required this.legalCause,
-      required this.legalCauseMsg,
-      this.legalIndex,
-      this.condition});
-  FtlLegalCause legalCause;
-  String legalCauseMsg;
-  int? legalIndex;
-  String? condition;
-}
-
-enum FtlDutyType { duty, fdp, other }
-
-class FtlDutyDetails {
-  FtlDutyDetails({
-    this.start,
-    this.end,
-    this.placeStart,
-    this.placeEnd,
-    this.type,
-    this.label,
-  });
-
-  Jiffy? start;
-  Jiffy? end;
-  DTInterval get interval => DTInterval(start!, end!);
-
-  Duration get duration => end!.dateTime.difference(start!.dateTime);
-  String? placeStart;
-  String? placeEnd;
-  FtlDutyDetailsType? type;
-  String get typeString {
-    switch (type) {
-      case FtlDutyDetailsType.flight:
-        return "FLT";
-      case FtlDutyDetailsType.dhflight:
-        return "DH-FLT";
-      case FtlDutyDetailsType.dhlimo:
-        return "DH-LIMO";
-      case FtlDutyDetailsType.sim:
-        return "SIM";
-      case FtlDutyDetailsType.standby:
-        return "STBY";
-      case FtlDutyDetailsType.reserve:
-        return "RSRV";
-      case FtlDutyDetailsType.ground:
-        return "GRND";
-
-      default:
-        return "UNK";
-    }
-  }
-
-  String? label;
-}
-
-enum FtlDutyDetailsType {
-  preflight,
-  flight,
-  postflight,
-  dhflight,
-  dhlimo,
-  ground,
-  standby,
-  reserve,
-  sim,
-//  training,
-//  other
-}
-
-class FtlDutyTotal {
-  FtlDutyTotal(
-      {required this.date, required this.dutyLength, required this.fltLength});
-  Jiffy date;
-  Duration dutyLength;
-  Duration fltLength;
-  Duration? dutylast7;
-  Duration? dutylast14;
-  Duration? dutylast28;
-  Duration? fltlast28;
-  Duration? fltyear;
-  Duration? fltlast12;
-}
-
-enum FtlLegalCause {
-  dutylast7,
-  dutylast14,
-  dutylast28,
-  fltlast28,
-  fltyear,
-  fltlast12,
-  fdpmax,
-  restfdp,
-  restrecurrent,
-  disruptive
-  //check duty length && flt length
-
-  //check fdp leength
-
-  //check rest before fdp
-  //check recurrent rest
-  //check disruptive sched
-}

+ 0 - 1557
lib/ftl/provider/ftl copy3.dart.bak

@@ -1,1557 +0,0 @@
-import 'dart:developer';
-
-import 'package:collection/collection.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:tp5/core/core.dart';
-import 'package:tp5/providers/airports.dart';
-import 'package:tp5/roster/models/duty.dart';
-
-import 'package:timezone/timezone.dart' as tz;
-
-class Ftl {
-  Duration minimumrest(String? station) =>
-      Duration(hours: station == base ? 12 : 12, minutes: 0, seconds: 0);
-  static Duration postflight = const Duration(minutes: 30);
-  static Duration preflight = const Duration(minutes: 60);
-  static Duration maxdutylast7 = const Duration(hours: 60);
-  static Duration maxdutylast14 = const Duration(hours: 110);
-  static Duration maxdutylast28 = const Duration(hours: 190);
-  static Duration maxfltlast28 = const Duration(hours: 100);
-  static Duration maxfltlastyear = const Duration(hours: 900);
-  static Duration maxfltlast12 = const Duration(hours: 1000);
-  Duration travelling(String station) {
-    if (base == station) return Duration.zero;
-    switch (station) {
-      case "DSS":
-        return const Duration(minutes: 60);
-      case "ORY":
-        return const Duration(minutes: 5);
-      default:
-        return const Duration(minutes: 30);
-    }
-  }
-
-  String base;
-
-  List<FtlDutyDetails> dutiesDetails = [];
-  List<Duty> clDuties = [];
-  List<FtlDuty> duties = [];
-
-  // List<FtlDutyTotal> dutiesLength = [];
-
-  List<DTInterval> get dutiesAsInterval => duties
-      .map((e) =>
-          (e.type != FtlDutyType.other) ? DTInterval(e.start!, e.end!) : null)
-      .whereNotNull()
-      .toList();
-  List<DTInterval> get stdbyAsInterval => dutiesDetails
-      .map((e) => (e.type == FtlDutyDetailsType.standby)
-          ? DTInterval(e.start!, e.end!)
-          : null)
-      .whereNotNull()
-      .toList();
-  List<DTInterval> get fltsAsInterval => dutiesDetails
-      .map((e) => (e.type == FtlDutyDetailsType.flight)
-          ? DTInterval(e.start!, e.end!)
-          : null)
-      .whereNotNull()
-      .toList();
-  bool frms;
-  Ftl({required this.dutiesDetails, required this.base, this.frms = false});
-  Ftl.fromCrewlink(
-      {required this.clDuties, required this.base, this.frms = false}) {
-    for (Duty one in clDuties) {
-      switch (one.type) {
-        case "flight":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.flight,
-              label: one.data["label"],
-            ),
-          );
-        case "dhflight":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.dhflight,
-              label: one.data["label"],
-            ),
-          );
-        case "dhlimo":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.dhlimo,
-              label: one.data["label"],
-            ),
-          );
-        case "ground":
-          if (["SBY1", "SBY2", "SBY3"].contains(one.data["label"])) {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.standby,
-                label: one.data["label"],
-              ),
-            );
-          } else if (["R0"].contains(one.data["label"])) {
-            //reserve is not duty
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.reserve,
-                label: one.data["label"],
-              ),
-            );
-          } else if ((one.data["actype"] ?? "") != "") {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.sim,
-                label: one.data["label"],
-              ),
-            );
-          } else if (one.start != null &&
-              one.end != null &&
-              one.end!.diff(one.start!, unit: Unit.hour).abs() < 12) {
-            dutiesDetails.add(
-              FtlDutyDetails(
-                start: one.start,
-                end: one.end,
-                placeStart: one.data["dep"],
-                // placeEnd: one.data["des"],
-                type: FtlDutyDetailsType.ground,
-                label: one.data["label"],
-              ),
-            );
-          } else {
-            // print("ftl: constr: unknown ${one.date} ${one.type} ${one.data}");
-          }
-        case "checkin":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              placeStart: one.data["dep"],
-              // placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.preflight,
-            ),
-          );
-
-        case "checkout":
-          dutiesDetails.add(
-            FtlDutyDetails(
-              start: one.start,
-              end: one.end,
-              // placeStart: one.data["dep"],
-              placeEnd: one.data["des"],
-              type: FtlDutyDetailsType.postflight,
-            ),
-          );
-        case "credit":
-        case "wholeday":
-          break;
-        default:
-        // print("ftl: unk: ${one.date} ${one.type} ${one.data}");
-      }
-    }
-  }
-
-  Jiffy? _calcPostflight(FtlDutyDetails xduty) {
-    if (xduty.end != null &&
-        [FtlDutyDetailsType.flight, FtlDutyDetailsType.dhflight]
-            .contains(xduty.type)) {
-      return xduty.end!.addDuration(postflight);
-    } else {
-      return xduty.end;
-    }
-  }
-
-  Jiffy? _calcPreflight(FtlDutyDetails xduty) {
-    if (xduty.start != null &&
-        [
-          FtlDutyDetailsType.flight,
-          FtlDutyDetailsType.dhflight,
-          FtlDutyDetailsType.dhlimo,
-          FtlDutyDetailsType.sim,
-        ].contains(xduty.type)) {
-      return (base == (xduty.placeStart ?? ""))
-          ? xduty.start!.subtractDuration(const Duration(minutes: 60))
-          : (xduty.start!.subtractDuration(preflight));
-    } else {
-      return xduty.start;
-    }
-  }
-
-  final List<FtlDutyDetailsType> _fdpList = [
-    FtlDutyDetailsType.flight,
-    FtlDutyDetailsType.dhflight,
-    FtlDutyDetailsType.dhlimo
-  ];
-
-  //calcul duties
-  calcduties({Jiffy? date}) {
-    log("FTL: start calcduties");
-    duties.clear();
-
-    final t1 = Jiffy.now();
-    _calcDuty();
-
-    log("FTL: start _calcfdpmax");
-    _calcfdpmax();
-
-    log("FTL: start _clacdutytotal");
-    // _calcDutyTotal();
-
-    log("FTL: start calclegal");
-    _calcLegal(date: date);
-
-    final t4 = Jiffy.now();
-    print(
-        "ftl: calcduties calculation :  ${t4.diff(t1, unit: Unit.second, asFloat: true)} ms");
-
-    log("FTL: finish calcduties");
-
-    // return [duties, dutiesDetails, dutiesLength];
-    return [duties, dutiesDetails];
-  }
-
-  _calcDuty() {
-    for (int i = 0; i < dutiesDetails.length; i++) {
-      var last = i > 0 ? dutiesDetails[i - 1] : null;
-
-      final checkin = ((last?.type == FtlDutyDetailsType.preflight)
-          ? dutiesDetails[i - 1].start
-          : null);
-
-      final newduty =
-          _addDutyDetail(index: i, duty: FtlDuty(), checkin: checkin);
-      //print("${dutiesDetails[i].type} $newduty");
-      if (newduty != null) {
-        if (duties.isEmpty) {
-          //first duty
-          duties.add(newduty);
-        } else if ((newduty.start!.isAfter(duties.last.end!)) &&
-            (duties.last.type == FtlDutyType.other ||
-                newduty.type == FtlDutyType.other)) {
-          //last and new are not duty nor fdp (other=>stdby or rsrv)
-          duties.add(newduty);
-        } else if ((newduty.start!
-                .subtractDuration(travelling(newduty.placeStart ?? base))
-                .isAfter(
-                  duties.last.end!
-                      .addDuration(travelling(duties.last.placeEnd ?? base)),
-                )) &&
-            // duties.last.type == FtlDutyType.duty &&
-            newduty.type == FtlDutyType.duty) {
-          //last is duty
-          duties.add(newduty);
-        } else if (newduty.start!.diff(duties.last.end!, unit: Unit.minute) <
-            minimumrest(duties.last.placeEnd).inMinutes) {
-          //diff < minimumrest
-          //ilhim
-          final mergedduty = _addDutyDetail(
-              index: i,
-              duty: duties.isNotEmpty ? duties.last : FtlDuty(),
-              checkin: checkin);
-          duties[duties.length - 1] = mergedduty!;
-        } else {
-          //jdida
-          duties.add(newduty);
-        }
-      }
-    }
-  }
-
-  _calcfdpmax() {
-    for (var i = 0; i < duties.length; i++) {
-      FtlDuty duty = duties[i];
-      FtlDuty? lastduty = i == 0 ? null : duties[i - 1];
-      if (duty.type == FtlDutyType.fdp) {
-        String acclim = _acclimatized(
-            tzoffset: tzDiff(duty.placeStart!, lastduty?.placeEnd ?? base,
-                duty.start!.dateTime),
-            timeElapsed:
-                lastduty?.end!.dateTime.difference(duty.start!.dateTime) ??
-                    const Duration());
-        duties[i].acclim = acclim;
-        duties[i].reftime = changeTz(duty.start!, duty.placeStart ?? base).Hm;
-
-        Jiffy reftime = duty.start!;
-        if (duty.reportdelay2 != null && duty.reportdelay1 != null) {
-          if (duty.start!.dateTime
-                  .difference(duty.reportdelay2!.dateTime)
-                  .inMinutes <
-              (4 * 60)) {
-            reftime = duty.start!;
-            duty.start =
-                duty.notification2!.add(hours: 1).min(duty.reportdelay1!);
-          } else {
-            reftime = duty.reportdelay2!;
-            duty.start = duty.reportdelay2!;
-          }
-        } else if (duty.reportdelay1 != null) {
-          if (duty.start!.dateTime
-                  .difference(duty.reportdelay1!.dateTime)
-                  .inMinutes <
-              (4 * 60)) {
-            reftime = duty.start!;
-            duty.start = duty.reportdelay1!;
-          } else {
-            reftime = duty.reportdelay1!;
-            duty.start = duty.reportdelay1!;
-          }
-        }
-
-        switch (acclim) {
-          case "D":
-            // print("${duty.start?.yMMMd} ${duty.start?.toUtc().Hm}");
-            duties[i].fdpMax = fdpMaxBasic(
-                reftime: reftime, iata: duty.placeStart, sectors: duty.sectors);
-            duties[i].fdpExtMax = fdpMaxExtBasic(
-                reftime: reftime, iata: duty.placeStart, sectors: duty.sectors);
-          case "B":
-            duties[i].fdpMax = fdpMaxBasic(
-                reftime: reftime,
-                iata: lastduty?.placeEnd ?? lastduty?.placeStart ?? base,
-                sectors: duty.sectors);
-            duties[i].fdpExtMax = fdpMaxExtBasic(
-                reftime: reftime,
-                iata: lastduty?.placeEnd ?? lastduty?.placeStart ?? base,
-                sectors: duty.sectors);
-          case "X":
-            if (frms) {
-              duties[i].fdpMax = fdpMaxUnk(
-                  reftime: reftime,
-                  iata: duty.placeStart,
-                  sectors: duty.sectors);
-            } else {
-              duties[i].fdpMax = fdpMaxUnkFrms(
-                  reftime: reftime,
-                  iata: duty.placeStart,
-                  sectors: duty.sectors);
-            }
-            break;
-          default:
-        }
-      }
-    }
-  }
-
-  _calcLegal({Jiffy? date}) {
-    if (date == null) {
-      for (var i = 0; i < duties.length; i++) {
-        _checklegal(index: i);
-      }
-    } else {
-      duties.forEachIndexed((i, e) {
-        if (duties[i]
-            .start!
-            .isSameOrAfter(date.startOf(Unit.day).subtract(days: 1))) {
-          _checklegal(index: i);
-        }
-      });
-    }
-  }
-
-  Duration _sumDuration(List<DTInterval> x) =>
-      Duration(milliseconds: x.map((e) => e.duration.inMilliseconds).sum);
-
-  List<DTInterval> breaks(FtlDuty duty) {
-    List<DTInterval> out = [];
-    for (var e in duty.dutiesDetailsIndex) {
-      final dutydetail = dutiesDetails[e];
-      final deptravel = (base == (dutydetail.placeStart ?? ""))
-          ? Duration.zero
-          : travelling(dutydetail.placeStart ?? "");
-      final destravel = (base == (dutydetail.placeEnd ?? ""))
-          ? Duration.zero
-          : travelling(dutydetail.placeEnd ?? dutydetail.placeStart ?? "");
-      final start = _calcPreflight(dutydetail)!.subtractDuration(deptravel);
-      final finish = _calcPostflight(dutydetail)!.addDuration(destravel);
-      if (finish.isAfter(start)) {
-        out.add(DTInterval(start, finish));
-      }
-    }
-    return duty.interval.minusmany(out);
-  }
-
-  _checklegal({required int index}) {
-    FtlDuty duty = duties[index];
-
-    final date = changeTz(duty.start!, base).endOf(Unit.day);
-
-    // log("ftl: dutylenght date=${date.format(pattern: "ddMMMyy HHmm")} \n date-7=${date.subtract(days: 7 - 1).startOf(Unit.day).format(pattern: "ddMMMyy HHmm")}");
-    // print("${date.yMEd}");
-    final dutyLength = FtlDutyTotal(
-        date: date, dutyLength: Duration.zero, fltLength: Duration.zero)
-      ..dutylast7 = _sumDuration(
-              DTInterval(date.subtract(days: 7 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(
-                  DTInterval(date.subtract(days: 7 - 1).startOf(Unit.day), date)
-                      .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..dutylast14 = _sumDuration(
-              DTInterval(date.subtract(days: 14 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(DTInterval(
-                      date.subtract(days: 14 - 1).startOf(Unit.day), date)
-                  .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..dutylast28 = _sumDuration(
-              DTInterval(date.subtract(days: 28 - 1).startOf(Unit.day), date)
-                  .intersectionmany(dutiesAsInterval))
-          .add(_sumDuration(DTInterval(
-                      date.subtract(days: 28 - 1).startOf(Unit.day), date)
-                  .intersectionmany(stdbyAsInterval))
-              .multiply(0.25))
-      ..fltlast28 = _sumDuration(
-          DTInterval(date.subtract(days: 28 - 1).startOf(Unit.day), date)
-              .intersectionmany(fltsAsInterval))
-      ..fltlast12 = _sumDuration(DTInterval(
-              date.endOf(Unit.month).subtract(months: 12).startOf(Unit.month),
-              date)
-          .intersectionmany(fltsAsInterval))
-      ..fltyear = _sumDuration(DTInterval(date.startOf(Unit.year), date)
-          .intersectionmany(fltsAsInterval));
-    duty.dutyTotal = dutyLength;
-    // print("${date.yMEd} ${dutyLength.fltyear?.tohhmm}");
-
-    // dutylast7,
-    if ((dutyLength.dutylast7?.inMinutes ?? 0) > maxdutylast7.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast7,
-          legalCauseMsg:
-              "Max duty in 7 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast7?.tohhmm} / ${maxdutylast7.inHours}h"));
-    }
-    // dutylast14,
-    if ((dutyLength.dutylast14?.inMinutes ?? 0) > maxdutylast14.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast14,
-          legalCauseMsg:
-              "Max duty in 14 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast14?.tohhmm} / ${maxdutylast14.inHours}h"));
-    }
-    // dutylast28,
-    if ((dutyLength.dutylast28?.inMinutes ?? 0) > maxdutylast28.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.dutylast28,
-          legalCauseMsg:
-              "Max duty in 28 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.dutylast28?.tohhmm} / ${maxdutylast28.inHours}h"));
-    }
-    // fltlast28,
-    if ((dutyLength.fltlast28?.inMinutes ?? 0) > maxfltlast28.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltlast28,
-          legalCauseMsg:
-              "Max flight hours in 28 days ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.fltlast28?.tohhmm} / ${maxfltlast28.inHours}h"));
-    }
-
-    // fltyear,
-    if ((dutyLength.fltyear?.inMinutes ?? 0) > maxfltlastyear.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltyear,
-          legalCauseMsg:
-              "Max flight hours in calendar year ${duty.start?.format(pattern: "yyyy")} exceeded: ${dutyLength.fltyear?.tohhmm} / ${maxfltlastyear.inHours}h"));
-    }
-    // fltlast12,
-    if ((dutyLength.fltlast12?.inMinutes ?? 0) > maxfltlast12.inMinutes) {
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.fltlast12,
-          legalCauseMsg:
-              "Max flight hours in 12 months ending ${duty.start?.format(pattern: "ddMMMyy")} exceeded: ${dutyLength.fltlast12?.tohhmm} / ${maxfltlast12.inHours}h"));
-    }
-
-    // fdpmax,
-    if (duty.type == FtlDutyType.fdp && duty.fdpMax != null) {
-      if (duty.fdpLength.inMinutes <= duty.fdpMax!.inMinutes) {
-      } else if (duty.fdpExtMax != null &&
-          duty.fdpLength.inMinutes <= duty.fdpExtMax!.inMinutes) {
-        int nbFdpExt = 0;
-        for (var i = index;
-            i >= 0 &&
-                DTInterval(
-                        changeTz(duty.start!, base)
-                            .startOf(Unit.day)
-                            .subtract(days: 7),
-                        changeTz(duty.end!, base))
-                    .isOverlap(DTInterval(duties[i].start!, duties[i].end!));
-            i--) {
-          if (duties[i].fdpExt) nbFdpExt++;
-        }
-
-        if (nbFdpExt < 2) {
-          duty.fdpExt = true;
-          duties[index] = duty;
-        } else {
-          //nbext more than2 in 7days
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              legalCauseMsg:
-                  "FDP Ext used more than twice in 7 days. ${duty.fdpLength.tohhmm} / ${duty.fdpMax?.tohhmm} / ext${duty.fdpExtMax?.tohhmm}"));
-        }
-      } else if (breaks(duty).any((e) => (e.duration.inHours > 3)
-          //&&
-          // ((duty.fdpLength.inMinutes) <=
-          //     (e.duration
-          //         .multiply(0.5)
-          //         .add(duty.fdpMax ?? Duration.zero)
-          //         .inMinutes)))) {
-          )) {
-        //split duty check
-        final fdpmaxbreak = breaks(duty)
-            .map((e) => ((e.duration.inHours > 3)
-                ? ((e.duration.multiply(0.5).add(duty.fdpMax ?? Duration.zero)))
-                : null))
-            .whereNotNull();
-        if (fdpmaxbreak.isNotEmpty && duty.fdpLength < fdpmaxbreak.first) {
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              condition:
-                  "A break on ground must be considered to extend FDP Max to ${fdpmaxbreak.first.tohhmm}, ",
-              legalCauseMsg: "FDP is: ${duty.fdpLength.tohhmm}"));
-        } else {
-          duty.legals.add(FtlLegal(
-              legalCause: FtlLegalCause.fdpmax,
-              legalCauseMsg:
-                  "FDP Max is excedeed even with ground break of ${breaks(duty).map((e) => ((e.duration.inHours > 3) ? (e.duration) : null)).whereNotNull().first.tohhmm}.  FDP:${duty.fdpLength.tohhmm}/Max:${fdpmaxbreak.first.tohhmm}"));
-        }
-      } else {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.fdpmax,
-            legalCauseMsg:
-                "FDP is ${duty.fdpLength.tohhmm}/Max:${duty.fdpMax?.tohhmm}"));
-      }
-    }
-    // restfdp without ext,
-    final FtlDuty? lastduty = (index > 0) ? duties[index - 1] : null;
-    // log("ftl: checking duty <${duty}> lastduty ended <${lastduty}>");
-
-    if (lastduty != null &&
-        duty.type == FtlDutyType.fdp &&
-        (lastduty.type == FtlDutyType.fdp ||
-            lastduty.type == FtlDutyType.duty ||
-            lastduty.dutiesDetailsIndex.any(
-                (e) => dutiesDetails[e].type == FtlDutyDetailsType.standby))) {
-      final rest = minimumrest(lastduty.placeEnd)
-          .max(duty.end!.dateTime.difference(duty.start!.dateTime));
-      duties[index - 1].restends = lastduty.end!.addDuration(rest);
-
-      if (lastduty.restends!.isAfter(duty.start!)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restfdp,
-            legalCauseMsg:
-                "Need more rest before starting FDP. rest: ${duty.start!.dateTime.difference(lastduty.end!.dateTime).tohhmm} / ${rest.tohhmm}"));
-      }
-    }
-    // restfdp with ext,
-    duty = duties[index];
-    FtlDuty? nextduty = (index < duties.length - 1) ? duties[index + 1] : null;
-    if (duty.fdpExt) {
-      final restbefore = (lastduty == null)
-          ? null
-          : minimumrest(lastduty.placeEnd)
-              .max(lastduty.end!.dateTime.difference(lastduty.start!.dateTime));
-      final restafter = (nextduty == null)
-          ? null
-          : minimumrest(duty.placeEnd)
-              .max(duty.end!.dateTime.difference(duty.start!.dateTime));
-//+2h rest before && 2h rest after
-      if ((lastduty == null ||
-              duty.start!.dateTime
-                      .difference(lastduty.end!.dateTime)
-                      .inMinutes >=
-                  (restbefore?.inMinutes ?? 0) + (2 * 60)) &&
-          (nextduty == null ||
-              nextduty.start!.dateTime
-                      .difference(duty.end!.dateTime)
-                      .inMinutes >=
-                  (restafter?.inMinutes ?? 0) + (60 * 2))) {
-      }
-//+4h rest after
-      else if ((nextduty == null ||
-          nextduty.start!.dateTime.difference(duty.end!.dateTime).inMinutes >=
-              (restafter?.inMinutes ?? 0) + (60 * 4))) {
-      }
-//not enough rest
-      else {
-        duty.restends = duty.end!.addDuration(restafter!).add(hours: 4);
-        duties[index] = duty;
-        nextduty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restfdp,
-            legalCauseMsg:
-                "Need more rest after ExtFDP before starting FDP on ${nextduty.start?.format(pattern: "ddMMMyy HH:mm")} rest: ${nextduty.start?.dateTime.difference(duty.end!.dateTime).tohhmm} / ${restafter.add(const Duration(hours: 4)).tohhmm}"));
-        duties[index + 1] = nextduty;
-      }
-    }
-    // restrecurrent,
-
-    //   36h inc 2 local nights or (60h if 4 disruptive)
-    const Duration maxdutyrecrest = Duration(hours: 168);
-    Duration minrecrest = const Duration(hours: 36);
-    bool foundrecrest = false;
-
-    var i = index;
-    int nbdisruptive = 0;
-    DTInterval rest = DTInterval(duty.start!.toUtc(), duty.start!.toUtc());
-    String restPlace = duty.placeStart!;
-    DTInterval dutyl = DTInterval(duty.start!.toUtc(), duty.end!.toUtc());
-    Jiffy lastdutystart = duty.start!.toUtc();
-
-    //find last recrest
-    while (i >= 1 && !(foundrecrest)) {
-      i--;
-
-      lastdutystart = duties[i + 1].start!.toUtc();
-      dutyl = DTInterval(lastdutystart, duty.end!.toUtc());
-      bool disruptive = (_isEarlyStart(duties[i + 1]) ||
-          _isLateFinish(duties[i + 1]) ||
-          _isNightDuty(duties[i + 1]));
-
-      while (i >= 1 &&
-          duties[i]
-              .legals
-              .any((e) => e.legalCause == FtlLegalCause.restrecurrent)) {
-        i--;
-      }
-
-      rest = DTInterval(duties[i].end!.toUtc(), lastdutystart);
-      restPlace = duties[i].placeStart!;
-
-      foundrecrest = (rest.duration.inMinutes >= minrecrest.inMinutes) &&
-          rest.contains(DTInterval.fromHm(
-              apartir: rest.start.toUtc(),
-              h: 23,
-              m: 0,
-              duration: const Duration(hours: 7, minutes: 59),
-              ap: restPlace)) &&
-          rest.contains(DTInterval.fromHm(
-              apartir: rest.start.toUtc().add(days: 1),
-              h: 23,
-              m: 0,
-              duration: const Duration(hours: 7, minutes: 59),
-              ap: restPlace));
-
-      if (foundrecrest) print("ftl: recrest 36h: $rest");
-      if (!foundrecrest && disruptive) {
-        nbdisruptive++;
-      }
-    }
-
-    //check if 60h rest needed
-
-    //find recrest before last recrest
-
-    int j = i;
-    final duty2 = duties[j];
-    bool foundrecrest2 = false;
-    int nbdisruptive2 = 0;
-    DTInterval rest2 = DTInterval(duty2.start!.toUtc(), duty2.start!.toUtc());
-    String restPlace2 = duty2.placeStart!;
-    DTInterval dutyl2 = DTInterval(duty2.start!.toUtc(), duty2.end!.toUtc());
-    Jiffy lastdutystart2 = duty2.start!.toUtc();
-    if (duty.start!.isBefore(rest.start.add(hours: 60))) {
-      print("ftl 60h: $duty");
-      while (j >= 1 && !(foundrecrest2)) {
-        j--;
-
-        lastdutystart2 = duties[j + 1].start!.toUtc();
-        dutyl2 = DTInterval(lastdutystart2, duty2.end!.toUtc());
-        bool disruptive2 = (_isEarlyStart(duties[j + 1]) ||
-            _isLateFinish(duties[j + 1]) ||
-            _isNightDuty(duties[j + 1]));
-
-        while (j >= 1 &&
-            duties[j]
-                .legals
-                .any((e) => e.legalCause == FtlLegalCause.restrecurrent)) {
-          j--;
-        }
-
-        rest2 = DTInterval(duties[j].end!.toUtc(), lastdutystart2);
-        restPlace2 = duties[j].placeStart!;
-
-        foundrecrest2 = (rest2.duration.inMinutes >= minrecrest.inMinutes) &&
-            rest2.contains(DTInterval.fromHm(
-                apartir: rest2.start.toUtc(),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 7, minutes: 59),
-                ap: restPlace2)) &&
-            rest2.contains(DTInterval.fromHm(
-                apartir: rest2.start.toUtc().add(days: 1),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 7, minutes: 59),
-                ap: restPlace2));
-
-        // if (foundrecrest) print(rest);
-        if (!foundrecrest2 && disruptive2) {
-          nbdisruptive2++;
-        }
-      }
-      print("ftl: duty 60h: nbdisruptive: $nbdisruptive2");
-    }
-
-    if (nbdisruptive2 >= 4) {
-      const restlength = Duration(hours: 60);
-      final lastduty = ((index >= 2 &&
-              duties[index - 1]
-                  .legals
-                  .any((e) => e.legalCause == FtlLegalCause.restrecurrent))
-          ? duties[index - 2]
-          : duties[index - 1]);
-      duty.legals.add(FtlLegal(
-          legalCause: FtlLegalCause.restrecurrent,
-          legalCauseMsg:
-              "More than 4 disruptive duties found before recurrent rest. Need ${restlength.inHours}h rest. Next duty can be started after <${lastduty.end!.addDuration(restlength).max(DTInterval.fromHm(apartir: lastduty.end!.toUtc(), h: 23, m: 0, duration: const Duration(hours: 7, minutes: 59), ap: lastduty.placeEnd!).end.add(days: 1)).format(pattern: "ddMMMyy HH:mm")}>"));
-    } else {
-      // if (DTInterval(duties[i].start!, duty.end!).duration.inMinutes >
-      // print("ftl nb disruptive $nbdisruptive");
-      if (dutyl.duration.inMinutes > maxdutyrecrest.inMinutes) {
-        final restlength =
-            ((nbdisruptive <= 4) ? minrecrest : const Duration(hours: 60));
-        final lastduty = ((index >= 2 &&
-                duties[index - 1]
-                    .legals
-                    .any((e) => e.legalCause == FtlLegalCause.restrecurrent))
-            ? duties[index - 2]
-            : duties[index - 1]);
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "More than ${maxdutyrecrest.inHours}h without recurrent rest. from <${rest.end.format(pattern: "ddMMMyy HH:mm")}> to <${duty.end!.format(pattern: "ddMMMyy HH:mm")}> ${DTInterval(rest.end, duty.end!).duration.tohhmm}. ${maxdutyrecrest.inHours}h ends at <${rest.end.addDuration(maxdutyrecrest).format(pattern: "ddMMMyy HH:mm")}>. Need ${restlength.inHours}h rest. Next duty can be started after <${lastduty.end!.addDuration(restlength).max(DTInterval.fromHm(apartir: lastduty.end!.toUtc(), h: 23, m: 0, duration: const Duration(hours: 7, minutes: 59), ap: lastduty.placeEnd!).end.add(days: 1)).format(pattern: "ddMMMyy HH:mm")}>"));
-      }
-    }
-
-    //   48h inc 2 local days
-
-    final startmonth = changeTz(duty.start!.startOf(Unit.month), base);
-    final endmonth = startmonth.endOf(Unit.month);
-    if (duty.interval.isOverlap(
-        DTInterval(endmonth.subtract(days: 4).add(minutes: 1), endmonth))) {
-      int nb48inmonth = 0;
-      List<FtlDuty> dutiesmonth = duties
-          .where((e) => DTInterval(startmonth, endmonth)
-              .isOverlap(DTInterval(e.start!, e.end!)))
-          .toList();
-
-      List<DTInterval> restmonth = DTInterval(startmonth, endmonth).minusmany(
-          dutiesmonth
-              .map((e) => DTInterval(changeTz(e.start!, e.placeStart!),
-                  changeTz(e.end!, e.placeStart!)))
-              .toList());
-      // print(restmonth);
-
-      while (restmonth.isNotEmpty) {
-        final e = restmonth.removeAt(0);
-
-        final localdays = DTInterval.fromHm(
-            apartir: e.start.toUtc(),
-            h: 0,
-            m: 0,
-            duration: const Duration(hours: 47, minutes: 59),
-            ap: base);
-        if (e.contains(localdays)) {
-          nb48inmonth++;
-          // print(
-          //     "2localdays: ${localdays.start.format(pattern: "ddMMMyy HH:mm")} ${localdays.end.format(pattern: "ddMMMyy HH:mm")}");
-          // print(
-          //     "in rest ${e.start.format(pattern: "ddMMMyy HH:mm")} ${e.end.format(pattern: "ddMMMyy HH:mm")}");
-          restmonth = [...e.minus(localdays), ...restmonth];
-        }
-      }
-
-      if (nb48inmonth == 0) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      } else if (nb48inmonth == 1 &&
-          DTInterval(endmonth.subtract(days: 2).add(minutes: 1), endmonth)
-              .isOverlap(duty.interval)) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      } else if (nb48inmonth == 1 &&
-          DTInterval(endmonth.subtract(days: 4).add(minutes: 1),
-                  endmonth.subtract(days: 2))
-              .isOverlap(duty.interval) &&
-          DTInterval(endmonth.subtract(days: 4).add(minutes: 1),
-                  endmonth.subtract(days: 2))
-              .intersectionmany(
-                  [...dutiesAsInterval, ...stdbyAsInterval]).isEmpty) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.restrecurrent,
-            legalCauseMsg:
-                "Before duty, need 2x2 local days rest from: ${startmonth.format(pattern: "ddMMMyy HH:mm")} to:  ${endmonth.format(pattern: "ddMMMyy HH:mm")}"));
-      }
-    }
-    // disruptive
-    duty.lateFinish = _isLateFinish(duty);
-    duty.earlyStart = _isEarlyStart(duty);
-    duty.nightDuty = _isNightDuty(duty);
-    if (duty.fdpStart != null &&
-        lastduty != null &&
-        base == lastduty.placeEnd &&
-        (_isLateFinish(lastduty) || _isNightDuty(lastduty)) &&
-        _isEarlyStart(duty)) {
-      // log("ftl: found late finish or nighty <${duty.start!.format(pattern: "ddMMMyy HH:mm")}");
-      if (!DTInterval(lastduty.end!, duty.start!).contains(DTInterval.fromHm(
-          apartir: changeTz(lastduty.end!, lastduty.placeEnd!).toUtc(),
-          h: 23,
-          m: 0,
-          duration: const Duration(hours: 7, minutes: 59),
-          ap: duty.placeStart!))) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            legalCauseMsg:
-                "Disruptive duty; one local night of rest is required before early departure."));
-      }
-    }
-
-    //consecutive night duty
-    if (_isConsecutiveNight(duty, lastduty)) {
-      var i = index;
-      final monthint = DTInterval(
-          changeTz(duty.start!.startOf(Unit.month), base),
-          changeTz(duty.start!.endOf(Unit.month), base));
-      int nbconsnight = 0;
-      while (i > 0 &&
-          duties[i]
-              .interval
-              .isOverlap(changeTzDt(monthint, duty.placeStart!))) {
-        if (_isConsecutiveNight(duties[i], duties[i - 1])) {
-          nbconsnight++;
-        }
-        i--;
-      }
-      if (nbconsnight > 1) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            legalCauseMsg:
-                "Consecutive nights is allowed only once per civil month."));
-      } else {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            condition:
-                "Two consecutive night duties; crew member agreement is required.",
-            legalCauseMsg: ""));
-      }
-    }
-
-    //local day rest if night duty
-    if (lastduty != null && _isNightDuty(lastduty)) {
-      if (DTInterval.fromHm(
-              apartir: changeTz(lastduty.end!, lastduty.placeEnd!).toUtc(),
-              h: 0,
-              m: 0,
-              duration: const Duration(hours: 23, minutes: 59),
-              ap: lastduty.placeEnd!)
-          .isOverlap(changeTzDt(duty.interval, duty.placeStart!))) {
-        duty.legals.add(FtlLegal(
-            legalCause: FtlLegalCause.disruptive,
-            condition: "You can request a local day off after last night duty.",
-            legalCauseMsg: ""));
-      }
-    }
-
-    // if (duty.legals.isNotEmpty) {
-    //   log("${duty.legals.map((e) => e.legalCauseMsg)}");
-    // }
-    // duties[index] = duty;
-  }
-
-  bool _isConsecutiveNight(FtlDuty duty, FtlDuty? lastduty) =>
-      _isNightDuty(duty) &&
-      lastduty != null &&
-      DTInterval.fromHm(
-              apartir: changeTz(lastduty.end!, lastduty.placeEnd!).toUtc(),
-              h: 2,
-              m: 0,
-              duration: const Duration(hours: 2, minutes: 59),
-              ap: lastduty.placeEnd!)
-          .isOverlap(lastduty.interval.toUtc());
-
-  FtlDuty? _addDutyDetail(
-      {required int index, required FtlDuty duty, Jiffy? checkin}) {
-    final one = dutiesDetails[index];
-    if (_fdpList.contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeEnd;
-
-      //duty.start = duty.start ?? _calcPreflight(one).latest(checkin);
-      duty.start = duty.start ?? checkin ?? _calcPreflight(one);
-
-      duty.end = _calcPostflight(one);
-      if (one.type == FtlDutyDetailsType.flight) {
-        duty.type = FtlDutyType.fdp;
-        duty.sectors++;
-        duty.fdpStart = duty.start;
-        duty.fdpEnd = one.end;
-      } else {
-        duty.type = duty.type ?? FtlDutyType.duty;
-      }
-      duty.dutiesDetailsIndex.add(index);
-    } else if ([FtlDutyDetailsType.standby, FtlDutyDetailsType.reserve]
-        .contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeStart;
-      duty.start = duty.start ?? _calcPreflight(one);
-      duty.end = one.end;
-      duty.type = FtlDutyType.other;
-      duty.dutiesDetailsIndex.add(index);
-    } else if ([FtlDutyDetailsType.ground, FtlDutyDetailsType.sim]
-        .contains(one.type)) {
-      duty.placeStart = duty.placeStart ?? one.placeStart;
-      duty.placeEnd = one.placeStart;
-      duty.start = duty.start ?? _calcPreflight(one);
-      duty.end = one.end;
-      duty.type = duty.type ?? FtlDutyType.duty;
-      duty.dutiesDetailsIndex.add(index);
-    } else {
-      return null;
-    }
-    return duty;
-  }
-
-  static bool _isEarlyStart(FtlDuty x) {
-//500 559
-    // print(
-    //     "$x is earlystart: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 5, m: 0, duration: const Duration(minutes: 59)).include(x.start!)}");
-    return (x.fdpStart != null &&
-        DTInterval.fromHm(
-                apartir: changeTz(x.start!.subtract(hours: 24), x.placeStart!)
-                    .toUtc(),
-                h: 5,
-                m: 0,
-                duration: const Duration(minutes: 59),
-                ap: x.placeStart!)
-            .include(changeTz(x.start!, x.placeStart!)));
-  }
-
-  static bool _isLateFinish(FtlDuty x) {
-//2300  159
-    // print(
-    //     "$x is latefinish: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 23, m: 0, duration: const Duration(hours: 2, minutes: 59)).include(x.end!)}");
-    return (x.type != FtlDutyType.other) &&
-        (DTInterval.fromHm(
-                apartir: changeTz(x.start!, x.placeStart!).toUtc(),
-                h: 23,
-                m: 0,
-                duration: const Duration(hours: 2, minutes: 59),
-                ap: x.placeStart!)
-            .include(changeTz(x.end!, x.placeStart!)));
-  }
-
-  static bool _isNightDuty(FtlDuty x) {
-//200  459
-    // print(
-    //     "$x is Night duty: ${DTInterval.fromHm(apartir: changeTz(x.start!, x.placeStart!), h: 2, m: 0, duration: const Duration(hours: 2, minutes: 59)).include(x.end!)}");
-    return (x.type != FtlDutyType.other) &&
-        ((DTInterval.fromHm(
-                    apartir: x.start!.toUtc(),
-                    h: 2,
-                    m: 0,
-                    duration: const Duration(hours: 2, minutes: 59),
-                    ap: x.placeStart!))
-                .isOverlap(x.interval.toUtc()) ||
-            (DTInterval.fromHm(
-                    apartir: x.start!.subtract(days: 1).toUtc(),
-                    h: 2,
-                    m: 0,
-                    duration: const Duration(hours: 2, minutes: 59),
-                    ap: x.placeStart!))
-                .isOverlap(x.interval.toUtc()));
-  }
-
-  Duration tzDiff(String iata1, String iata2, DateTime sourceDateTime) {
-    // print(Airports.instance.find(iata1)!.timezoneid);
-    // print(Airports.instance.find(iata2)!.timezoneid);
-    final iata1Location = tz.getLocation(Airports.find(iata1)!.timezoneid);
-    final iata2Location = tz.getLocation(Airports.find(iata2)!.timezoneid);
-    tz.TZDateTime iata1TZDateTime =
-        tz.TZDateTime.from(sourceDateTime, iata1Location);
-    tz.TZDateTime iata2TZDateTime =
-        tz.TZDateTime.from(sourceDateTime, iata2Location);
-    return Duration(
-        minutes: (iata2TZDateTime.timeZoneOffset.inMinutes -
-                iata1TZDateTime.timeZoneOffset.inMinutes)
-            .abs());
-  }
-
-  String _acclimatized(
-      {required Duration tzoffset, required Duration timeElapsed}) {
-    if (tzoffset.inHours <= 2) {
-      return "D";
-    } else if (timeElapsed.inHours < 48) {
-      return "B";
-    } else if (tzoffset.inHours < 4 && timeElapsed.inHours >= 48) {
-      return "D";
-    } else if (tzoffset.inHours <= 6 && timeElapsed.inHours >= 72) {
-      return "D";
-    } else if (tzoffset.inHours <= 9 && timeElapsed.inHours >= 96) {
-      return "D";
-    } else if (tzoffset.inHours <= 12 && timeElapsed.inHours >= 120) {
-      return "D";
-    } else {
-      return "X";
-    }
-  }
-
-  static Jiffy changeTz(Jiffy jiffy, String iata) {
-    return Jiffy.parseFromDateTime(tz.TZDateTime.from(jiffy.dateTime,
-        tz.getLocation(Airports.find(iata)?.timezoneid ?? "UTC")));
-  }
-
-  static DTInterval changeTzDt(DTInterval dt, String iata) {
-    return DTInterval(changeTz(dt.start, iata), changeTz(dt.end, iata));
-  }
-
-  Duration _fdpMax(
-      {required reftime,
-      String? iata,
-      required int sectors,
-      required Map<String, List<String>> tab}) {
-    Jiffy reftjiffy = Jiffy.now();
-    String reft = "";
-
-    if (reftime is Jiffy && iata != null) {
-      reftjiffy = reftime;
-      reftjiffy = changeTz(reftjiffy, iata);
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else if (reftime is DateTime && iata != null) {
-      reftjiffy = Jiffy.parseFromDateTime(reftime);
-      reftjiffy = changeTz(reftjiffy, iata);
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else if (reftime is String && reftime.length == 4) {
-      reft = reftime;
-    } else if (reftime is String && iata != null) {
-      reftjiffy = Jiffy.parse(reftime);
-      reftjiffy = changeTz(reftjiffy, iata);
-
-      reft = reftjiffy.format(pattern: "HHmm");
-    } else {
-      throw ("_fdpMax type of reftime unrecognized!!!");
-    }
-    // print("$iata  $reft ${reftjiffy.toUtc().Hm}");
-    for (String key in tab.keys) {
-      List<String> intervalle = key.split("-");
-      int cmph1 = reft.compareTo(intervalle[0]);
-      int cmph2 = reft.compareTo(intervalle[1]);
-
-      bool inint = (intervalle[0].compareTo(intervalle[1]) < 0)
-          ? (cmph1 >= 0 && cmph2 <= 0)
-          : ((cmph1 >= 0 || cmph2 <= 0));
-      if (inint) {
-        final List<String>? lres = tab[key];
-        final int nrow = ((sectors == 1) ? 2 : sectors) - 2;
-        final String? res =
-            (lres != null && nrow < lres.length) ? lres[nrow] : null;
-        if (res != null && res != "Not allowed") {
-          return Duration(
-              hours: int.parse(res.split(".")[0]),
-              minutes: int.parse(res.split(".")[1]));
-        }
-      }
-    }
-    return Duration.zero;
-  }
-
-  Duration fdpMaxBasic(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(reftime: reftime, iata: iata, sectors: sectors, tab: _fdpMaxTab);
-
-  Duration fdpMaxExtBasic(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(
-          reftime: reftime, iata: iata, sectors: sectors, tab: _fdpMaxExtTab);
-
-  Duration fdpMaxUnk({required reftime, String? iata, required int sectors}) =>
-      _fdpMax(reftime: reftime, iata: iata, sectors: sectors, tab: _fdpUnkTab);
-
-  Duration fdpMaxUnkFrms(
-          {required reftime, String? iata, required int sectors}) =>
-      _fdpMax(
-          reftime: reftime, iata: iata, sectors: sectors, tab: _fdpUnkFrmsTab);
-
-//acclim
-
-  final Map<String, List<String>> _fdpMaxTab = {
-    "0600-1329": [
-      "13.00",
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-    ],
-    "1330-1359": [
-      "12.45",
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-    ],
-    "1400-1429": [
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-    ],
-    "1430-1459": [
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-    ],
-    "1500-1529": [
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1530-1559": [
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1600-1629": [
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1630-1659": [
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "1700-0459": [
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "0500-0514": [
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-      "09.00",
-    ],
-    "0515-0529": [
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-      "09.00",
-    ],
-    "0530-0544": [
-      "12.30",
-      "12.00",
-      "11.30",
-      "11.00",
-      "10.30",
-      "10.00",
-      "09.30",
-      "09.00",
-      "09.00",
-    ],
-    "0545-0559": [
-      "12.45",
-      "12.15",
-      "11.45",
-      "11.15",
-      "10.45",
-      "10.15",
-      "09.45",
-      "09.15",
-      "09.00",
-    ],
-  };
-  final Map<String, List<String>> _fdpMaxExtTab = {
-    "0600-0614": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0615-0629": [
-      "13.15",
-      "12.45",
-      "12.15",
-      "11.45",
-    ],
-    "0630-0644": [
-      "13.30",
-      "13.00",
-      "12.30",
-      "12.00",
-    ],
-    "0645-0659": [
-      "13.45",
-      "13.15",
-      "12.45",
-      "12.15",
-    ],
-    "0700-1329": [
-      "14.00",
-      "13.30",
-      "13.00",
-      "12.30",
-    ],
-    "1330-1359": [
-      "13.45",
-      "13.15",
-      "12.45",
-      "Not allowed",
-    ],
-    "1400-1429": [
-      "13.30",
-      "13.00",
-      "12.30",
-      "Not allowed",
-    ],
-    "1430-1459": [
-      "13.15",
-      "12.45",
-      "12.15",
-      "Not allowed",
-    ],
-    "1500-1529": [
-      "13.00",
-      "12.30",
-      "12.00",
-      "Not allowed",
-    ],
-    "1530-1559": [
-      "12.45",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1600-1629": [
-      "12.30",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1630-1659": [
-      "12.15",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1700-1729": [
-      "12.00",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1730-1759": [
-      "11.45",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1800-1829": [
-      "11.30",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1830-1859": [
-      "11.15",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "1900-0359": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0400-0414": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0415-0429": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0430-0444": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0445-0459": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0500-0514": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0515-0529": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0530-0544": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ],
-    "0545-0559": [
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-      "Not allowed",
-    ]
-  };
-  final Map<String, List<String>> _fdpUnkTab = {
-    "0000-2359": ["11.00", "10:30", "10.00", "09.30", "09.00", "09.00", "09.00"]
-  };
-  final Map<String, List<String>> _fdpUnkFrmsTab = {
-    "0000-2359": ["12.00", "11.30", "11.00", "10.30", "10.00", "09.30", "09.00"]
-  };
-}
-
-class FtlDuty {
-  FtlDuty({this.start, this.end, this.placeStart, this.placeEnd, this.type});
-  @override
-  String toString() {
-    return "${start?.yMEd} ${start?.Hm} >>> ${end?.Hm} : ${fdpLength.inMinutes > 0 ? "FDP" : "DUTY"} ${dutiesDetailsIndex.length}leg(s)";
-  }
-
-  Jiffy? start;
-  Jiffy? end;
-  DTInterval get interval => DTInterval(start!, end!);
-  String? placeStart;
-  String? placeEnd;
-  FtlDutyType? type;
-  List<int> dutiesDetailsIndex = [];
-  Jiffy? fdpStart;
-  Jiffy? fdpEnd;
-  int sectors = 0;
-  Duration? fdpMax;
-  Duration? fdpExtMax;
-  //Duration? fdpIfRExtMax;//if inflight rest rest
-
-  bool fdpExt = false;
-  List<FtlLegal> legals = [];
-
-  Duration get dutyLength => (start != null && end != null)
-      ? end!.dateTime.difference(start!.dateTime)
-      : Duration.zero;
-  Duration get fdpLength => (fdpStart != null && fdpEnd != null)
-      ? fdpEnd!.dateTime.difference(fdpStart!.dateTime)
-      : Duration.zero;
-
-  // Duration? get rest => (dutyLength.max(Ftl.minimumrest(placeEnd)));
-  Jiffy? restends;
-
-  String? acclim;
-  String? reftime;
-
-  FtlDutyTotal? dutyTotal;
-
-  //Jiffy? report;
-  Jiffy? reportdelay1;
-  Jiffy? notification1;
-  Jiffy? reportdelay2;
-  Jiffy? notification2;
-  bool earlyStart = false;
-  bool lateFinish = false;
-  bool nightDuty = false;
-}
-
-class FtlLegal {
-  FtlLegal(
-      {required this.legalCause,
-      required this.legalCauseMsg,
-      this.legalIndex,
-      this.condition});
-  FtlLegalCause legalCause;
-  String legalCauseMsg;
-  int? legalIndex;
-  String? condition;
-}
-
-enum FtlDutyType { duty, fdp, other }
-
-class FtlDutyDetails {
-  FtlDutyDetails({
-    this.start,
-    this.end,
-    this.placeStart,
-    this.placeEnd,
-    this.type,
-    this.label,
-  });
-
-  Jiffy? start;
-  Jiffy? end;
-  DTInterval get interval => DTInterval(start!, end!);
-
-  Duration get duration => end!.dateTime.difference(start!.dateTime);
-  String? placeStart;
-  String? placeEnd;
-  FtlDutyDetailsType? type;
-  String get typeString {
-    switch (type) {
-      case FtlDutyDetailsType.flight:
-        return "FLT";
-      case FtlDutyDetailsType.dhflight:
-        return "DH-FLT";
-      case FtlDutyDetailsType.dhlimo:
-        return "DH-LIMO";
-      case FtlDutyDetailsType.sim:
-        return "SIM";
-      case FtlDutyDetailsType.standby:
-        return "STBY";
-      case FtlDutyDetailsType.reserve:
-        return "RSRV";
-      case FtlDutyDetailsType.ground:
-        return "GRND";
-
-      default:
-        return "UNK";
-    }
-  }
-
-  String? label;
-}
-
-enum FtlDutyDetailsType {
-  preflight,
-  flight,
-  postflight,
-  dhflight,
-  dhlimo,
-  ground,
-  standby,
-  reserve,
-  sim,
-//  training,
-//  other
-}
-
-class FtlDutyTotal {
-  FtlDutyTotal(
-      {required this.date, required this.dutyLength, required this.fltLength});
-  Jiffy date;
-  Duration dutyLength;
-  Duration fltLength;
-  Duration? dutylast7;
-  Duration? dutylast14;
-  Duration? dutylast28;
-  Duration? fltlast28;
-  Duration? fltyear;
-  Duration? fltlast12;
-}
-
-enum FtlLegalCause {
-  dutylast7,
-  dutylast14,
-  dutylast28,
-  fltlast28,
-  fltyear,
-  fltlast12,
-  fdpmax,
-  restfdp,
-  restrecurrent,
-  disruptive
-  //check duty length && flt length
-
-  //check fdp leength
-
-  //check rest before fdp
-  //check recurrent rest
-  //check disruptive sched
-}

+ 0 - 787
lib/ftl/view/ftl_page copy.dart.bak

@@ -1,787 +0,0 @@
-// ignore_for_file: use_build_context_synchronously
-
-import 'package:collection/collection.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:hive_flutter/hive_flutter.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
-import 'package:tp5/core/basic_page.dart';
-import 'package:tp5/core/utils.dart';
-import 'package:tp5/ftl/provider/ftl.dart';
-import 'package:tp5/ftl/widget/w_shadowbox.dart';
-import 'package:tp5/roster/api/crewlink_api.dart';
-import 'package:tp5/roster/models/duty.dart';
-import 'package:scroll_to_index/scroll_to_index.dart';
-import 'package:tp5/roster/widgets/w_airport.dart';
-import 'package:tp5/roster/widgets/w_hour.dart';
-
-class FtlPage extends ConsumerStatefulWidget {
-  const FtlPage({super.key, required this.params});
-  final FtlPageParams params;
-  @override
-  ConsumerState<ConsumerStatefulWidget> createState() => _FtlPageState();
-}
-
-class _FtlPageState extends ConsumerState<FtlPage> {
-  late String crewlinkUser;
-  late String crewlinkPass;
-  late String startdate;
-  late String enddate;
-  Map? roster;
-  List<Duty> duties = [];
-
-  String _rosterKey({String? clUser, String? start, String? end}) =>
-      "roster_${clUser ?? crewlinkUser}_${start ?? startdate}_${end ?? enddate}";
-  String fileidroster({String? clUser, String? start, String? end}) =>
-      PathTo().crewlinkFile(
-          "${_rosterKey(clUser: clUser, start: start, end: end)}.pdf");
-  // String get _rosterKey =>
-  //     "roster_${crewlinkUser}_${widget.params.datestart}_${widget.params.dateend}";
-  // String get fileidroster => PathTo().crewlinkFile("$_rosterKey.pdf");
-  final AutoScrollController _scrollCtrl = AutoScrollController();
-  late Jiffy now;
-
-  @override
-  void initState() {
-    crewlinkUser = widget.params.crewlinkuser ??
-        Hive.box("profile").get("crewlink_user") ??
-        "";
-    crewlinkPass = widget.params.crewlinkpass ??
-        Hive.box("profile").get("crewlink_pass") ??
-        "";
-
-    startdate = widget.params.datestart ??
-        Jiffy.now().toUtc().startOf(Unit.month).format(pattern: "ddMMMyy");
-    enddate = widget.params.dateend ??
-        Jiffy.now()
-            .toUtc()
-            //.add(months: 1)
-            .endOf(Unit.month)
-            .format(pattern: "ddMMMyy");
-
-    Future.delayed(Duration.zero, () async {
-      await _loadMinMax();
-      //await _loadRoster();
-      await _loadOldRoster();
-      await _ftlCalc(base: 'DJE');
-    }).then(
-        (value) => Future.delayed(const Duration(milliseconds: 200), () async {
-              _scrollToDate();
-            }));
-
-    super.initState();
-  }
-
-  bool _isLoading = false;
-
-  Future<Map?> _loadRosterOnline(
-      {String? clUser, String? start, String? end}) async {
-    //print("FtlPage: Requesting ONline roster $start -> $end");
-    if (!ref.read(crewlinkapiProvider).logged) {
-      final login = await ref
-          .read(crewlinkapiProvider)
-          .login(username: crewlinkUser, password: crewlinkPass);
-      if (login["data"]?["logged"] != true) {
-        context.showError(login["error"] ?? "Unknown error");
-        return null;
-      }
-    }
-
-    final roster = await ref.read(crewlinkapiProvider).roster(
-        start: start ?? startdate
-        //??Jiffy.now().toUtc().startOf(Unit.month).format(pattern: "ddMMMyy")
-        ,
-        end: end ?? enddate
-        //??Jiffy.now().toUtc().endOf(Unit.month).format(pattern: "ddMMMyy")
-        ,
-        fileid: fileidroster(clUser: clUser, start: start, end: end));
-
-    if (roster?["data"]?["msg"] != null) {
-      context.showError(roster?["data"]?["msg"] ?? "Unknown error");
-    }
-    if (roster["error"] == null && roster["data"] != null) {
-      if (roster["msg"] != null) context.showAlert(roster["msg"]);
-      Hive.box("crewlink")
-          .put(_rosterKey(clUser: clUser, start: start, end: end), roster);
-
-      return roster;
-    }
-
-    return null;
-  }
-
-  Future<Map?> _loadRosterOffline(
-      {String? clUser, String? start, String? end}) async {
-    //print("FtlPage: Requesting OFFline roster $start -> $end");
-
-    return Hive.box("crewlink")
-        .get(_rosterKey(clUser: clUser, start: start, end: end));
-  }
-
-  _loadRoster(
-      {String? clUser,
-      String? start,
-      String? end,
-      bool cachefirst = false}) async {
-    try {
-      ref.read(isLoadingProvider.notifier).state = true;
-
-      final rosterOffline =
-          await _loadRosterOffline(clUser: clUser, start: start, end: end);
-      if (rosterOffline?["data"]?["decoded"] is Map) {
-        print(
-            "FTL Page: found offline: $start ${rosterOffline?["data"]?["decoded"] is Map}");
-        _convertRoster(rosterOffline);
-        setState(() {});
-      }
-
-      if (rosterOffline?["data"]?["decoded"] is! Map || !cachefirst) {
-        final rosterOnline =
-            await _loadRosterOnline(clUser: clUser, start: start, end: end);
-
-        if (rosterOnline?["data"]?["decoded"] is Map) {
-          print(
-              "FTL Page: found online: $start ${rosterOnline?["data"]?["decoded"] is Map}");
-          _convertRoster(rosterOnline);
-          setState(() {});
-        } else if (rosterOffline?["data"]?["decoded"] is Map) {
-          print(
-              "FTL Page: found offline: $start ${rosterOffline?["data"]?["decoded"] is Map}");
-          _convertRoster(rosterOnline);
-          setState(() {});
-        }
-      }
-    } finally {
-      ref.read(isLoadingProvider.notifier).state = false;
-    }
-  }
-
-  _loadOldRoster() async {
-    bool exitnow = false;
-    // _rosterMax = Jiffy.now().toUtc().endOf(Unit.month).subtract(hours: 10);
-
-    Jiffy date1 = Jiffy.parse(startdate, pattern: "ddMMMyy")
-        .subtract(months: 11)
-        .startOf(Unit.day)
-        .startOf(Unit.month)
-        .max(_rosterMin ?? Jiffy.now().toUtc().startOf(Unit.month));
-    while (!exitnow) {
-      Jiffy date2 = date1
-          .endOf(Unit.month)
-          .min(_rosterMax?.endOf(Unit.day) ?? Jiffy.now().toUtc().add(days: 3));
-      if (date2.isAfter(date1) &&
-          date2.endOf(Unit.month) == date1.endOf(Unit.month)) {
-        //print("ftlpage: loadoldroster: loading ${DTInterval(date1, date2)}");
-        await _loadRoster(
-            start: date1.format(pattern: "ddMMMyy"),
-            end: date2.format(pattern: "ddMMMyy"),
-            cachefirst: date1
-                .endOf(Unit.month)
-                .isBefore(Jiffy.now().endOf(Unit.month)));
-      } else {
-        exitnow = true;
-      }
-      date1 = date1.add(months: 1).startOf(Unit.month);
-    }
-  }
-
-  String get _rosterMinMaxKey => "minmax_$crewlinkUser";
-
-  _loadMinMax() async {
-    final resoff = Hive.box("crewlink").get(_rosterMinMaxKey);
-    //print("ftlpage: resoff: $resoff");
-
-    final reson = await ref.read(crewlinkapiProvider).rosterMinMax();
-    //print("ftlpage: reson: $reson");
-    ref.read(isLoadingProvider.notifier).state = false;
-
-    dynamic res;
-
-    if (reson != null && reson["error"] == null && reson?["data"] != null) {
-      Hive.box("crewlink").put(_rosterMinMaxKey, reson["data"]);
-      res = reson["data"];
-    } else if (resoff == null) {
-      //print(reson["error"] ?? "Unknown error");
-    }
-    res = res ?? resoff;
-
-    _rosterMin =
-        Jiffy.parse(res["mindate"], pattern: "yyyy-MM-dd", isUtc: true);
-    _rosterMax =
-        Jiffy.parse(res["maxdate"], pattern: "yyyy-MM-dd", isUtc: true);
-  }
-
-  Jiffy? _rosterMin;
-  Jiffy? _rosterMax;
-
-  _scrollToDate({Jiffy? date}) async {
-    final jdate = date ?? Jiffy.now().toUtc();
-    bool found = false;
-
-    int id = 0;
-    for (Duty duty in duties) {
-      // if (duty.jdate.yMd == jdate.yMd) {
-      if (duty.jdate.isSameOrAfter(jdate)) {
-        found = true;
-        break;
-      }
-      id++;
-    }
-
-    if (found && mounted && _scrollCtrl.hasClients) {
-      // await _scrollCtrl.scrollToIndex(duties.length - 30,
-      //     duration: const Duration(milliseconds: 500),
-      //     preferPosition: AutoScrollPosition.end);
-      await _scrollCtrl.scrollToIndex(0,
-          duration: const Duration(milliseconds: 1000),
-          preferPosition: AutoScrollPosition.end);
-      await _scrollCtrl.scrollToIndex(id,
-          duration: const Duration(milliseconds: 1000),
-          preferPosition: AutoScrollPosition.end);
-    }
-  }
-
-  int i = 0;
-  _convertRoster(Map? input) {
-    roster = input;
-    final decoded = (input?["data"]?["decoded"]?["roster"] ?? {});
-    for (var date in decoded.keys) {
-      duties = duties.where((e) => e.date != date).toList();
-      var dutylist = (decoded[date] as List);
-      for (var duty in dutylist) {
-        i++;
-        duties.add(
-            Duty(date: date, type: duty["type"], data: duty["data"], order: i));
-        //print("${(duties.last).jdate.yMd} ${(duties.last).type} ${(duties.last).start?.Hm} ${(duties.last).end?.Hm}");
-      }
-    }
-  }
-
-  Ftl ftldata = Ftl.fromCrewlink(clDuties: [], base: 'DJE');
-
-  Jiffy ftlcalcdate = Jiffy.now().subtract(days: 30).startOf(Unit.month);
-
-  _ftlCalc({required String base}) async {
-    ref.read(isLoadingProvider.notifier).state = true;
-
-    ftldata = Ftl.fromCrewlink(clDuties: duties, base: base);
-    //await compute(ftlCalc, {"clDuties": duties, "base": base});
-
-    // await ftldata.calcduties(date: null);
-    await ftldata.calcduties(date: ftlcalcdate);
-
-    ref.read(isLoadingProvider.notifier).state = false;
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return BasicPage(
-      actions: [
-        ElevatedButton(
-            onPressed: _isLoading
-                ? null
-                : () async {
-                    setState(() {
-                      _isLoading = true;
-                    });
-                    await _ftlCalc(base: "DJE");
-                    setState(() {
-                      _isLoading = false;
-                    });
-                  },
-            child: const Text("calc"))
-      ],
-      title: "FTL",
-      body: ftldata.duties.isEmpty
-          ? const Text("Please wait, calculations in progress...")
-          : ListView.builder(
-              itemCount: ftldata.duties.length,
-              itemBuilder: (contexte, index) => AutoScrollTag(
-                key: ValueKey(index),
-                controller: _scrollCtrl,
-                index: index,
-                child: (ftldata.duties
-                        .elementAt(index)
-                        .start!
-                        .isSameOrAfter(ftlcalcdate))
-                    ? _getItem(contexte, index)
-                    : Container(),
-              ),
-              shrinkWrap: false,
-              controller: _scrollCtrl,
-            ),
-    );
-  }
-
-  bool _is36h(DTInterval? e, String station) {
-    if (e == null) return false;
-    final firstnight = DTInterval.fromHm(
-        apartir: Ftl.changeTz(e.start, station).toUtc(),
-        h: 23,
-        m: 0,
-        duration: const Duration(hours: 7, minutes: 59),
-        ap: station);
-    final secondnight =
-        DTInterval(firstnight.start.add(days: 1), firstnight.end.add(days: 1));
-    if (e.duration.inHours >= 36 &&
-        e.contains(firstnight) &&
-        e.contains(secondnight)) {
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  bool _is48h(DTInterval? e, String station) {
-    if (e == null) return false;
-    final localdays = DTInterval.fromHm(
-        apartir: Ftl.changeTz(e.start, station).toUtc(),
-        h: 0,
-        m: 0,
-        duration: const Duration(hours: 47, minutes: 59),
-        ap: station);
-    if (e.contains(localdays)) {
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  _showDutyInfo(int i) {
-    final duty = ftldata.duties[i];
-    //print("ftlpage: ${duty.interval}  ${duty.type}");
-    final margin =
-        ((duty.fdpExt ? duty.fdpExtMax : duty.fdpMax) ?? Duration.zero)
-            .subtract(duty.fdpLength);
-    showMaterialModalBottomSheet(
-      bounce: true,
-      context: context,
-      builder: (context) => Container(
-        padding: const EdgeInsets.all(10),
-        decoration: const BoxDecoration(
-            border: Border(top: BorderSide(width: 3, color: Colors.white70))),
-        //height: 250,
-        child: SingleChildScrollView(
-          child: Column(
-            children: [
-              const Gap(5),
-              ElevatedButton(
-                  onPressed: () {
-                    context.pop();
-                  },
-                  child: const Text(
-                    "Close",
-                    style: TextStyle(
-                        color: Colors.red, fontWeight: FontWeight.w700),
-                  )),
-              const Gap(5),
-              const Text(
-                "Duty FTL Details",
-                style: TextStyle(fontSize: 22),
-              ),
-              const Gap(10),
-              Row(
-                children: [
-                  const Text("Duty:",
-                      style: TextStyle(fontWeight: FontWeight.w800)),
-                  const Gap(20),
-                  _titleInfo(duty.start!.yMMMEd, duty.start!.Hm),
-                  const Gap(20),
-                  _titleInfo(duty.start!.yMMMEd, duty.end!.Hm)
-                ],
-              ),
-              const Gap(20),
-              if (duty.fdpStart != null)
-                Row(
-                  children: [
-                    const Text("FDP:",
-                        style: TextStyle(fontWeight: FontWeight.w800)),
-                    const Gap(20),
-                    _titleInfo("FDP Length", duty.fdpLength.tohhmm),
-                    const Gap(20),
-                    _titleInfo("Fdp Max", duty.fdpMax!.tohhmm),
-                    const Gap(20),
-                    _titleInfo("Fdp Ext Max", duty.fdpExtMax!.tohhmm),
-                    const Gap(20),
-                    _titleInfo(margin.isNegative ? "Exceeded" : "Margin",
-                        margin.abs().tohhmm,
-                        color: margin.isNegative ? Colors.red : Colors.green,
-                        sizeinfo: 12),
-                  ],
-                ),
-              const Gap(20),
-              if (duty.fdpStart != null)
-                Row(
-                  children: [
-                    const Text("Acclim:",
-                        style: TextStyle(fontWeight: FontWeight.w800)),
-                    const Gap(20),
-                    _titleInfo("Acclim type", duty.acclim),
-                    const Gap(20),
-                    _titleInfo("Ref time", duty.reftime),
-                  ],
-                ),
-              const Gap(20),
-              if (duty.fdpStart != null)
-                Row(
-                  children: [
-                    const Text("Report:",
-                        style: TextStyle(fontWeight: FontWeight.w800)),
-                    const Gap(10),
-                    _titleInfo("Report time", duty.start?.Hm ?? "----"),
-                    const Gap(10),
-                    _titleInfo(
-                        "Delayed Report1", duty.reportdelay1?.Hm ?? "----"),
-                    const Gap(10),
-                    _titleInfo(
-                        "Delayed Report1", duty.reportdelay2?.Hm ?? "----"),
-                  ],
-                ),
-              const Gap(20),
-              if (duty.fdpStart != null &&
-                  (duty.lateFinish || duty.earlyStart || duty.nightDuty))
-                Row(
-                  children: [
-                    const Text("Disruptive:",
-                        style: TextStyle(fontWeight: FontWeight.w800)),
-                    const Gap(10),
-                    if (duty.earlyStart)
-                      const Text("early start duty",
-                          style: TextStyle(
-                              fontWeight: FontWeight.w800,
-                              fontSize: 12,
-                              color: Colors.cyan)),
-                    const Gap(10),
-                    if (duty.lateFinish)
-                      const Text("late finish duty",
-                          style: TextStyle(
-                              fontWeight: FontWeight.w800,
-                              fontSize: 12,
-                              color: Colors.cyan)),
-                    const Gap(10),
-                    if (duty.nightDuty)
-                      const Text("night duty",
-                          style: TextStyle(
-                              fontWeight: FontWeight.w800,
-                              fontSize: 12,
-                              color: Colors.cyan)),
-                    const Gap(10),
-                  ],
-                ),
-              const Gap(20),
-              Row(
-                children: [
-                  SingleChildScrollView(
-                    scrollDirection: Axis.horizontal,
-                    child: Row(
-                        mainAxisSize: MainAxisSize.max,
-                        mainAxisAlignment: MainAxisAlignment.start,
-                        children: [
-                          const Text("Detail:",
-                              style: TextStyle(fontWeight: FontWeight.w800)),
-                          ...(duty.dutiesDetailsIndex.map((e) {
-                            final detail = ftldata.dutiesDetails[e];
-                            final label = (detail.placeEnd != null)
-                                ? "${detail.placeStart}-${detail.placeEnd}"
-                                : "${detail.label}";
-                            return [
-                              const Gap(20),
-                              _titleInfo(label,
-                                  "${detail.start?.Hm}-${detail.end?.Hm}",
-                                  sizeinfo: 10)
-                            ];
-                          }).flattened),
-                        ]),
-                  ),
-                ],
-              ),
-              const Gap(20),
-              Row(
-                children: [
-                  const Text("Tot duties hrs:",
-                      style: TextStyle(fontWeight: FontWeight.w800)),
-                  const Gap(10),
-                  _titleInfo("7 days",
-                      "${duty.dutyTotal?.dutylast7?.tohhmm}|${Ftl.maxdutylast7.tohhmm}",
-                      sizeinfo: 10),
-                  const Gap(5),
-                  _titleInfo("14 days",
-                      "${duty.dutyTotal?.dutylast14?.tohhmm}|${Ftl.maxdutylast14.tohhmm}",
-                      sizeinfo: 10),
-                  const Gap(5),
-                  _titleInfo("28 days",
-                      "${duty.dutyTotal?.dutylast28?.tohhmm}|${Ftl.maxdutylast28.tohhmm}",
-                      sizeinfo: 10),
-                ],
-              ),
-              const Gap(20),
-              Row(
-                children: [
-                  const Text("Tot Flt hrs:",
-                      style: TextStyle(fontWeight: FontWeight.w800)),
-                  const Gap(10),
-                  _titleInfo("28 days",
-                      "${duty.dutyTotal?.fltlast28?.tohhmm}|${Ftl.maxfltlast28.tohhmm}",
-                      sizeinfo: 10),
-                  const Gap(5),
-                  _titleInfo("12 months",
-                      "${duty.dutyTotal?.fltlast12?.tohhmm}|${Ftl.maxfltlast12.tohhmm}",
-                      sizeinfo: 10),
-                  const Gap(5),
-                  _titleInfo("year",
-                      "${duty.dutyTotal?.fltyear?.tohhmm}|${Ftl.maxfltlastyear.tohhmm}",
-                      sizeinfo: 10),
-                ],
-              ),
-            ],
-          ),
-        ),
-      ),
-    );
-  }
-
-  _titleInfo(String? title, String? info,
-          {double sizetitle = 10,
-          double sizeinfo = 16,
-          Color color = Colors.blueGrey}) =>
-      Column(
-        children: [
-          Text(
-            title ?? "---",
-            style: TextStyle(color: Colors.grey, fontSize: sizetitle),
-          ),
-          Text(info ?? "---",
-              style: TextStyle(color: color, fontSize: sizeinfo)),
-        ],
-      );
-
-  Widget _getItem(BuildContext _, int i) {
-    final duty = ftldata.duties.elementAt(i);
-    final lastduty = i == 0 ? null : ftldata.duties.elementAt(i - 1);
-
-    final rest =
-        lastduty == null ? null : DTInterval(lastduty.end!, duty.start!);
-
-    Color legal;
-    if (duty.legals.isEmpty) {
-      legal = Colors.green[900]!;
-    } else if (duty.legals.every((e) => (e.condition ?? "") != "")) {
-      legal = Colors.amber;
-    } else {
-      legal = Colors.red;
-    }
-
-    return Column(
-      children: [
-        if (lastduty != null)
-          WShadowbox(
-              child: Column(children: [
-            Container(
-              decoration: const BoxDecoration(
-                color: Color.fromARGB(255, 8, 9, 9),
-                border: Border(top: BorderSide(width: 5)),
-                borderRadius: BorderRadius.all(Radius.circular(10.0)),
-              ),
-              padding: const EdgeInsets.all(5),
-              // width: double.infinity,
-              child: Row(
-                mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                children: [
-                  Column(
-                    children: [
-                      _titleInfo("Rest",
-                          "${(rest?.duration.inDays ?? 0)} days, ${(rest?.duration.inHours ?? 0) % 24} hours, ${(rest?.duration.inMinutes ?? 0) % 60} minutes",
-                          sizeinfo: 10),
-                    ],
-                  ),
-                  Column(children: [
-                    if (_is48h(rest, lastduty.placeEnd ?? "UTC"))
-                      Container(
-                          color: Colors.teal[900],
-                          padding: const EdgeInsets.all(5),
-                          child: Text(
-                            "48h with 2 local days",
-                            style: TextStyle(
-                                color: Colors.yellow[600]!,
-                                fontSize: 11,
-                                fontWeight: FontWeight.w600),
-                          )),
-                    if (_is36h(rest, lastduty.placeEnd ?? "UTC"))
-                      Container(
-                          color: Colors.teal[800],
-                          padding: const EdgeInsets.all(5),
-                          child: Text(
-                            "36h with 2 local nights",
-                            style: TextStyle(
-                                color: Colors.yellow[500]!,
-                                fontSize: 11,
-                                fontWeight: FontWeight.w600),
-                          ))
-                  ]),
-                ],
-              ),
-            )
-          ])),
-        InkWell(
-          onTap: () => _showDutyInfo(i),
-          child: WShadowbox(
-            child: Column(
-              children: [
-                Container(
-                  decoration: BoxDecoration(
-                    color: const Color.fromARGB(255, 1, 45, 47),
-                    border: Border(top: BorderSide(width: 5, color: legal)),
-                    borderRadius:
-                        const BorderRadius.vertical(top: Radius.circular(10.0)),
-                  ),
-                  padding: const EdgeInsets.symmetric(horizontal: 20),
-                  // width: double.infinity,
-                  child: Row(
-                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                    children: [
-                      Text(
-                        "${duty.start?.format(pattern: "dd MMM'yy")}",
-                        style: const TextStyle(color: Colors.white54),
-                      ),
-                      if (duty.start != null) WHour(jiffy: duty.start!),
-                    ],
-                  ),
-                ),
-
-                Container(
-                  width: double.infinity,
-                  padding: const EdgeInsets.only(left: 20, right: 10),
-                  decoration: const BoxDecoration(
-                    color: Colors.black,
-                  ),
-                  child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.start,
-                      children: duty.legals
-                          .map((e) => Text(
-                                "+ ${e.condition ?? ""} ${e.legalCauseMsg}",
-                                style: const TextStyle(fontSize: 10),
-                              ))
-                          .toList()),
-                ),
-
-                //details
-
-                ...duty.dutiesDetailsIndex.map((index) {
-                  final FtlDutyDetails dutydetail =
-                      ftldata.dutiesDetails[index];
-                  return Row(
-                    children: [
-                      const Gap(40),
-                      SizedBox(
-                        width: 50,
-                        child: Row(children: [
-                          Text(
-                            dutydetail.typeString,
-                            style: TextStyle(
-                              backgroundColor: Colors.blueGrey[900],
-                              color: Colors.yellow,
-                              fontSize: 10,
-                              fontWeight: FontWeight.w600,
-                            ),
-                          )
-                        ]),
-                      ),
-                      SizedBox(
-                        width: 60,
-                        child: Row(
-                          children: [
-                            WHour(
-                              jiffy: dutydetail.start!,
-                              size: 12,
-                              color: Colors.white38,
-                            ),
-                            const Gap(5),
-                            WHour(
-                              jiffy: dutydetail.end!,
-                              size: 12,
-                              color: Colors.white38,
-                            ),
-                          ],
-                        ),
-                      ),
-                      SizedBox(
-                        // width: 80,
-                        child: Row(children: [
-                          const Gap(10),
-                          if (dutydetail.placeStart != null)
-                            WAirport(iata: dutydetail.placeStart!, size: 12),
-                          if (dutydetail.placeEnd != null) ...[
-                            const Icon(Icons.arrow_right_alt, size: 9),
-                            WAirport(iata: dutydetail.placeEnd!, size: 12)
-                          ] else if ((dutydetail.label ?? "") != "")
-                            Text(" (${dutydetail.label})",
-                                style: const TextStyle(
-                                    color: Colors.white54,
-                                    fontSize: 10,
-                                    letterSpacing: 2),
-                                overflow: TextOverflow.ellipsis),
-                        ]),
-                      ),
-                    ],
-                  );
-                }),
-
-                Container(
-                  decoration: const BoxDecoration(
-                    color: Color.fromARGB(255, 1, 45, 47),
-                    borderRadius:
-                        BorderRadius.vertical(bottom: Radius.circular(10.0)),
-                  ),
-                  padding: const EdgeInsets.symmetric(horizontal: 20),
-                  // width: double.infinity,
-                  child: Row(
-                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                    children: [
-                      if (duty.end != null && duty.start != null)
-                        _titleInfo(
-                            "Duty length",
-                            duty.end!.dateTime
-                                .difference(duty.start!.dateTime)
-                                .tohhmm),
-                      const Row(children: []),
-                      Column(
-                        mainAxisSize: MainAxisSize.min,
-                        children: [
-                          Text(
-                            (duty.end?.yMMMd != duty.start?.yMMMd)
-                                ? "${duty.end?.format(pattern: "dd MMM")}"
-                                : "",
-                            style: const TextStyle(
-                                color: Colors.white54, fontSize: 12),
-                          ),
-                          if (duty.end != null) WHour(jiffy: duty.end!),
-                        ],
-                      ),
-                    ],
-                  ),
-                ),
-              ],
-            ),
-          ),
-        ),
-      ],
-    );
-  }
-}
-
-class FtlPageParams {
-  const FtlPageParams({
-    this.dateend,
-    this.datestart,
-    this.crewlinkuser,
-    this.crewlinkpass,
-  });
-
-  final String? dateend;
-  final String? datestart;
-  final String? crewlinkuser;
-  final String? crewlinkpass;
-}

+ 0 - 441
lib/lido/api_lido4d copy.dart.bak

@@ -1,441 +0,0 @@
-//import 'package:html';
-
-import 'dart:convert';
-import 'dart:developer';
-
-import 'package:flutter/foundation.dart';
-import 'package:intl/intl.dart';
-
-class ApiLido4d {
-  //static const url = "https://tar.lido.aero";
-  static const url =
-      kIsWeb ? "https://proxy.fares.cyou" : "https://tar.lido.aero";
-  //static const url = "https://proxy.fares.cyou";
-  static const realurl = "https://tar.lido.aero";
-  ApiLido4d({this.username = "", this.password = ""});
-  bool get logged => cookieMap.isNotEmpty;
-  String username;
-  String password;
-  String get cookie =>
-      "${cookieMap.keys.fold("", (t, e) => (t == "") ? "$e=${cookieMap[e]}" : "$t; $e=${cookieMap[e]}")};SameSite=None; Secure";
-
-  Map cookieMap = {};
-  Map get headers => {
-        "Accept": "application/vnd.lsy.lido.lcb.v1.hal+json",
-        "Accept-Encoding": "gzip, deflate, br",
-        "Accept-Language": "en",
-        "Connection": "keep-alive",
-        "Content-Type": "application/json;charset=UTF-8",
-        //"Host": Uri.parse(realurl).host,
-        "Origin": Uri.parse(realurl).host,
-        //"sec-ch-ua":'" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"',
-        // "sec-ch-ua-mobile": "?0",
-        // "sec-ch-ua-platform": "Windows",
-        // "Sec-Fetch-Dest": "empty",
-        // "Sec-Fetch-Mode": "cors",
-        // "Sec-Fetch-Site": "same-origin",
-        "User-Agent":
-            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
-        "X-lido-applicationId": "lido-lcb",
-        "X-lido-clientId": "lido-lcb-web",
-        "X-lido-customerId": "TAR",
-        "X-lido-operatingAirline": "",
-        "X-lido-timeStamp": DateTime.now().toUtc().toIso8601String(),
-        "X-lido-traceId": "0c497133-2a92-45a0-8ffe-a03c77852201",
-        "cookie": "SERVERID=docker2; ${cookie}",
-        "X-lido-csrf": cookieMap["lido_csrf"] ?? "",
-      };
-  Future logout() async {
-    var response = await post(Uri.parse('${url}USR/actionLogout.jsp'),
-        body: {"Cookie": cookie});
-  }
-
-  Future login() async {
-    try {
-      var response = await get(
-        Uri.parse(
-            '$url/lido/las/login.jsp?DESMON_RESULT_PAGE=$realurl/briefing//'),
-      );
-      cookieMap.addAll(_getcookies(response.headers["set-cookie"] ??
-          response.headers["_set-cookie"] ??
-          ""));
-      //print(response.headers);
-      response = await post(
-          Uri.parse('$url/lido/las/dwr/call/plaincall/LoginBean.login.dwr'),
-          body: {
-            "callCount": "1",
-            "windowName": "DWR-5F9BFD0ECADDCF42109A9C1099F4B49B",
-            "c0-scriptName": "LoginBean",
-            "c0-methodName": "login",
-            "c0-id": "0",
-            "c0-param0": "boolean:false",
-            "c0-param1": "boolean:false",
-            "c0-param2": "string:$username",
-            "c0-param3": "string:$password",
-            "c0-param4": "string:",
-            "c0-param5": "string:LIDO",
-            "c0-param6": "string:en",
-            "batchId": "1",
-            "page":
-                "/lido/las/login.jsp?DESMON_RESULT_PAGE=$realurl/briefing&DESMON_CODE=LAS_002&DESMON_LANG=en",
-            "httpSessionId": "",
-            "scriptSessionId": "C63C650BEED5A9D544876B2756E3ECF0"
-          },
-          headers: {});
-      cookieMap.addAll(_getcookies(response.headers["set-cookie"] ?? ""));
-      //log("$username $password ${response.statusCode} ${response.body}");
-
-      final message = RegExp(r'(?<=errorMessage2:")(.+)(?=",)')
-              .firstMatch(response.body)
-              ?.group(0) ??
-          RegExp(r'(?<=errorMessage1:")(.+)(?=",)')
-              .firstMatch(response.body)
-              ?.group(0);
-
-      final changepass = RegExp(r'(?<=forcePasswdChange:)(.+)(?=,)')
-              .firstMatch(response.body)
-              ?.group(0) ==
-          "true";
-
-      cookieMap = (message != null) ? {} : cookieMap;
-      log("api lido 4d login $username $password ${response.statusCode} logged:$logged msg:${message}");
-
-      return {
-        'error': logged ? null : message,
-        'data': {"logged": logged},
-        'meta': {
-          "changepass": changepass,
-          "user": username,
-          "pass": password,
-          "cookie": cookieMap
-        }
-      };
-    } catch (e) {
-      return {
-        'error': e.toString(),
-        'data': {"logged": false},
-        'meta': {"user": username, "pass": password, "cookie": null}
-      };
-    }
-  }
-
-  Future list(
-      {String date = "",
-      String dep = "",
-      String des = "",
-      String al = "",
-      String fnum = ""}) async {
-    try {
-      final startdate = (date == "")
-          ? DateTime.now()
-              .subtract(const Duration(hours: 36))
-              .toUtc()
-              .millisecondsSinceEpoch
-          : DateTime.parse(date).millisecondsSinceEpoch;
-      final endate = startdate + (1000 * 60 * 60 * 36);
-      var response = await get(
-          Uri.parse(
-                  "$url/lido/lcb/ui/flights?page=0&size=100&startDateTime=1653148128544&endDateTime=1653191328544")
-              .replace(queryParameters: {
-            "page": "0",
-            "size": "1000",
-            "startDateTime": startdate.toString(),
-            "endDateTime": endate.toString(),
-            ...(al != "" ? {"commAirLine": al} : {}),
-            ...(fnum != "" ? {"flightNumber": fnum} : {}),
-            ...(dep != "" ? {"departure": dep} : {}),
-            ...(des != "" ? {"destination": des} : {}),
-          }),
-          headers: {"X-lido-businessId": "SearchFlights", ...headers});
-      //log(response.headers.toString());
-      Map decodedresponse;
-
-      // print("${response.body}");
-      try {
-        decodedresponse = json.decode(response.body) ?? {};
-      } catch (e) {
-        decodedresponse = {
-          "body": response.body,
-          "response": response.statusCode
-        };
-      }
-      String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
-              ?["message"] ??
-          decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
-          ((response.statusCode == 200) ? null : "ERR");
-
-      /*
-      print(((decodedresponse["totalElements"] ?? 0) > 0
-          ? decodedresponse["content"].fold([], (t, e) {
-              t.add(e["leg"]);
-              return t;
-            })
-          : []));
-      */
-
-      return {
-        'error': message,
-        'data': (message == null) ? decodedresponse["content"] : null,
-        'meta': {
-          "legs": (decodedresponse["totalElements"] ?? 0) > 0
-              ? decodedresponse["content"].fold([], (t, e) {
-                  t.add(e["leg"]["legidentifier"]);
-                  return t;
-                })
-              : [],
-          "user": username,
-          "pass": password,
-          "nb": decodedresponse["totalElements"] ?? 0,
-          "cookie": cookieMap
-        }
-      };
-    } catch (e) {
-      return {'error': e.toString(), 'data': {}, 'meta': {}};
-    }
-  }
-
-  Future ofp(
-      {String al = "",
-      String fnum = "",
-      String date = "",
-      String origin = "",
-      String dep = '',
-      String des = ''}) async {
-    try {
-      final dateoforigin =
-          DateTime.parse("${(origin == "") ? date : origin}T00:00:00Z")
-              .millisecondsSinceEpoch;
-      String brieflink = "";
-      String legid = "";
-      if (origin == "") {
-        final res = await list(
-            date: date != "" ? date : origin,
-            al: al,
-            fnum: fnum,
-            dep: dep,
-            des: des);
-        if (res["error"] != null) {
-          return res;
-        } else if (res["data"]?[0]?["_links"]?["self"]?["href"] != null) {
-          //(res["data"]?[0]?["_links"]?["self"]?["href"] ?? "").toString());
-          brieflink = res["data"]?[0]?["_links"]?["self"]?["href"];
-          legid = res["data"]?[0]?["leg"]?["legidentifier"];
-        } else {
-          // no link found
-          return {
-            'error': "Can't find the requested OFP.",
-            'data': res["data"],
-            'meta': {"user": username, "pass": password, "cookie": cookieMap}
-          };
-        }
-      } else {
-        legid =
-            '$al.$fnum.${DateFormat("ddLLLy").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}.$dep.$des.';
-
-        brieflink = "$url/lido/lcb/ui/$legid/briefing";
-      }
-
-      var response = await put(Uri.parse(brieflink),
-          headers: {
-            "X-lido-businessId": 'SearchBP',
-            ...headers,
-          },
-          //body: json.encode(({"commercialAirline": al,"flightNumber": fnum,"operationalSuffix": "","date": dateoforigin.toString()
-
-          body: json.encode(({
-            "categories": [
-              "APLI",
-              "APTDXML",
-              "SOFP",
-              "CDA",
-              "RADAR",
-              "OFPDLK",
-              "ATSXML",
-              "REGWXXML",
-              "WXSIGWX",
-              "SIGWXROUTE",
-              "VAATCA",
-              "ASPDXML",
-              "NOTAMXML",
-              "OTS",
-              "SFC",
-              "WINDDATA",
-              "RAIMXML",
-              "ARPTWXXML",
-              "SOFPINFO",
-              "IWFRXML",
-              "OFPNLXML",
-              "VERTPROF",
-              "SOFPSUM",
-              "RAIM",
-              "UAD",
-              "DISMAP",
-              "WXSATWX"
-            ],
-          })));
-      //log(response.body);
-
-      Map decodedresponse;
-      try {
-        decodedresponse = (json.decode(response.body) ?? {});
-      } catch (e) {
-        decodedresponse = {};
-      }
-      String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
-              ?["message"] ??
-          decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
-          ((response.statusCode == 201) ? null : "ERR");
-
-      return {
-        'error': (message == null) ? null : message,
-        'data': decodedresponse,
-        'meta': {
-          "user": username,
-          "pass": password,
-          "cookie": cookieMap,
-          "legid": legid
-        }
-      };
-    } catch (e) {
-      return {'error': e.toString(), 'data': {}, 'meta': {}};
-    }
-  }
-
-  Future ofppdf(
-      {String al = "",
-      String fnum = "",
-      String date = "",
-      String origin = "",
-      String dep = '',
-      String des = ''}) async {
-    try {
-      final dateoforigin =
-          DateTime.parse("${(origin == "") ? date : origin}T00:00:00Z")
-              .millisecondsSinceEpoch;
-
-      String legid = "";
-      if (origin == "") {
-        final res = await list(
-            date: date != "" ? date : origin,
-            al: al,
-            fnum: fnum,
-            dep: dep,
-            des: des);
-        if (res["error"] != null) {
-          log("lido4d: ofps listed, ${res["error"]}");
-          return res;
-        } else if (res["data"]?[0]?["_links"]?["self"]?["href"] != null) {
-          legid = res["data"]?[0]?["leg"]?["legidentifier"];
-        } else {
-          log("lido4d: no link found");
-          // no link found
-          return {
-            'error': "Can't find the requested OFP.",
-            'data': res["data"],
-            'meta': {"user": username, "pass": password, "cookie": cookieMap}
-          };
-        }
-      } else {
-        legid =
-            '$al.$fnum.${DateFormat("ddLLLy").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}.$dep.$des.';
-      }
-
-      var response = await put(
-          Uri.parse("$url/lido/lcb/ui/briefing/multi/print?force=true"),
-          headers: {
-            "Accept":
-                "application/vnd.lsy.lido.lcb.v1.hal+json,application/pdf",
-            //"Accept-Encoding": "gzip, deflate, br",
-            "Accept-Language": "en",
-            "Connection": "keep-alive",
-            "Content-Type": "application/json;charset=UTF-8",
-            "Cookie": cookie,
-            //"host": Uri.parse(realurl).host,
-            "Origin": Uri.parse(realurl).host,
-            // "sec-ch-ua":'" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"',
-
-            "User-Agent":
-                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36",
-            "X-lido-applicationId": "lido-lcb",
-            "X-lido-businessId": "printBP",
-            "X-lido-clientId": "lido-lcb-web",
-            "X-lido-csrf": cookieMap["lido_csrf"],
-            "X-lido-customerId": "TAR",
-            "X-lido-operatingAirline": "TU",
-            "X-lido-timeStamp": "2022-05-25T06:29:56.659Z",
-            "X-lido-traceId": "3cbab7e0-56ca-49ec-b158-8899c0d3bbbb",
-          },
-          body: json.encode({
-            "legIdentifiers": [legid],
-            "categories": [
-              "OFP",
-              "ATS",
-              "CREWINFO",
-              "DISP",
-              "IWFR",
-              "NOTAM",
-              "UAD",
-              "WXSIGWX",
-              "VERTPROF",
-              "RAIM",
-              "DMS",
-              "WXNOTAM",
-              "ABD",
-              "SIGWXROUTE",
-              //"WXSATWX"
-            ],
-            "merge": false,
-            "quickprint": false,
-            "weatherDataRequired": false,
-          }));
-
-      Map decodedresponse;
-      try {
-        //decodedresponse = (json.decode(response.body) ?? {});
-        decodedresponse = {};
-      } catch (e) {
-        decodedresponse = {};
-      }
-      String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
-              ?["message"] ??
-          decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
-          ((response.statusCode == 201) ? null : "ERR");
-      //log("xx ${response.headers}");
-      //final id ="${DateFormat("yyyyMMdd").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}_${dep}_${des}_$al$fnum";
-      final id = Lido4dService.filename(
-          al: al, fnum: fnum, dep: dep, des: des, origin: origin, date: date);
-      var filepdf =
-          await Io.getFile(response, filename: "$id.pdf", folder: "ofps");
-
-      return {
-        'error': (message == null) ? null : message,
-        'data': (message == null)
-            ? {"file": filepdf["location"], "bytes": filepdf["bytes"], "id": id}
-            : null,
-        'meta': {"user": username, "pass": password, "cookie": cookieMap}
-      };
-    } catch (e) {
-      return {'error': e.toString(), 'data': {}, 'meta': {}};
-    }
-  }
-
-  Map<String, String> _getcookies(String cookiesData,
-      {List<String> vars = const [
-        "lido_auth",
-        "lido_csrf",
-        "JSESSIONID",
-        "SERVERID"
-      ]}) {
-    Map<String, String> cookies = {};
-    for (var title in vars) {
-      if (cookiesData.contains(title)) {
-        List at =
-            (RegExp(r'(' + title + ')(.*?)[^;]+').stringMatch(cookiesData) ??
-                    "")
-                .split('=');
-        cookies[title] = at[1];
-      }
-    }
-    return cookies;
-  }
-}

+ 1 - 1
lib/lido/lido_api.dart

@@ -64,7 +64,7 @@ class LidoApi {
   }
 
   bool credSaved() {
-    return (Hive.box("profile").get("lido_user", defaultValue: "") != null) &&
+    return (Hive.box("profile").get("lido_user", defaultValue: "") != "") &&
         (Hive.box("profile").get("lido_pass", defaultValue: "") != "");
   }
 

+ 0 - 1
lib/onboarding/onboarding.dart

@@ -1,2 +1 @@
 export 'api/onboarding_repository.dart';
-export 'view/verification_page.dart';

+ 0 - 154
lib/onboarding/view/verification_page.dart

@@ -1,154 +0,0 @@
-// ignore_for_file: use_build_context_synchronously
-
-import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:go_router/go_router.dart';
-import 'package:tp5/core/core.dart';
-import 'package:tp5/onboarding/onboarding.dart';
-
-class VerificationPageParams {
-  const VerificationPageParams({
-    required this.email,
-    required this.password,
-    required this.username,
-  });
-
-  final String email;
-  final String password;
-  final String username;
-}
-
-class VerificationPage extends ConsumerStatefulWidget {
-  const VerificationPage({required this.params, super.key});
-
-  final VerificationPageParams params;
-
-  @override
-  ConsumerState<VerificationPage> createState() => _VerificationPageState();
-}
-
-class _VerificationPageState extends ConsumerState<VerificationPage> {
-  final _formKey = GlobalKey<FormState>();
-  AutovalidateMode? _autovalidateMode;
-  bool _isSubmitting = false;
-
-  final _codeCtrl = TextEditingController();
-
-  Future<void> _resendCode() async {
-    try {
-      setState(() {
-        _isSubmitting = true;
-      });
-
-      await ref.read(onboardingRepositoryProvider).signUp(
-            email: widget.params.email,
-            password: widget.params.password,
-            username: widget.params.username,
-          );
-
-      if (mounted) {
-        context.showAlert('Code resent');
-      }
-    } catch (e) {
-      context.showAlert(e.toString());
-    }
-
-    setState(() {
-      _isSubmitting = false;
-    });
-  }
-
-  Future<void> _verify() async {
-    try {
-      setState(() {
-        _isSubmitting = true;
-      });
-
-      await ref.read(onboardingRepositoryProvider).verifyCode(
-            email: widget.params.email,
-            code: _codeCtrl.text,
-          );
-
-      if (mounted) {
-        context.showAlert('Successfully signed up');
-
-        context.go('/');
-      }
-    } catch (e) {
-      setState(() {
-        _isSubmitting = false;
-      });
-
-      context.showAlert(e.toString());
-    }
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: const Text('Verify Account'),
-      ),
-      body: Padding(
-        padding: const EdgeInsets.symmetric(
-          horizontal: 20,
-          vertical: 30,
-        ),
-        child: Form(
-          key: _formKey,
-          autovalidateMode: _autovalidateMode,
-          child: Column(
-            children: [
-              Text(
-                'Enter the verification code sent '
-                'to your email address ${widget.params.email}',
-              ),
-              const SizedBox(height: 30),
-              TextFormField(
-                controller: _codeCtrl,
-                readOnly: _isSubmitting,
-                decoration: const InputDecoration(
-                  labelText: 'Verification code',
-                  border: OutlineInputBorder(),
-                ),
-                validator: (value) {
-                  if (value == null || value.isEmpty) {
-                    return 'Missing the verification code';
-                  }
-
-                  return null;
-                },
-              ),
-              const SizedBox(height: 20),
-              SizedBox(
-                width: double.infinity,
-                child: OutlinedButton(
-                  onPressed: _isSubmitting ? null : _resendCode,
-                  child: const Text('Resend Code'),
-                ),
-              ),
-              const SizedBox(height: 10),
-              SizedBox(
-                width: double.infinity,
-                child: FilledButton(
-                  onPressed: _isSubmitting
-                      ? null
-                      : () {
-                          if (_formKey.currentState!.validate()) {
-                            _verify();
-                          } else {
-                            setState(() {
-                              _autovalidateMode = AutovalidateMode.always;
-                            });
-                          }
-                        },
-                  child: const Text('Submit'),
-                ),
-              ),
-            ],
-          ),
-        ),
-      ),
-    );
-  }
-}

+ 6 - 0
lib/roster/api/crewlink_api.dart

@@ -7,6 +7,7 @@ import 'package:dio/io.dart';
 import 'package:dio_cookie_manager/dio_cookie_manager.dart';
 import 'package:cookie_jar/cookie_jar.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:hive_flutter/hive_flutter.dart';
 // import 'package:flutter_riverpod/flutter_riverpod.dart';
 import '../api/dio_exceptions.dart';
 import 'package:html/dom.dart' as dom;
@@ -637,6 +638,11 @@ class CrewlinkApi {
     };
   }
 
+  bool credSaved() {
+    return (Hive.box("profile").get("crewlink_user", defaultValue: "") != "") &&
+        (Hive.box("profile").get("crewlink_pass", defaultValue: "") != "");
+  }
+
   String storedusername = "";
   String storedpassword = "";
   bool get logged => storedusername != "" && storedpassword != "";

+ 0 - 454
lib/roster/view/roster_page copy.dart.bak

@@ -1,454 +0,0 @@
-// ignore_for_file: use_build_context_synchronously
-
-import 'dart:developer';
-import 'dart:io';
-
-import 'package:awesome_dialog/awesome_dialog.dart';
-import 'package:collection/collection.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:hive_flutter/hive_flutter.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:scroll_to_index/scroll_to_index.dart';
-
-import 'package:tp5/core/basic_page.dart';
-import 'package:tp5/core/core.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/view/crewlist_page.dart';
-import 'package:tp5/roster/widgets/w_day.dart';
-import 'package:tp5/roster/widgets/w_duty.dart';
-import 'package:tp5/roster/widgets/w_horizontal_month.dart';
-
-class RosterPage extends ConsumerStatefulWidget {
-  const RosterPage({required this.params, super.key});
-
-  final RosterPageParams params;
-  @override
-  ConsumerState<ConsumerStatefulWidget> createState() => _RosterPageState();
-}
-
-class _RosterPageState extends ConsumerState<RosterPage> {
-  late String crewlinkUser;
-  late String crewlinkPass;
-  Map? roster;
-  List<Duty> duties = [];
-
-  List<Jiffy> get rostermonths => duties
-      .fold(
-          <Jiffy>[],
-          (List<Jiffy> p, Duty e) => [
-                ...p,
-                if (!p
-                    .map((Jiffy j) => j.format(pattern: "MMMyy"))
-                    .contains(e.jdate.format(pattern: "MMMyy")))
-                  e.jdate
-              ])
-      .where((Jiffy e) => (duties
-              .map((Duty d) => d.jdate.yMd)
-              .contains(e.startOf(Unit.month).yMd) &&
-          duties
-              .map((Duty d) => d.jdate.yMd)
-              .contains(e.endOf(Unit.month).yMd)))
-      .toList();
-
-  String get _rosterKey =>
-      "roster_${crewlinkUser}_${widget.params.datestart}_${widget.params.dateend}";
-  String get _rosterMinMaxKey => "minmax_$crewlinkUser";
-  String get fileidroster => PathTo().crewlinkFile("$_rosterKey.pdf");
-  String get fileidnotif => PathTo().crewlinkFile("notif_$crewlinkUser.pdf");
-
-  final AutoScrollController _scrollCtrl = AutoScrollController();
-  late Jiffy now;
-
-  @override
-  void initState() {
-    // getusername & pass
-    // crewlinkPass = Hive.box("profile").get("crewlink_pass");
-
-    crewlinkUser = widget.params.crewlinkuser ??
-        Hive.box("profile").get("crewlink_user") ??
-        "";
-    crewlinkPass = widget.params.crewlinkpass ??
-        Hive.box("profile").get("crewlink_pass") ??
-        "";
-    Future.delayed(Duration.zero, () => _loadRoster());
-
-    super.initState();
-  }
-
-  Future<Map?> _loadRosterOnline() async {
-    if (!ref.read(crewlinkapiProvider).logged) {
-      final login = await ref
-          .read(crewlinkapiProvider)
-          .login(username: crewlinkUser, password: crewlinkPass);
-      if (login["data"]?["logged"] != true) {
-        context.showError(login["error"] ?? "Unknown error");
-        return null;
-      }
-    }
-
-    final roster = await ref.read(crewlinkapiProvider).roster(
-        start: widget.params.datestart ??
-            Jiffy.now().toUtc().startOf(Unit.month).format(pattern: "ddMMMyy"),
-        end: widget.params.dateend ??
-            Jiffy.now().toUtc().endOf(Unit.month).format(pattern: "ddMMMyy"),
-        fileid: fileidroster);
-
-    if (roster?["data"]?["msg"] != null) {
-      context.showError(roster?["data"]?["msg"] ?? "Unknown error");
-    }
-    if (roster["error"] == null && roster["data"] != null) {
-      if (roster["msg"] != null) context.showAlert(roster["msg"]);
-      Hive.box("crewlink").put(_rosterKey, roster);
-
-      return roster;
-    }
-
-    return null;
-  }
-
-  Future<Map?> _loadRosterOffline() async {
-    return Hive.box("crewlink").get(_rosterKey);
-  }
-
-  _loadRoster() async {
-    try {
-      ref.read(isLoadingProvider.notifier).state = true;
-      final rosterOffline = await _loadRosterOffline();
-      if (rosterOffline != null && mounted) {
-        _convertRoster(rosterOffline);
-        setState(() {});
-        _scrollToDate();
-      }
-      final rosterOnline = await _loadRosterOnline();
-
-      if (rosterOnline != null && mounted) {
-        _convertRoster(rosterOnline);
-        setState(() {});
-
-        _scrollToDate();
-      }
-    } finally {
-      ref.read(isLoadingProvider.notifier).state = false;
-    }
-  }
-
-  _scrollToDate({Jiffy? date}) {
-    final jdate = date ?? Jiffy.now().toUtc();
-    bool found = false;
-    int id = 0;
-    for (Duty duty in duties) {
-      if (duty.jdate.yMd == jdate.yMd) {
-        found = true;
-        break;
-      }
-      id++;
-    }
-    Future.delayed(const Duration(milliseconds: 100)).then((value) {
-      if (found && mounted && _scrollCtrl.hasClients) {
-        _scrollCtrl.scrollToIndex(id,
-            duration: const Duration(milliseconds: 1300),
-            preferPosition: AutoScrollPosition.begin);
-      }
-    });
-  }
-
-  _convertRoster(Map? input) {
-    roster = input;
-    int i = 0;
-    duties.clear();
-    final decoded = (input?["data"]?["decoded"]?["roster"] ?? {});
-    for (var date in decoded.keys) {
-      var dutylist = (decoded[date] as List);
-      for (var duty in dutylist) {
-        i++;
-        duties.add(
-            Duty(date: date, type: duty["type"], data: duty["data"], order: i));
-        // print(
-        //     "${(duties.last).jdate.yMd} ${(duties.last).type} ${(duties.last).start?.Hm} ${(duties.last).end?.Hm}");
-      }
-    }
-  }
-
-  final bottomnavstyle = ElevatedButton.styleFrom(
-      shape: RoundedRectangleBorder(
-        borderRadius: BorderRadius.circular(5.0),
-      ),
-      backgroundColor:
-          const Color.fromARGB(255, 0, 36, 53) //elevated btton background color
-      );
-  @override
-  Widget build(BuildContext context) {
-    now = ref.watch(clockProvider);
-
-    return BasicPage(
-      actions: [
-        IconButton(
-            onPressed: () => context.push("/crewlink/settings"),
-            icon: const Icon(Icons.settings)),
-        const Gap(10)
-      ],
-      bottomNavigationBar: Container(
-        padding: const EdgeInsets.all(8),
-        // color: Colors.black,
-        decoration: BoxDecoration(
-            gradient: LinearGradient(
-          begin: Alignment.topCenter,
-          end: Alignment.bottomCenter,
-          colors: [
-            Colors.grey[700]!,
-            Colors.black,
-          ],
-        )),
-        child: Row(
-          mainAxisAlignment: MainAxisAlignment.spaceAround,
-          children: [
-            ElevatedButton.icon(
-              onPressed: () {
-                _showMonths(context);
-              },
-              icon: const Icon(
-                  Icons.calendar_month), //icon data for elevated button
-              label: const Text("Change\nMonth"), //label text
-              style: bottomnavstyle,
-            ),
-            const Gap(10),
-            ElevatedButton.icon(
-              onPressed: () {
-                _showPdf(context);
-              },
-              icon: Image.asset(
-                'assets/pdficon.png',
-                width: 28,
-              ), //icon data for elevated button
-              label: const Text("Roster\n  PDF"), //label text
-              style: bottomnavstyle,
-            ),
-          ],
-        ),
-      ),
-      title: "CrewLink / Roster",
-      body: ListView.builder(
-        itemCount: duties.length,
-        itemBuilder: (_, index) => AutoScrollTag(
-            key: ValueKey(index),
-            controller: _scrollCtrl,
-            index: index,
-            child: _getItem(_, index)),
-        shrinkWrap: false,
-        controller: _scrollCtrl,
-      ),
-    );
-  }
-
-  Widget _getItem(BuildContext ctx, int i) {
-    final duty = duties.elementAt(i);
-    Duty? firstitem =
-        duties.firstWhereOrNull((Duty el) => el.date == duty.date);
-    bool isfirstitem = false;
-    if (firstitem != null &&
-        firstitem.type == duty.type &&
-        firstitem.data == duty.data) isfirstitem = true;
-    final String lastday =
-        duty.jdate.subtract(days: 1).format(pattern: "yyyy-MM-dd");
-
-    final Duty? dutyendingtoday = (!isfirstitem)
-        ? null
-        : duties.firstWhereOrNull((Duty el) =>
-            (el.date == lastday) &&
-            (el.end != null) &&
-            (el.end!.format(pattern: "yyyy-MM-dd") == duty.date));
-    return Column(children: [
-      if (isfirstitem) ...[
-        const Gap(10),
-        const Divider(),
-        WDay(
-          date: duty.jdate,
-          highlight: now.yMd == duty.jdate.yMd,
-          onTap: () => context.push("/crewlink/crewlist",
-              extra: CrewlistPageParams(
-                  datestart: duty.jdate.format(pattern: "ddMMMyy"))),
-        ),
-        if (dutyendingtoday != null)
-          WDuty(duty: dutyendingtoday, date: duty.date),
-      ],
-      InkWell(
-        highlightColor: Colors.yellow[900],
-        onTap: () {
-          log("Tap: ${duty.type} ${duty.data}", name: "RosterPage");
-          switch (duty.type) {
-            case "changed":
-              AwesomeDialog(
-                      context: context,
-                      dialogType: DialogType.question,
-                      animType: AnimType.topSlide,
-                      title: 'Notification',
-                      desc: 'Load and show pending notification?',
-                      btnOkOnPress: () async {
-                        ref.read(isLoadingProvider.notifier).state = true;
-
-                        final res = await ref
-                            .read(crewlinkapiProvider)
-                            .notif(download: true, fileid: fileidnotif);
-                        ref.read(isLoadingProvider.notifier).state = false;
-                        if (res is Map && res["data"]?["id"] != null) {
-                          _showNotif();
-                        } else {
-                          AwesomeDialog(
-                                  context: context,
-                                  dialogType: DialogType.warning,
-                                  animType: AnimType.topSlide,
-                                  title: 'Notification',
-                                  desc: res?["error"] ??
-                                      res?["data"]?["msg"] ??
-                                      'No pending notification found !!!',
-                                  btnOkOnPress: () async {})
-                              .show();
-                        }
-                      },
-                      btnCancelOnPress: () {},
-                      btnOkText: "Load notification",
-                      showCloseIcon: true)
-                  .show();
-              break;
-            default:
-          }
-        },
-        child: WDuty(duty: duty),
-      )
-    ]);
-  }
-
-  void _showNotif() {
-    {
-      context
-          .push("/pdf",
-              extra: PdfPageParams(
-                  file: fileidnotif,
-                  title: "Roster change",
-                  bottom: ElevatedButton(
-                    style: ElevatedButton.styleFrom(
-                      backgroundColor: Colors.red[900],
-                    ),
-                    onPressed: () async {
-                      ref.read(isLoadingProvider.notifier).state = true;
-
-                      final ack =
-                          await ref.read(crewlinkapiProvider).confirmNotif();
-                      // final ack = {
-                      //   "error": null,
-                      //   "data": {
-                      //     "msg": null,
-                      //     "error": null,
-                      //     "notif": true
-                      //   }
-                      // };
-                      ref.read(isLoadingProvider.notifier).state = false;
-                      final ackok = (ack is Map &&
-                          ack["error"] != null &&
-                          ack["data"]?["error"] != null);
-                      AwesomeDialog(
-                          context: context,
-                          dialogType:
-                              ackok ? DialogType.success : DialogType.warning,
-                          animType: AnimType.topSlide,
-                          title: 'Notification',
-                          desc:
-                              // ack["data"]?["msg"] ??
-                              'Notification for change was acknowledged.',
-                          btnOkOnPress: () {
-                            context.pop({"notif": true});
-                          }).show();
-                    },
-                    child: const Padding(
-                      padding: EdgeInsets.all(8.0),
-                      child: Text(
-                        'Acknowledge & Confirm changes',
-                        style: TextStyle(fontSize: 20, color: Colors.yellow),
-                      ),
-                    ),
-                  )))
-          .then((res) {
-        if (res is Map && res["notif"]) _loadRoster();
-      });
-    }
-  }
-
-  void _showPdf(xcontext) {
-    if (File(fileidroster).existsSync()) {
-      context.push("/pdf",
-          extra: PdfPageParams(
-              file: fileidroster,
-              title:
-                  "Roster: ${Jiffy.parse(widget.params.datestart ?? "", pattern: "ddMMMyy", isUtc: true).format(pattern: "MMMM yyyy")}"));
-    } else {
-      context.showError(
-          "Can't find the roster for this month.\n Try to connect to internet and retrieve it from CrewLink?");
-    }
-  }
-
-  void _showMonths(xcontext) async {
-    ref.read(isLoadingProvider.notifier).state = true;
-
-    final resoff = Hive.box("crewlink").get(_rosterMinMaxKey);
-
-    final reson = await ref.read(crewlinkapiProvider).rosterMinMax();
-    ref.read(isLoadingProvider.notifier).state = false;
-
-    dynamic res;
-
-    if (reson["error"] == null && reson?["data"] != null) {
-      Hive.box("crewlink").put(_rosterMinMaxKey, reson["data"]);
-      res = reson["data"];
-    } else if (resoff == null) {
-      context.showError(reson["error"] ?? "Unknown error");
-      return;
-    }
-    res = res ?? resoff;
-
-    showModalBottomSheet(
-        useSafeArea: true,
-        backgroundColor: Colors.blueGrey[900],
-        context: context,
-        builder: (BuildContext bc) {
-          return HorizontalMonth(
-              start: Jiffy.parse(res["mindate"],
-                      pattern: "yyyy-MM-dd", isUtc: true)
-                  // .add(days: 1),
-                  .add(months: 1)
-                  .startOf(Unit.month),
-              end: Jiffy.parse(res["maxdate"],
-                      pattern: "yyyy-MM-dd", isUtc: true)
-                  .subtract(days: 1),
-              selectedmonth: rostermonths,
-              onmonthclick: (date) {
-                bc.push("/crewlink/roster",
-                    extra: RosterPageParams(
-                        dateend:
-                            date.endOf(Unit.month).format(pattern: "ddMMMyy"),
-                        datestart:
-                            date.startOf(Unit.month).format(pattern: "ddMMMyy"),
-                        crewlinkuser: crewlinkUser,
-                        crewlinkpass: crewlinkPass));
-              });
-        });
-  }
-}
-
-class RosterPageParams {
-  const RosterPageParams({
-    this.dateend,
-    this.datestart,
-    this.crewlinkuser,
-    this.crewlinkpass,
-  });
-
-  final String? dateend;
-  final String? datestart;
-  final String? crewlinkuser;
-  final String? crewlinkpass;
-}

+ 50 - 0
lib/roster/view/roster_page.dart

@@ -15,6 +15,8 @@ import 'package:scroll_to_index/scroll_to_index.dart';
 
 import 'package:tp5/core/basic_page.dart';
 import 'package:tp5/core/core.dart';
+import 'package:tp5/csv/data.dart';
+import 'package:tp5/fltinfo/view/dutyinfo_page.dart';
 import 'package:tp5/fltinfo/view/fltinfo_page.dart';
 import 'package:tp5/pdf/pdf_page.dart';
 import 'package:tp5/roster/api/crewlink_api.dart';
@@ -401,6 +403,54 @@ class _RosterPageState extends ConsumerState<RosterPage> {
                       des: duty.data["des"],
                       jdep: duty.start,
                       jdes: duty.end));
+            case "dhflight":
+              context.push("/fltinfo",
+                  extra: FltinfoParams(
+                      al: duty.data["al"],
+                      fnum: duty.data["fnum"],
+                      dep: duty.data["dep"],
+                      des: duty.data["des"],
+                      jdep: duty.start,
+                      jdes: duty.end));
+            case "dhlimo":
+              final pseudoleg = Pnleg(
+                  dep: duty.data["dep"],
+                  arr: duty.data["des"],
+                  depdate: duty.start?.format(pattern: "dd/MM/yyyy"),
+                  deptime: duty.start?.format(pattern: "HHmm"),
+                  arrdate: duty.end?.format(pattern: "dd/MM/yyyy"),
+                  arrtime: duty.end?.format(pattern: "HHmm"),
+                  //label: duty.data["label"],
+                  type: "G");
+              context.push("/dutyinfo",
+                  extra: DutyinfoParams(
+                      dutytype: pseudoleg.dutytype,
+                      jdep: duty.start,
+                      jdes: duty.end,
+                      dep: duty.data["dep"],
+                      des: duty.data["des"]));
+              break;
+            case "ground":
+              final pseudoleg = Pnleg(
+                dep: duty.data["dep"],
+                arr: duty.data["des"],
+                depdate: duty.start?.format(pattern: "dd/MM/yyyy"),
+                deptime: duty.start?.format(pattern: "HHmm"),
+                arrdate: duty.end?.format(pattern: "dd/MM/yyyy"),
+                arrtime: duty.end?.format(pattern: "HHmm"),
+                label: duty.data["label"],
+                //type: "G",
+              );
+              context.push("/dutyinfo",
+                  extra: DutyinfoParams(
+                      dutytype: pseudoleg.dutytype,
+                      label: pseudoleg.label,
+                      jdep: duty.start,
+                      jdes: duty.end,
+                      start: duty.start,
+                      end: duty.end,
+                      dep: duty.data["dep"],
+                      des: duty.data["des"]));
               break;
             default:
           }

+ 0 - 375
lib/rosters/rosters_page.bak2

@@ -1,375 +0,0 @@
-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:tp5/core/basic_page.dart';
-import 'package:data_table_2/data_table_2.dart';
-
-class RostersPage extends ConsumerStatefulWidget {
-  const RostersPage({super.key});
-
-  @override
-  ConsumerState<ConsumerStatefulWidget> createState() => _RostersPageState();
-}
-
-class _RostersPageState extends ConsumerState<RostersPage> {
-  @override
-  Widget build(BuildContext context) {
-    return buildFixedDataTable(tableData);
-  }
-
-// Example of a custom widget with fixed column and row headers
-  Widget buildFixedDataTable(List<List<String>> data) {
-    return SingleChildScrollView(
-      scrollDirection: Axis.vertical,
-      child: SingleChildScrollView(
-        scrollDirection: Axis.horizontal,
-        child: DataTable(
-          columns: data[0]
-              .map<DataColumn>((name) => DataColumn(
-                      label: Text(
-                    name,
-                    style: const TextStyle(
-                        fontWeight: FontWeight.bold, color: Colors.black),
-                  )))
-              .toList(),
-          rows: data
-              .sublist(1)
-              .map<DataRow>((row) => DataRow(
-                    cells: row
-                        .map<DataCell>((cell) => DataCell(Text(cell)))
-                        .toList(),
-                  ))
-              .toList(),
-        ),
-      ),
-    );
-  }
-
-// Usage example:
-  final tableData = [
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    [
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3',
-      'Column 1',
-      'Column 2',
-      'Column 3'
-    ],
-    // Add more rows and data as needed
-  ];
-}

+ 0 - 744
lib/rosters/rosters_page.bak3

@@ -1,744 +0,0 @@
-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:hive_flutter/hive_flutter.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:tp5/core/basic_page.dart';
-import 'package:tp5/core/utils.dart';
-import 'package:tp5/csv/data.dart';
-
-import 'package:linked_scroll_controller/linked_scroll_controller.dart';
-import 'package:tp5/fltinfo/view/dutyinfo_page.dart';
-import 'package:tp5/fltinfo/view/fltinfo_page.dart';
-import 'package:tp5/rosters/rosters_crew_filter.dart';
-import 'package:tp5/widgets/my_col.dart';
-import 'package:tp5/widgets/my_row.dart';
-import 'package:google_fonts/google_fonts.dart';
-
-class RostersPage extends ConsumerStatefulWidget {
-  const RostersPage({super.key});
-
-  @override
-  ConsumerState<ConsumerStatefulWidget> createState() => _RostersPageState();
-}
-
-class _RostersPageState extends ConsumerState<RostersPage> {
-  final scrollControllerGroup = LinkedScrollControllerGroup();
-  Map<int, ScrollController> scrollCtrls = {};
-
-  ScrollController? _getCtrl(int i) {
-    if (!scrollCtrls.containsKey(i)) {
-      scrollCtrls[i] = scrollControllerGroup.addAndGet();
-    }
-
-    return scrollCtrls[i];
-  }
-
-  final bottomnavstyle = ElevatedButton.styleFrom(
-      shape: RoundedRectangleBorder(
-        borderRadius: BorderRadius.circular(5.0),
-      ),
-      backgroundColor:
-          const Color.fromARGB(255, 0, 36, 53) //elevated btton background color
-      );
-
-  TextEditingController ctrldep = TextEditingController();
-  TextEditingController ctrldes = TextEditingController();
-  TextEditingController ctrlairline = TextEditingController();
-  TextEditingController ctrlfnum = TextEditingController();
-
-  Map<String, String> flightFilter = {
-    "dep": "",
-    "des": "",
-    "al": "",
-    "fnum": ""
-  };
-  void _searchFlights(xcontext) async {
-    ctrldep.text = flightFilter["dep"] ?? "";
-    ctrldes.text = flightFilter["des"] ?? "";
-    ctrlairline.text = flightFilter["al"] ?? "";
-    ctrlfnum.text = flightFilter["fnum"] ?? "";
-
-    final res = await showModalBottomSheet(
-        context: context, builder: (context) => _flightFilter(xcontext));
-    if (res is Map<String, String>) {
-      Hive.box("settings").put("rosters.filter.flights", (res));
-      await recalcultlcs();
-
-      setState(() {
-        flightFilter = res;
-      });
-    }
-  }
-
-  Widget _flightFilter(BuildContext context) {
-    return Container(
-        padding: const EdgeInsets.all(20),
-        child: Column(mainAxisSize: MainAxisSize.min, children: [
-          Row(
-            children: [
-              Expanded(
-                child: TextField(
-                  decoration:
-                      const InputDecoration(labelText: "Departure Airport"),
-                  maxLength: 3, // Set maximum length
-                  controller: ctrldep,
-                ),
-              ),
-              const SizedBox(width: 10),
-              Expanded(
-                child: TextField(
-                  decoration:
-                      const InputDecoration(labelText: "Arrival Airport"),
-                  maxLength: 3, // Set maximum length
-                  controller: ctrldes,
-                ),
-              ),
-            ],
-          ),
-          const SizedBox(height: 15),
-          Row(
-            children: [
-              Expanded(
-                child: TextField(
-                  controller: ctrlairline,
-
-                  decoration:
-                      const InputDecoration(labelText: "Airline IATA code"),
-                  maxLength: 2, // Set maximum length
-                ),
-              ),
-              const SizedBox(width: 10),
-              Expanded(
-                child: TextField(
-                  controller: ctrlfnum,
-
-                  decoration: const InputDecoration(labelText: "Flight number"),
-                  maxLength: 6, // Set maximum length
-                ),
-              ),
-            ],
-          ),
-          const SizedBox(height: 15),
-          const SizedBox(height: 35),
-          SizedBox(
-            width: 360,
-            child: ElevatedButton(
-              onPressed: () async => Navigator.pop(context, {
-                "dep": ctrldep.text.toUpperCase(),
-                "des": ctrldes.text.toUpperCase(),
-                "al": ctrlairline.text.toUpperCase(),
-                "fnum": ctrlfnum.text.toUpperCase()
-              }), // Close the bottom sheet
-              style: ElevatedButton.styleFrom(
-                backgroundColor: Colors.green, // Set button color to green
-                shape: RoundedRectangleBorder(
-                  borderRadius:
-                      BorderRadius.circular(15), // Add rounded corners
-                ),
-                padding:
-                    const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
-              ),
-              child: const Text(
-                'Flight filter',
-                style: TextStyle(fontSize: 18, color: Colors.white),
-              ),
-            ),
-          ),
-        ]));
-  }
-
-  Map<String, List<String>> crewFilter = {"college": [], "ac": [], "base": []};
-  void _searchCrew(xcontext, List<Qualif> qualif) async {
-    final res = await showModalBottomSheet(
-        context: context,
-        builder: (context) =>
-            RostersCrewFilter(qualif: qualif, crewFilter: crewFilter));
-    if (res is Map<String, List<String>>) {
-      Hive.box("settings").put("rosters.filter.crew", (res));
-      await recalcultlcs();
-      setState(() {
-        crewFilter = res;
-      });
-    }
-  }
-
-  final double rosterswidth = 110;
-  final double rostersheight = 60;
-  Widget _duty2line(Pnleg leg, {bool showdatedep = true}) {
-    // print(
-    //     ">>${leg.label},${leg.type},${leg.dep},${leg.arr},${leg.jdep?.format(pattern: "HHmm")},${leg.jarr?.format(pattern: "HHmm")},");
-    final whdep = showdatedep
-        ? Text(
-            "${leg.jdep?.format(pattern: "HHmm")}",
-            style: const TextStyle(fontSize: 10, color: Colors.teal),
-          )
-        : const Row(children: [
-            Icon(
-              Icons.arrow_back_ios_new_outlined,
-              size: 12,
-              color: Colors.teal,
-            ),
-            Icon(
-              Icons.arrow_back_ios_new_outlined,
-              size: 12,
-              color: Colors.teal,
-            ),
-          ]);
-    final wharr = Text(
-      "${leg.jarr?.format(pattern: "HHmm")}",
-      style: const TextStyle(fontSize: 10, color: Colors.teal),
-    );
-    if (leg.type == "L" || (leg.type == "F")) {
-      return InkWell(
-        onTap: () {
-          context.push("/fltinfo",
-              extra: FltinfoParams(
-                  al: leg.al,
-                  fnum: leg.fnum,
-                  dep: leg.dep,
-                  des: leg.arr,
-                  jdep: leg.jdep,
-                  jdes: leg.jarr));
-        },
-        child: MyRow(children: [
-          whdep,
-          const Gap(3),
-          Text(
-            "${leg.dep}-${leg.arr}",
-            style: GoogleFonts.robotoMono(
-                fontSize: 11, fontWeight: FontWeight.w300),
-          ),
-          const Gap(3),
-          wharr,
-        ]),
-      );
-    } else if ((leg.type == "G") ||
-        ((leg.dep ?? "") != "" && (leg.arr ?? "") != "")) {
-      return InkWell(
-        onTap: () {
-          context.push("/dutyinfo",
-              extra: DutyinfoParams(
-                  dutytype: leg.dutytype,
-                  label: leg.label,
-                  dep: leg.dep,
-                  des: leg.arr,
-                  jdep: leg.jdep,
-                  jdes: leg.jarr));
-        },
-        child: MyRow(children: [
-          whdep,
-          const Gap(3),
-          const Text("Limo ",
-              style: TextStyle(fontSize: 11, color: Colors.amber)),
-          Text(
-            "${leg.dep}-${leg.arr}",
-            style: GoogleFonts.robotoMono(
-                fontSize: 11, fontWeight: FontWeight.w300),
-          ),
-          const Gap(3),
-          wharr,
-        ]),
-      );
-    }
-    //  else if ((leg.type == "F") ||
-    //     ((leg.dep ?? "") != "" && (leg.arr ?? "") != "")) {
-    //   return MyRow(children: [
-    //     whdep,
-    //     const Gap(3),
-    //     const Text("DH ", style: TextStyle(fontSize: 11, color: Colors.amber)),
-    //     Text(
-    //       "${leg.dep}-${leg.arr}",
-    //       style:
-    //           GoogleFonts.robotoMono(fontSize: 11, fontWeight: FontWeight.w300),
-    //     ),
-    //     const Gap(3),
-    //     wharr,
-    //   ]);
-    // }
-    else if ((!["OFF", "CM", "CA", "PP"].contains(leg.label)) &&
-        (leg.jarr != null &&
-            leg.jdep != null &&
-            DTInterval(leg.jdep!, leg.jarr!).duration.inHours < 18)) {
-      return InkWell(
-        onTap: () {
-          context.push("/dutyinfo",
-              extra: DutyinfoParams(
-                  dutytype: leg.dutytype,
-                  label: leg.label,
-                  dep: leg.dep,
-                  des: leg.arr,
-                  jdep: leg.jdep,
-                  jdes: leg.jarr));
-        },
-        child: MyRow(children: [
-          whdep,
-          const Gap(3),
-          Text("${leg.type == "S" ? "SIMU " : ""}${leg.label}",
-              style: const TextStyle(fontSize: 11, color: Colors.amber)),
-          Text(
-            " ${leg.dep}",
-            style: GoogleFonts.robotoMono(
-                fontSize: 8, fontWeight: FontWeight.w300),
-          ),
-          const Gap(3),
-          wharr,
-        ]),
-      );
-    } else {
-      return Text(
-        leg.label ?? "",
-        style: TextStyle(
-            fontSize: 16,
-            color: Colors.blueGrey[800],
-            fontWeight: FontWeight.w700,
-            letterSpacing: 1),
-      );
-    }
-  }
-
-  Widget _rostersDay(
-      {required Jiffy date,
-      required List<Pnleg> legs,
-      Color? color,
-      bool border = false}) {
-    return Container(
-      decoration: BoxDecoration(
-          border: border ? Border.all(color: Colors.white, width: 1) : null,
-          color: color ?? Colors.grey[900]),
-      width: rosterswidth,
-      height: rosterswidth,
-      child: Column(children: [
-        Row(
-          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-          children: [
-            Text(
-              date.format(pattern: "EEE"),
-              style: const TextStyle(
-                  fontSize: 14,
-                  color: Colors.blueGrey,
-                  fontWeight: FontWeight.w700),
-            ),
-            Text(
-              date.format(pattern: "dd MMM "),
-              style: const TextStyle(
-                  fontSize: 14,
-                  color: Color.fromARGB(255, 151, 163, 55),
-                  fontWeight: FontWeight.w500),
-            )
-          ],
-        ),
-        Expanded(
-            child: MyCol(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: legs
-                    .map((leg) => _duty2line(leg,
-                        showdatedep: date.yMEd == leg.jdep?.yMEd))
-                    .toList()))
-      ]),
-    );
-  }
-
-  bool showalldates = false;
-
-  recalcultlcs() async {
-    final data = ref.read(dataProvider);
-    final pnlegTlcs = ref.read(pnlegMeta).tlcs;
-    final pnleg = data.pnleg;
-    final qualif = data.qualif;
-
-    tlcs = await compute(
-        calcultlcs,
-        {
-          "crewFilter": crewFilter,
-          "flightFilter": flightFilter,
-          "pnleg": pnleg,
-          "pnlegTlcs": pnlegTlcs,
-          "qualif": qualif
-        },
-        debugLabel: "calcul tlcs");
-    setState(() {});
-    // print("rosterspages: recalcultlcs: $tlcs");
-  }
-
-  // recalculdates() async {
-  //   final data = ref.watch(dataProvider);
-  //   final pnleg = data.pnleg;
-
-  //   dates = await compute(calculdates, pnleg, debugLabel: "calcul dates");
-  //   setState(() {});
-  //   print("rosterspages: recalculdates: $dates");
-  // }
-
-  // static List<Jiffy> calculdates(List<Pnleg> pnleg) {
-  //   return pnleg
-  //       .fold(
-  //           <Jiffy>{},
-  //           (t, e) => {
-  //                 ...t,
-  //                 e.jdep?.startOf(Unit.day) ??
-  //                     Jiffy.parse(e.date ?? "01/01/1970",
-  //                         pattern: "dd/MM/yyyy", isUtc: true)
-  //               })
-  //       .sortedBy((e) => e.dateTime)
-  //       .where((e) =>
-  //           e.isAfter(Jiffy.now().toUtc().startOf(Unit.day).subtract(days: 3)))
-  //       .toList();
-  // }
-
-  static List<String> calcultlcs(Map data) {
-    final List<Qualif> qualif = data["qualif"];
-    final crewFilter = data["crewFilter"];
-    final flightFilter = data["flightFilter"];
-    final List<Pnleg> pnleg = data["pnleg"];
-    final Set<String> tlcsCrewfilter = qualif
-        .where((e) => ((crewFilter["college"]!.isEmpty ||
-                crewFilter["college"]!.contains(e.college)) &&
-            (crewFilter["ac"]!.isEmpty || crewFilter["ac"]!.contains(e.ac)) &&
-            (crewFilter["base"]!.isEmpty ||
-                crewFilter["base"]!.contains(e.base))))
-        .map((e) => e.tlc ?? "")
-        .toSet();
-
-    final List<String> pnlegTlcs = data["pnlegTlcs"];
-    // final List<String> pnlegTlcs =
-    //     pnleg.fold(<String>{}, (t, e) => {...t, e.tlc ?? ""}).sortedBy((e) {
-    //   final pn = qualif.firstWhereOrNull((q) => q.tlc == e);
-    //   return "${pn?.lname} ${pn?.fname}";
-    // });
-
-    final Set<String> tlcsFlightfilter = pnlegTlcs
-        .where((e) => ((flightFilter["al"] == "" ||
-                pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.al == flightFilter["al"])) !=
-                    null) &&
-            (flightFilter["fnum"] == "" ||
-                pnleg.firstWhereOrNull((k) =>
-                        (k.tlc == e) && (k.fnum == flightFilter["fnum"])) !=
-                    null) &&
-            (flightFilter["dep"] == "" ||
-                pnleg.firstWhereOrNull((k) => (k.tlc == e) && (k.dep == flightFilter["dep"])) !=
-                    null) &&
-            (flightFilter["des"] == "" ||
-                pnleg.firstWhereOrNull((k) =>
-                        (k.tlc == e) && (k.arr == flightFilter["des"])) !=
-                    null)))
-        .toSet();
-
-    return tlcsCrewfilter.intersection(tlcsFlightfilter).sortedBy((e) =>
-        "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
-  }
-
-  List<String> tlcs = [];
-  // List<Jiffy> dates = [];
-
-
-  @override
-  Widget build(BuildContext context) {
-    final data = ref.watch(dataProvider);
-    final pnleg = data.pnleg;
-    final qualif = data.qualif;
-    // final now = ref.watch(clockProvider);
-    final now = Jiffy.now().toUtc();
-
-    final pnlegmeta = ref.watch(pnlegMeta);
-    final dates = pnlegmeta.dates;
-    final alltlcs = pnlegmeta.tlcs;
-    // final dates = data.pnleg_dates;
-    // final tlcs = data.pnleg_tlcs;
-
-    return BasicPage(
-      actions: [Text("showing ${tlcs.length} crew member"), const Gap(5)],
-      bottomNavigationBar: Container(
-        padding: const EdgeInsets.only(left: 8, right: 8, bottom: 2, top: 6),
-        // color: Colors.black,
-        decoration: BoxDecoration(
-            gradient: LinearGradient(
-          begin: Alignment.topCenter,
-          end: Alignment.bottomCenter,
-          colors: [
-            Colors.grey[700]!,
-            Colors.black,
-          ],
-        )),
-        child: Column(
-          mainAxisSize: MainAxisSize.min,
-          children: [
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceAround,
-              children: [
-                Row(
-                  children: [
-                    ElevatedButton.icon(
-                      onPressed: () {
-                        _searchCrew(context, qualif);
-                      },
-                      icon: const Icon(
-                          Icons.calendar_month), //icon data for elevated button
-                      label: const Text("Filter\nCrew"), //label text
-                      style: bottomnavstyle,
-                    ),
-                    const Gap(10),
-                    Row(
-                      children: [
-                        Column(
-                            mainAxisSize: MainAxisSize.min,
-                            children: crewFilter.keys
-                                .where((e) => crewFilter[e]!.isNotEmpty)
-                                .map((e) => Text(
-                                      "${crewFilter[e]}",
-                                      style: const TextStyle(
-                                          fontSize: 12, color: Colors.yellow),
-                                    ))
-                                .toList()),
-                        const Gap(10),
-                        if (crewFilter.values.flattened.isNotEmpty)
-                          Badge(
-                            label: Text(
-                                crewFilter.values.flattened.length.toString()),
-                            child: IconButton.outlined(
-                                onPressed: () {
-                                  for (var k in crewFilter.keys) {
-                                    crewFilter[k]!.clear();
-                                  }
-                                  Hive.box("settings")
-                                      .delete("rosters.filter.crew");
-                                  setState(() {});
-                                },
-                                icon: const Icon(Icons.filter_alt_off_rounded,
-                                    size: 18)),
-                          ),
-                      ],
-                    )
-                  ],
-                ),
-                const Gap(10),
-                Row(
-                  children: [
-                    ElevatedButton.icon(
-                      onPressed: () {
-                        _searchFlights(context);
-                      },
-                      icon: const Icon(Icons.manage_search),
-                      label: const Text("Filter\nFlights"),
-                      style: bottomnavstyle,
-                    ),
-                    const Gap(10),
-                    if (flightFilter.values.any((e) => e != ""))
-                      Badge(
-                        label: Text(flightFilter.values
-                            .where((e) => e != "")
-                            .length
-                            .toString()),
-                        child: IconButton.outlined(
-                            onPressed: () {
-                              for (var k in flightFilter.keys) {
-                                flightFilter[k] = "";
-                              }
-                              Hive.box("settings")
-                                  .delete("rosters.filter.flights");
-
-                              setState(() {});
-                            },
-                            icon: const Icon(Icons.filter_alt_off_rounded,
-                                size: 18)),
-                      )
-                  ],
-                ),
-                const Gap(10), //icon data for elevated button
-              ],
-            ),
-            Row(
-              mainAxisAlignment: MainAxisAlignment.end,
-              children: [
-                data.aclegupdate != null
-                    ? Text("data retrieved ${data.pnlegupdate?.from(now)}",
-                        style: GoogleFonts.robotoMono(
-                            fontSize: 10,
-                            fontWeight: FontWeight.w300,
-                            color: Colors.white))
-                    : Text("no data found",
-                        style: GoogleFonts.robotoMono(
-                            fontSize: 10, fontWeight: FontWeight.w300))
-              ],
-            ),
-          ],
-        ),
-      ),
-      title: "Rosters",
-      body: tlcs.isEmpty
-          ? const Text("no Pnleg data")
-          : ListView.builder(
-              itemCount: tlcs.length, // Number of list items
-              itemBuilder: (context, index) {
-                final qualifData =
-                    qualif.where((k) => k.tlc == tlcs.elementAt(index));
-                final tlc = tlcs.elementAt(index);
-
-                final dutiesTlc = ref.watch(pnlegByTlcProvider(tlc)).where(
-                    (e) => ((flightFilter["al"] == "" ||
-                            e.al == flightFilter["al"]) &&
-                        (flightFilter["fnum"] == "" ||
-                            e.fnum == flightFilter["fnum"]) &&
-                        (flightFilter["dep"] == "" ||
-                            e.dep == flightFilter["dep"]) &&
-                        (flightFilter["des"] == "" ||
-                            e.arr == flightFilter["des"])));
-
-                final name =
-                    "${qualifData.firstOrNull?.lname?.capitalizeword()}, ${qualifData.firstOrNull?.fname?.capitalizeword()}";
-                final base = "${qualifData.map((e) => e.base).toSet()}";
-                return Column(
-                  crossAxisAlignment: CrossAxisAlignment.start,
-                  children: [
-                    Padding(
-                        padding: const EdgeInsets.all(2),
-                        child: Row(children: [
-                          const Gap(10),
-                          Text(name,
-                              style: const TextStyle(
-                                  fontWeight: FontWeight.w700,
-                                  letterSpacing: 1)),
-                          const Gap(10),
-                          Text(
-                            tlc,
-                            style: const TextStyle(
-                                fontSize: 12, fontWeight: FontWeight.w300),
-                          ),
-                          const Gap(5),
-                          Text(
-                            base,
-                            style: GoogleFonts.robotoMono(
-                                fontSize: 11, fontWeight: FontWeight.w300),
-                          )
-                        ])),
-                    SizedBox(
-                      height: rostersheight,
-                      child: (dates.isEmpty)
-                          ? const Text("No Pnlegs data found")
-                          : ListView.builder(
-                              // controller: scrollControllerGroup.addAndGet(), //_scrollCtrl,
-                              controller: _getCtrl(index), //_scrollCtrl,
-                              scrollDirection: Axis.horizontal,
-                              itemCount:
-                                  dates.length, // Number of horizontal items
-                              itemBuilder: (context, horizontalIndex) {
-                                final date = dates.elementAt(horizontalIndex);
-                                final duties = dutiesTlc.where((e) =>
-                                    DTInterval(
-                                            e.jdep ??
-                                                e.jdate?.startOf(Unit.day) ??
-                                                Jiffy.now(),
-                                            e.jarr ??
-                                                e.jdate?.endOf(Unit.day) ??
-                                                Jiffy.now())
-                                        .isOverlap(DTInterval(
-                                            date.startOf(Unit.day),
-                                            date.endOf(Unit.day))));
-                                if (pnleg.isEmpty) {
-                                  return const Padding(
-                                    padding: EdgeInsets.all(5.0),
-                                    child: Center(
-                                      child: Text("No Pnlegs data found"),
-                                    ),
-                                  );
-                                }
-                                return Padding(
-                                  padding: const EdgeInsets.symmetric(
-                                      horizontal: 2, vertical: 1),
-                                  child: _rostersDay(
-                                      date: date,
-                                      legs: duties.toList(),
-                                      color: date
-                                              .endOf(Unit.day)
-                                              .isBefore(now.startOf(Unit.day))
-                                          ? Colors.grey[900]
-                                          : Colors.black,
-                                      border: date.yMEd == now.yMEd),
-                                );
-                              },
-                            ),
-                    ),
-                  ],
-                );
-              },
-            ),
-    );
-  }
-
-  @override
-  void initState() {
-    Future.delayed(Duration.zero).then((x) async {
-      final savedcrewfilter =
-          await Hive.box("settings").get("rosters.filter.crew");
-      final savedflightsfilter =
-          await Hive.box("settings").get("rosters.filter.flights");
-
-      print(
-          "rosters: saved crew filter: ${savedcrewfilter.runtimeType} $savedcrewfilter");
-      print("rosters: saved flights filter: $savedflightsfilter");
-
-      if (savedcrewfilter != null && savedcrewfilter is Map) {
-        crewFilter = savedcrewfilter
-            .map((key, value) => MapEntry(key, List<String>.from(value)));
-      }
-      if (savedflightsfilter != null && savedflightsfilter is Map) {
-        flightFilter =
-            savedflightsfilter.map((key, value) => MapEntry(key, value));
-      }
-    });
-    super.initState();
-  }
-}
-
-class PnlegMeta {
-  PnlegMeta({required this.tlcs, required this.dates});
-  final List<String> tlcs;
-  final List<Jiffy> dates;
-}
-
-// final pnlegMeta = Provider((ref) {
-//   print("data: start analyzing pnleg");
-//   final now = Jiffy.now();
-//   final data = ref.watch(dataProvider);
-//   final pnlegs = data.pnleg;
-//   final qualif = data.qualif;
-//   Set<String> tlcs = {};
-//   Set<Jiffy> dates = {};
-//   for (Pnleg pnleg in pnlegs) {
-//     tlcs.add(pnleg.tlc ?? "");
-//     dates.add(pnleg.jdep?.startOf(Unit.day) ??
-//         Jiffy.parse(pnleg.date ?? "01/01/1970",
-//             pattern: "dd/MM/yyyy", isUtc: true));
-//   }
-//   // final restlcs = tlcs.sortedBy((k) =>qualif.firstWhereOrNull((q) => q.tlc == k)?.lname ?? "zzzzzzzzzzzzz");
-//   final restlcs = tlcs.sortedBy((e) =>
-//       "${qualif.firstWhereOrNull((k) => k.tlc == e)?.lname} ${qualif.firstWhereOrNull((k) => k.tlc == e)?.fname}");
-//   final resdates = dates.sortedBy((k) => k.millisecondsSinceEpoch.toString());
-//   print(
-//       "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
-//   return PnlegMeta(tlcs: restlcs, dates: resdates);
-// });
-
-final pnlegMeta = Provider((ref) {
-  print("data: start analyzing pnleg");
-  final now = Jiffy.now();
-  final data = ref.watch(dataProvider);
-  final pnlegs = data.pnleg;
-  final qualif = data.qualif;
-  print(
-      "data: end analyzing pnleg ${Duration(milliseconds: Jiffy.now().millisecondsSinceEpoch - now.millisecondsSinceEpoch).inSeconds} sec");
-  return PnlegMeta(tlcs:  pnleg.fold(<String>{}, (t, e) => {...t, e.tlc ?? ""}).sortedBy((e) {
-        final pn = qualif.firstWhereOrNull((q) => q.tlc == e);
-        return "${pn?.lname} ${pn?.fname}";
-      }), dates: pnleg.fold(
-      <Jiffy>{},
-      (t, e) => {
-            ...t,
-            e.jdep?.startOf(Unit.day) ??
-                Jiffy.parse(e.date ?? "01/01/1970",
-                    pattern: "dd/MM/yyyy", isUtc: true)
-          }).sortedBy((e) => e.dateTime));
-});

+ 8 - 7
lib/rosters/rosters_page.dart

@@ -415,13 +415,14 @@ class _RostersPageState extends ConsumerState<RostersPage> {
       final tlc = tlcs.elementAt(index);
 
       final dutiesTlcAll = ref.watch(pnlegByTlcProvider(tlc));
-      final dutiesTlc = flightFilter.values.every((x) => x == "")
-          ? dutiesTlcAll
-          : (dutiesTlcAll.where((e) => ((flightFilter["al"] == "" ||
-                  e.al == flightFilter["al"]) &&
-              (flightFilter["fnum"] == "" || e.fnum == flightFilter["fnum"]) &&
-              (flightFilter["dep"] == "" || e.dep == flightFilter["dep"]) &&
-              (flightFilter["des"] == "" || e.arr == flightFilter["des"]))));
+      final dutiesTlc = dutiesTlcAll;
+      // final dutiesTlc = flightFilter.values.every((x) => x == "")
+      //     ? dutiesTlcAll
+      //     : (dutiesTlcAll.where((e) => ((flightFilter["al"] == "" ||
+      //             e.al == flightFilter["al"]) &&
+      //         (flightFilter["fnum"] == "" || e.fnum == flightFilter["fnum"]) &&
+      //         (flightFilter["dep"] == "" || e.dep == flightFilter["dep"]) &&
+      //         (flightFilter["des"] == "" || e.arr == flightFilter["des"]))));
 
       final name =
           "${qualifData.firstOrNull?.lname?.capitalizeword()}, ${qualifData.firstOrNull?.fname?.capitalizeword()}";

+ 16 - 5
lib/widgets/nav_drawer.dart

@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:go_router/go_router.dart';
+import 'package:supabase_flutter/supabase_flutter.dart';
 import 'package:tp5/ftl/view/ftl_page.dart';
 import 'package:tp5/lido/view/lidolist_page.dart';
 
@@ -14,11 +15,16 @@ class NavDrawer extends StatelessWidget {
         children: <Widget>[
           const DrawerHeader(
             decoration: BoxDecoration(
-                color: Colors.black54,
-                image: DecorationImage(
-                    fit: BoxFit.fill, image: AssetImage('assets/logo.png'))),
+              color: Colors.black54,
+              image: DecorationImage(
+                alignment: Alignment.bottomRight,
+                fit: BoxFit.fitHeight,
+                scale: 0.5,
+                image: AssetImage('assets/logo.png'),
+              ),
+            ),
             child: Text(
-              'Side menu',
+              'Menu',
               style: TextStyle(color: Colors.white, fontSize: 25),
             ),
           ),
@@ -67,7 +73,12 @@ class NavDrawer extends StatelessWidget {
           ListTile(
             leading: const Icon(Icons.exit_to_app),
             title: const Text('Logout'),
-            onTap: () => {Navigator.of(context).pop()},
+            onTap: () async {
+              await Supabase.instance.client.auth.signOut();
+              if (context.mounted) {
+                context.go('/login-otp');
+              }
+            },
           ),
         ],
       ),

+ 34 - 114
pubspec.lock

@@ -334,14 +334,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.0.0"
-  email_validator:
-    dependency: transitive
-    description:
-      name: email_validator
-      sha256: e9a90f27ab2b915a27d7f9c2a7ddda5dd752d6942616ee83529b686fc086221b
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.1.17"
   fake_async:
     dependency: transitive
     description:
@@ -379,6 +371,14 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_launcher_icons:
+    dependency: "direct dev"
+    description:
+      name: flutter_launcher_icons
+      sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.14.1"
   flutter_lints:
     dependency: "direct dev"
     description:
@@ -405,14 +405,6 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
-  font_awesome_flutter:
-    dependency: transitive
-    description:
-      name: font_awesome_flutter
-      sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f"
-      url: "https://pub.dev"
-    source: hosted
-    version: "10.7.0"
   freezed_annotation:
     dependency: transitive
     description:
@@ -457,10 +449,10 @@ packages:
     dependency: "direct main"
     description:
       name: go_router
-      sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc"
+      sha256: ce89c5a993ca5eea74535f798478502c30a625ecb10a1de4d7fef5cd1bcac2a4
       url: "https://pub.dev"
     source: hosted
-    version: "14.3.0"
+    version: "14.4.1"
   google_fonts:
     dependency: "direct main"
     description:
@@ -469,54 +461,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "6.2.1"
-  google_identity_services_web:
-    dependency: transitive
-    description:
-      name: google_identity_services_web
-      sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.3.1+4"
-  google_sign_in:
-    dependency: transitive
-    description:
-      name: google_sign_in
-      sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f"
-      url: "https://pub.dev"
-    source: hosted
-    version: "6.2.1"
-  google_sign_in_android:
-    dependency: transitive
-    description:
-      name: google_sign_in_android
-      sha256: "0928059d2f0840f63c7b07a30cf73b593ae872cdd0dbd46d1b9ba878d2599c01"
-      url: "https://pub.dev"
-    source: hosted
-    version: "6.1.33"
-  google_sign_in_ios:
-    dependency: transitive
-    description:
-      name: google_sign_in_ios
-      sha256: "83f015169102df1ab2905cf8abd8934e28f87db9ace7a5fa676998842fed228a"
-      url: "https://pub.dev"
-    source: hosted
-    version: "5.7.8"
-  google_sign_in_platform_interface:
-    dependency: transitive
-    description:
-      name: google_sign_in_platform_interface
-      sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.4.5"
-  google_sign_in_web:
-    dependency: transitive
-    description:
-      name: google_sign_in_web
-      sha256: "042805a21127a85b0dc46bba98a37926f17d2439720e8a459d27045d8ef68055"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.12.4+2"
   gotrue:
     dependency: transitive
     description:
@@ -597,6 +541,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.1.1"
+  image:
+    dependency: transitive
+    description:
+      name: image
+      sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.3.0"
   intl:
     dependency: "direct main"
     description:
@@ -1061,30 +1013,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.0.0"
-  sign_in_with_apple:
-    dependency: transitive
-    description:
-      name: sign_in_with_apple
-      sha256: "602f1374c9c4c33889c969b53ebf7cc8417c22cc7e25ea771581330173bc6603"
-      url: "https://pub.dev"
-    source: hosted
-    version: "6.1.3"
-  sign_in_with_apple_platform_interface:
-    dependency: transitive
-    description:
-      name: sign_in_with_apple_platform_interface
-      sha256: c2ef2ce6273fce0c61acd7e9ff5be7181e33d7aa2b66508b39418b786cca2119
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.1.0"
-  sign_in_with_apple_web:
-    dependency: transitive
-    description:
-      name: sign_in_with_apple_web
-      sha256: c009e9beeb6c376e86aaa154fcc8b4e075d4bad90c56286b9668a51cdb6129ea
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.1.0"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -1170,14 +1098,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.5.0"
-  supabase_auth_ui:
-    dependency: "direct main"
-    description:
-      name: supabase_auth_ui
-      sha256: "2a9752f8f0fea257f834ee6da9ac764d73ada67c2947f74f5024c72bdd7f8b2e"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.5.4"
   supabase_flutter:
     dependency: "direct main"
     description:
@@ -1198,66 +1118,66 @@ packages:
     dependency: transitive
     description:
       name: syncfusion_flutter_core
-      sha256: "6a2445aef2adc77136aedaf8b0c1b7f22c43b43d7036f219414db9acd679570a"
+      sha256: "31d2ddf410ee41abb3ecf85b7b6e8e1563307ad52ee784ddd91337e30280f715"
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_flutter_pdf:
     dependency: "direct main"
     description:
       name: syncfusion_flutter_pdf
-      sha256: a0c666ba74b50c6082798d888a161f256445eb108bba66a8c6ee39e91a166f44
+      sha256: ada2e2cf5603be558ff9e67e5941858cb15d6fac1de4d5307b3ecfb97bfe8108
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_flutter_pdfviewer:
     dependency: "direct main"
     description:
       name: syncfusion_flutter_pdfviewer
-      sha256: "6ec1795e19517679c13c3c24c32cb570d66c658ef18db671992b73dde0b9fdac"
+      sha256: "3f267a63272deda5a17d370b7a1e7ae31f1a0fd9bc1cb43d0fda8a9b8fa8fe40"
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_flutter_signaturepad:
     dependency: transitive
     description:
       name: syncfusion_flutter_signaturepad
-      sha256: "4fd8a242e68c750faa50e3e49c7ee9d3ca153cdac9382bb38b4e6e2b2a0392a5"
+      sha256: e37efd2e2d57af7e4597073769dee3c2f343d46c324a6d81a055302fad65fc7c
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_pdfviewer_macos:
     dependency: transitive
     description:
       name: syncfusion_pdfviewer_macos
-      sha256: "0055ce021501b88592754f2942cebb399b9409f8cee13d6c34ef9284a126faf2"
+      sha256: f90e57ffc3c9460ed8096e2c585977af180f30889b0f620844ef587745b3e4bd
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_pdfviewer_platform_interface:
     dependency: transitive
     description:
       name: syncfusion_pdfviewer_platform_interface
-      sha256: d4b5c9f318235b0cc28b3d252bda44bf7c476eb079b252177c92c94d431012c0
+      sha256: "70f4730f4db0d00a9f38a25ffb71403e579f3f091ef824a69dfe8b35dc2f1270"
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_pdfviewer_web:
     dependency: transitive
     description:
       name: syncfusion_pdfviewer_web
-      sha256: "2b8c64a03f5466eb5a14ca7a58d58ed00381abdb2d142362d65bdde52c8498cb"
+      sha256: dfbd5c6f7d504129f854df448ad6cd330878ae55c105409cf26c4834257be2f6
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   syncfusion_pdfviewer_windows:
     dependency: transitive
     description:
       name: syncfusion_pdfviewer_windows
-      sha256: "2019ba5a0e4ad53489ba8bd7fed0ca7b46273d75a388a8bba9a538f921ab1c92"
+      sha256: "30ef646d5a42a89e47b3faa6a9af4d814bef87bccd4214ed46a191698657c5ca"
       url: "https://pub.dev"
     source: hosted
-    version: "27.1.57"
+    version: "27.1.58"
   term_glyph:
     dependency: transitive
     description:

+ 12 - 2
pubspec.yaml

@@ -55,7 +55,7 @@ dependencies:
   super_sliver_list: #^0.4.1
   #sticky_headers: #^0.3.0+2
   linear_progress_bar: #^1.1.2
-  supabase_auth_ui: ^0.5.4
+  #supabase_auth_ui: ^0.5.4
 
 dev_dependencies:
   flutter_test:
@@ -69,6 +69,17 @@ dev_dependencies:
   #json_serializable: #^6.6.1
   custom_lint:
   riverpod_lint: #^2.3.1
+  flutter_launcher_icons: "^0.14.1"
+
+flutter_launcher_icons:
+  android: "launcher_icon"
+#  ios: true
+  windows:
+    generate: true
+    image_path: "assets/logo.png"
+    icon_size: 48 # min:48, max:256, default: 48
+  image_path: "assets/logo.png"
+  min_sdk_android: 21 # android min sdk min:16, default 21
 
 flutter:
   uses-material-design: true 
@@ -77,7 +88,6 @@ flutter:
     - assets/fonts/
     - assets/csv/
 
-
 flutter_native_splash:
   # This package generates native code to customize Flutter's default white native splash screen
   # with background color and splash image.

BIN
windows/runner/resources/app_icon.ico