NotSooFriendly94

NotSooFriendly / TaskApp

Mar 28th, 2024
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 58.29 KB | Source Code | 0 0
  1. //main.dart -
  2.  
  3. import 'package:flutter/material.dart';
  4. import 'package:taskapp/work_screen.dart';
  5. import 'splash_page.dart';
  6. //import 'work_screen.dart';
  7. //import 'meeting_list_screen.dart';
  8.  
  9. void main() {
  10.   runApp(const MyApp());
  11. }
  12.  
  13. class MyApp extends StatelessWidget {
  14.   const MyApp({Key? key}) : super(key: key);
  15.  
  16.   @override
  17.   Widget build(BuildContext context) {
  18.     return MaterialApp(
  19.       title: 'Task Manager',
  20.       theme: ThemeData(
  21.         primarySwatch: Colors.blue,
  22.       ),
  23.       home: const SplashPage(),
  24.     );
  25.   }
  26. }
  27.  
  28. -------------------------------------
  29.  
  30. //splash_page.dart -
  31.  
  32. import 'package:flutter/material.dart';
  33. import 'login_page.dart'; // Importing LoginPage widget
  34.  
  35. class SplashPage extends StatefulWidget {
  36.   const SplashPage({Key? key}) : super(key: key);
  37.  
  38.   @override
  39.   _SplashPageState createState() => _SplashPageState();
  40. }
  41.  
  42. class _SplashPageState extends State<SplashPage> {
  43.   @override
  44.   void initState() {
  45.     super.initState();
  46.     // Add a delay before navigating to the LoginPage
  47.     Future.delayed(const Duration(seconds: 3), () {
  48.       // Navigate to the LoginPage and replace the SplashPage
  49.       Navigator.of(context).pushReplacement(
  50.         MaterialPageRoute(
  51.           builder: (context) => const LoginPage(),
  52.         ),
  53.       );
  54.     });
  55.   }
  56.  
  57.   @override
  58.   Widget build(BuildContext context) {
  59.     return const Scaffold(
  60.       backgroundColor: Color.fromARGB(255, 79, 16, 150),
  61.       body: Center(
  62.         child: Column(
  63.           mainAxisAlignment: MainAxisAlignment.center,
  64.           children: [
  65.             Text(
  66.               'Task Manager',
  67.               style: TextStyle(
  68.                 fontSize: 48,
  69.                 fontWeight: FontWeight.bold,
  70.                 color: Colors.white,
  71.               ),
  72.             ),
  73.             SizedBox(height: 20),
  74.             CircularProgressIndicator(
  75.               valueColor: AlwaysStoppedAnimation<Color>(
  76.                 Colors.white,
  77.               ),
  78.             ),
  79.           ],
  80.         ),
  81.       ),
  82.     );
  83.   }
  84. }
  85.  
  86.  
  87. -------------------------------------------
  88.  
  89. //login_page.dart -
  90.  
  91. import 'package:flutter/material.dart';
  92. import 'package:flutter/services.dart';
  93. import 'package:google_fonts/google_fonts.dart';
  94. import 'package:taskapp/home_screen.dart';
  95. import 'package:taskapp/work_screen.dart';
  96.  
  97. class LoginPage extends StatefulWidget {
  98.   const LoginPage({Key? key}) : super(key: key);
  99.  
  100.   @override
  101.   _LoginPageState createState() => _LoginPageState();
  102. }
  103.  
  104. class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver {
  105.   final String correctUsername = '**redacted**';
  106.   final String correctPassword = '**redacted***';
  107.   bool _homeSelected = false;
  108.   bool _workSelected = false;
  109.   String enteredUsername = '';
  110.   String enteredPassword = '';
  111.   bool _isLoading = false;
  112.   bool _loginFailed = false;
  113.   String _errorPromptMessage = '';
  114.   bool _keyboardVisible = false;
  115.  
  116.   @override
  117.   void initState() {
  118.     super.initState();
  119.     WidgetsBinding.instance!.addObserver(this);
  120.   }
  121.  
  122.   @override
  123.   void dispose() {
  124.     WidgetsBinding.instance!.removeObserver(this);
  125.     super.dispose();
  126.   }
  127.  
  128.   @override
  129.   void didChangeMetrics() {
  130.     final bool isKeyboardOpen = MediaQuery.of(context).viewInsets.bottom > 0;
  131.     setState(() {
  132.       _keyboardVisible = isKeyboardOpen;
  133.     });
  134.   }
  135.  
  136.   @override
  137.   Widget build(BuildContext context) {
  138.     return Scaffold(
  139.       appBar: AppBar(
  140.         toolbarHeight: 15,
  141.         backgroundColor: Color.fromARGB(255, 0, 0, 0),
  142.       ),
  143.       body: GestureDetector(
  144.         onTap: () {
  145.           FocusScope.of(context).unfocus();
  146.         },
  147.         child: Stack(
  148.           children: [
  149.             Container(
  150.               width: double.infinity,
  151.               height: double.infinity,
  152.               decoration: const BoxDecoration(
  153.                 gradient: LinearGradient(
  154.                   begin: Alignment.centerLeft,
  155.                   end: Alignment.centerRight,
  156.                   colors: [
  157.                     Color.fromARGB(255, 98, 68, 87),
  158.                     Color.fromARGB(255, 28, 28, 28),
  159.                   ],
  160.                 ),
  161.               ),
  162.             ),
  163.             SingleChildScrollView(
  164.               child: Center(
  165.                 child: Padding(
  166.                   padding: const EdgeInsets.all(0.0),
  167.                   child: Column(
  168.                     crossAxisAlignment: CrossAxisAlignment.center,
  169.                     children: [
  170.                       const SizedBox(height: 0.0),
  171.                       Row(
  172.                         mainAxisAlignment: MainAxisAlignment.start,
  173.                         children: [
  174.                           Align(
  175.                             alignment: Alignment.topLeft,
  176.                             child: Padding(
  177.                               padding: const EdgeInsets.only(
  178.                                   left: 5.0, right: 5.0, top: 0.0),
  179.                               child: Container(
  180.                                 transform:
  181.                                     Matrix4.translationValues(10.0, -10.0, 0.0),
  182.                                 child: Stack(
  183.                                   children: [
  184.                                     Text(
  185.                                       'Login',
  186.                                       style: GoogleFonts.dancingScript(
  187.                                         textStyle: TextStyle(
  188.                                           fontSize: 100,
  189.                                           fontWeight: FontWeight.bold,
  190.                                           foreground: Paint()
  191.                                             ..shader = const LinearGradient(
  192.                                               colors: [
  193.                                                 Color.fromARGB(103, 192, 192,
  194.                                                     192), // Light gray (silver-like)
  195.                                                 Color.fromARGB(72, 91, 91,
  196.                                                     91), // Medium gray (silver-like)
  197.                                                 Color.fromARGB(131, 56, 56,
  198.                                                     56), // Lighter gray (silver-like)
  199.                                                 Color.fromARGB(98, 183, 182,
  200.                                                     182), // Very light gray (silver-like)
  201.                                                 Color.fromARGB(60, 71, 71,
  202.                                                     71), // Almost white (silver-like)
  203.                                                 Color.fromARGB(112, 172, 172,
  204.                                                     172), // Almost white (silver-like)
  205.                                               ],
  206.                                             ).createShader(
  207.                                               const Rect.fromLTWH(
  208.                                                 30.0, // left position
  209.                                                 0.0, // top position
  210.                                                 110, // width
  211.                                                 80.0, // height
  212.                                               ),
  213.                                             ),
  214.                                         ),
  215.                                       ),
  216.                                     ),
  217.                                     Text(
  218.                                       'Login',
  219.                                       style: GoogleFonts.dancingScript(
  220.                                         textStyle: TextStyle(
  221.                                           fontSize: 100,
  222.                                           fontWeight: FontWeight.bold,
  223.                                           foreground: Paint()
  224.                                             ..style = PaintingStyle.stroke
  225.                                             ..strokeWidth = 0.7
  226.                                             ..color = Color.fromARGB(
  227.                                                 135, 225, 211, 211),
  228.                                         ),
  229.                                       ),
  230.                                     ),
  231.                                   ],
  232.                                 ),
  233.                               ),
  234.                             ),
  235.                           ),
  236.                           const SizedBox(height: 20),
  237.                           const SizedBox(
  238.                             height: 20,
  239.                             width: 20,
  240.                           ),
  241.                         ],
  242.                       ),
  243.                       const SizedBox(height: 50.0),
  244.                       AnimatedContainer(
  245.                         duration: const Duration(milliseconds: 500),
  246.                         curve: Curves.easeInOut,
  247.                         width: 300.0,
  248.                         height: 150,
  249.                         padding: const EdgeInsets.symmetric(horizontal: 10.0),
  250.                         decoration: BoxDecoration(
  251.                           color: const Color.fromARGB(0, 0, 0, 0),
  252.                           borderRadius: BorderRadius.circular(3.0),
  253.                           border: Border.all(
  254.                             width: 2.0,
  255.                             color: const Color.fromARGB(0, 255, 255, 255),
  256.                           ),
  257.                         ),
  258.                         child: Column(
  259.                           children: [
  260.                             Container(
  261.                               decoration: BoxDecoration(
  262.                                 color: const Color.fromARGB(78, 0, 0, 0),
  263.                                 borderRadius: BorderRadius.circular(3.0),
  264.                                 border: Border.all(
  265.                                   width: 2.0,
  266.                                   color:
  267.                                       const Color.fromARGB(82, 176, 176, 176),
  268.                                 ),
  269.                               ),
  270.                               child: TextFormField(
  271.                                 textAlign: TextAlign.center,
  272.                                 style: GoogleFonts.kodeMono(
  273.                                   fontSize: 32,
  274.                                   color: const Color.fromARGB(255, 0, 242, 255),
  275.                                 ),
  276.                                 decoration: InputDecoration.collapsed(
  277.                                   hintText: 'Username',
  278.                                   hintStyle: GoogleFonts.bebasNeue(
  279.                                     fontSize: 35,
  280.                                     color: const Color.fromARGB(
  281.                                         127, 152, 152, 152),
  282.                                   ),
  283.                                 ),
  284.                                 onChanged: (value) {
  285.                                   setState(() {
  286.                                     enteredUsername = value;
  287.                                   });
  288.                                 },
  289.                               ),
  290.                             ),
  291.                             const SizedBox(height: 20.0),
  292.                             Container(
  293.                               decoration: BoxDecoration(
  294.                                 color: const Color.fromARGB(78, 0, 0, 0),
  295.                                 borderRadius: BorderRadius.circular(3.0),
  296.                                 border: Border.all(
  297.                                   width: 2.0,
  298.                                   color:
  299.                                       const Color.fromARGB(82, 176, 176, 176),
  300.                                 ),
  301.                               ),
  302.                               child: TextFormField(
  303.                                 textAlign: TextAlign.center,
  304.                                 obscureText: true,
  305.                                 style: GoogleFonts.kodeMono(
  306.                                   fontSize: 32,
  307.                                   color: const Color.fromARGB(255, 0, 242, 255),
  308.                                 ),
  309.                                 decoration: InputDecoration.collapsed(
  310.                                   hintText: 'Password',
  311.                                   hintStyle: GoogleFonts.bebasNeue(
  312.                                     fontSize: 35,
  313.                                     color: const Color.fromARGB(
  314.                                         127, 152, 152, 152),
  315.                                   ),
  316.                                 ),
  317.                                 onChanged: (value) {
  318.                                   setState(() {
  319.                                     enteredPassword = value;
  320.                                   });
  321.                                 },
  322.                               ),
  323.                             ),
  324.                           ],
  325.                         ),
  326.                       ),
  327.                       const SizedBox(height: 20.0),
  328.                       Row(
  329.                         mainAxisAlignment: MainAxisAlignment.center,
  330.                         children: [
  331.                           Checkbox(
  332.                             value: _homeSelected,
  333.                             onChanged: (value) {
  334.                               setState(() {
  335.                                 _homeSelected = value!;
  336.                                 if (value) {
  337.                                   _workSelected = false;
  338.                                 }
  339.                               });
  340.                             },
  341.                             splashRadius: 200,
  342.                             materialTapTargetSize:
  343.                                 MaterialTapTargetSize.shrinkWrap,
  344.                             side: const BorderSide(
  345.                                 color: Color.fromARGB(255, 141, 85, 255),
  346.                                 width: 1.5),
  347.                             activeColor: const Color.fromARGB(255, 0, 183, 255),
  348.                             checkColor: const Color.fromARGB(255, 0, 0, 0),
  349.                           ),
  350.                           const Text(
  351.                             'Home',
  352.                             style: TextStyle(
  353.                                 fontSize: 25.0,
  354.                                 color: Color.fromARGB(196, 255, 255, 255)),
  355.                           ),
  356.                           const SizedBox(width: 45.0),
  357.                           Checkbox(
  358.                             value: _workSelected,
  359.                             onChanged: (value) {
  360.                               setState(() {
  361.                                 _workSelected = value!;
  362.                                 if (value) {
  363.                                   _homeSelected = false;
  364.                                 }
  365.                               });
  366.                             },
  367.                             splashRadius: 200,
  368.                             materialTapTargetSize:
  369.                                 MaterialTapTargetSize.shrinkWrap,
  370.                             side: const BorderSide(
  371.                                 color: Color.fromARGB(255, 141, 85, 255),
  372.                                 width: 1.5),
  373.                             activeColor: const Color.fromARGB(255, 0, 183, 255),
  374.                             checkColor: const Color.fromARGB(255, 0, 0, 0),
  375.                           ),
  376.                           const Text(
  377.                             'Work',
  378.                             style: TextStyle(
  379.                                 fontSize: 25.0,
  380.                                 color: Color.fromARGB(196, 255, 255, 255)),
  381.                           ),
  382.                         ],
  383.                       ),
  384.                       const SizedBox(height: 40.0),
  385.                       _isLoading
  386.                           ? const CircularProgressIndicator()
  387.                           : SizedBox(
  388.                               height: 40.0,
  389.                               width: 150.0,
  390.                               child: InkWell(
  391.                                 onTap: _login,
  392.                                 child: Container(
  393.                                   decoration: BoxDecoration(
  394.                                     borderRadius: BorderRadius.circular(5.0),
  395.                                     color: const Color.fromARGB(95, 96, 23, 85),
  396.                                     border: Border.all(
  397.                                       width: 2.0,
  398.                                       color: const Color.fromARGB(
  399.                                           255, 141, 85, 255),
  400.                                     ),
  401.                                   ),
  402.                                   child: const Center(
  403.                                     child: Text(
  404.                                       'Login',
  405.                                       style: TextStyle(
  406.                                         fontSize: 20.0,
  407.                                         fontWeight: FontWeight.bold,
  408.                                         color:
  409.                                             Color.fromARGB(136, 255, 255, 255),
  410.                                       ),
  411.                                     ),
  412.                                   ),
  413.                                 ),
  414.                               ),
  415.                             ),
  416.                       if (_loginFailed)
  417.                         Container(
  418.                           width: double.infinity,
  419.                           alignment: Alignment.bottomCenter,
  420.                           padding: const EdgeInsets.symmetric(vertical: 20.0),
  421.                           child: Text(
  422.                             _errorPromptMessage,
  423.                             style: GoogleFonts.kodeMono(
  424.                               fontSize: 16,
  425.                               color: const Color.fromARGB(255, 255, 255, 255),
  426.                               fontWeight: FontWeight.normal,
  427.                               decoration: TextDecoration.underline,
  428.                               decorationColor:
  429.                                   const Color.fromARGB(255, 255, 255, 255),
  430.                               decorationStyle: TextDecorationStyle.solid,
  431.                               decorationThickness: 1.0,
  432.                             ),
  433.                           ),
  434.                         ),
  435.                     ],
  436.                   ),
  437.                 ),
  438.               ),
  439.             ),
  440.             AnimatedPositioned(
  441.               duration: const Duration(milliseconds: 100),
  442.               curve: Curves.easeInOut,
  443.               bottom: _keyboardVisible ? 0 : 0,
  444.               left: _keyboardVisible ? 0 : 50,
  445.               child: AnimatedContainer(
  446.                 duration: const Duration(milliseconds: 100),
  447.                 curve: Curves.easeInOut,
  448.                 width: _keyboardVisible ? 45 : 200,
  449.                 height: _keyboardVisible ? 45 : 200,
  450.                 child: Image.asset(
  451.                   'assets/cat_galaxy.gif',
  452.                   repeat: ImageRepeat.noRepeat,
  453.                 ),
  454.               ),
  455.             ),
  456.           ],
  457.         ),
  458.       ),
  459.     );
  460.   }
  461.  
  462.   void showErrorPrompt(String message) {
  463.     setState(() {
  464.       _loginFailed = true;
  465.       _errorPromptMessage = message;
  466.     });
  467.     // Reset login failed state after 4 seconds
  468.     Future.delayed(const Duration(seconds: 2), () {
  469.       setState(() {
  470.         _loginFailed = false;
  471.         _isLoading = false;
  472.       });
  473.     });
  474.   }
  475.  
  476.   void _login() {
  477.     // Hide the keyboard
  478.     FocusScope.of(context).unfocus();
  479.  
  480.     setState(() {
  481.       _isLoading = true;
  482.     });
  483.  
  484.     // Simulate login process
  485.     Future.delayed(const Duration(seconds: 1), () {
  486.       // Check if username and password are empty
  487.       if (enteredUsername.isEmpty &&
  488.           enteredPassword.isEmpty &&
  489.           !_homeSelected &&
  490.           !_workSelected) {
  491.         showErrorPrompt('Please fill the form to continue');
  492.       } else if (enteredUsername.isEmpty && enteredPassword.isEmpty) {
  493.         showErrorPrompt('Please enter a username and password');
  494.       }
  495.       // Check if username is missing
  496.       else if (enteredUsername.isEmpty) {
  497.         showErrorPrompt('Please enter a valid username to continue');
  498.       }
  499.       // Check if password is missing
  500.       else if (enteredPassword.isEmpty) {
  501.         showErrorPrompt('Please enter a valid password to continue');
  502.       }
  503.       // Check if no checkbox is selected
  504.       else if (!_homeSelected && !_workSelected) {
  505.         showErrorPrompt('Please select a box to continue');
  506.       }
  507.       // Check login credentials
  508.       else if (enteredUsername == correctUsername &&
  509.           enteredPassword == correctPassword) {
  510.         // Simulate loading for 4 seconds
  511.         Future.delayed(const Duration(seconds: 2), () {
  512.           // Navigate to HomePage with a smooth transition
  513.           Navigator.pushReplacement(
  514.             context,
  515.             PageRouteBuilder(
  516.               transitionDuration: const Duration(milliseconds: 800),
  517.               reverseTransitionDuration: const Duration(milliseconds: 800),
  518.               pageBuilder: (context, animation, secondaryAnimation) {
  519.                 return FadeTransition(
  520.                   opacity: animation,
  521.                   child:
  522.                       _homeSelected ? const HomeScreen() : const WorkScreen(),
  523.                 );
  524.               },
  525.             ),
  526.           );
  527.         });
  528.       }
  529.       // Invalid credentials
  530.       else {
  531.         showErrorPrompt('Username or Password is incorrect, please try again');
  532.       }
  533.     });
  534.   }
  535. }
  536.  
  537.  
  538. ----------------------------------------
  539.    
  540. //work_screen.dart -
  541.  
  542. import 'dart:convert';
  543. import 'dart:io';
  544.  
  545. import 'package:flutter/material.dart';
  546. import 'package:flutter/widgets.dart';
  547. import 'package:intl/intl.dart';
  548. import 'package:shared_preferences/shared_preferences.dart';
  549. import 'package:path_provider/path_provider.dart';
  550. import 'package:flutter_moving_background/flutter_moving_background.dart';
  551.  
  552. // Import the MeetingListScreen
  553. import 'meeting_list_screen.dart';
  554.  
  555. class WorkScreen extends StatefulWidget {
  556.   const WorkScreen({Key? key}) : super(key: key);
  557.  
  558.   @override
  559.   _WorkScreenState createState() => _WorkScreenState();
  560. }
  561.  
  562. class _WorkScreenState extends State<WorkScreen> {
  563.   final TextEditingController _meetingNameController = TextEditingController();
  564.   final TextEditingController _jobNameController = TextEditingController();
  565.   final TextEditingController _actionController = TextEditingController();
  566.   String? meetingName;
  567.   String? jobName;
  568.   String? currentAction;
  569.   List<String> actions = [];
  570.   List<Job> jobs = [];
  571.   ScrollController _scrollController = ScrollController();
  572.   bool _isScrolled = false;
  573.  
  574.   @override
  575.   void initState() {
  576.     super.initState();
  577.     _scrollController.addListener(_onScroll);
  578.   }
  579.  
  580.   @override
  581.   void dispose() {
  582.     _scrollController.removeListener(_onScroll);
  583.     _scrollController.dispose();
  584.     super.dispose();
  585.   }
  586.  
  587.   void _onScroll() {
  588.     setState(() {
  589.       _isScrolled =
  590.           _scrollController.hasClients && _scrollController.offset > 0;
  591.     });
  592.   }
  593.  
  594.   void _startMeeting() {
  595.   final String newMeetingName = _meetingNameController.text.trim();
  596.   if (newMeetingName.isNotEmpty) {
  597.     setState(() {
  598.       final now = DateTime.now();
  599.       final formattedDate =
  600.           '$newMeetingName (${DateFormat.yMd().add_jms().format(now)})';
  601.       meetingName = formattedDate;
  602.       _meetingNameController.clear();
  603.     });
  604.   } else {
  605.     // Show a styled Snackbar
  606.     ScaffoldMessenger.of(context).showSnackBar(
  607.       SnackBar(
  608.         behavior: SnackBarBehavior.floating, // Makes the Snackbar float
  609.         elevation: 0, // Remove shadow
  610.         content: Container(
  611.           height: 40, // Set height to 40
  612.           alignment: Alignment.center, // Align content to center
  613.           padding: const EdgeInsets.symmetric(horizontal: 16.0), // Add horizontal padding
  614.           decoration: BoxDecoration(
  615.             color: const Color.fromARGB(133, 255, 0, 0), // Background color
  616.             borderRadius: BorderRadius.circular(20), // Rounded corners
  617.             border: Border.all(color: Colors.white), // White border
  618.           ),
  619.           child: const Text(
  620.             'Please write a meeting name',
  621.             textAlign: TextAlign.center, // Align text to center
  622.             style: TextStyle(
  623.               color: Colors.white, // White font color
  624.               fontSize: 15, // Font size
  625.             ),
  626.           ),
  627.         ),
  628.         duration: const Duration(seconds: 4),
  629.         margin: const EdgeInsets.only(bottom: 20), // Padding from bottom
  630.       ),
  631.     );
  632.   }
  633. }
  634.  
  635. void _addJob() {
  636.   final String newJobName = _jobNameController.text.trim();
  637.   if (newJobName.isNotEmpty) {
  638.     setState(() {
  639.       jobName = newJobName;
  640.       jobs.add(Job(jobName!, [])); // Add job with empty actions list
  641.       _jobNameController.clear();
  642.     });
  643.   } else {
  644.     // Show a styled Snackbar
  645.     ScaffoldMessenger.of(context).showSnackBar(
  646.       SnackBar(
  647.         behavior: SnackBarBehavior.floating, // Makes the Snackbar float
  648.         elevation: 0, // Remove shadow
  649.         content: Container(
  650.           height: 40, // Set height to 40
  651.           alignment: Alignment.center, // Align content to center
  652.           padding: const EdgeInsets.symmetric(horizontal: 16.0), // Add horizontal padding
  653.           decoration: BoxDecoration(
  654.             color: const Color.fromARGB(133, 255, 0, 0), // Background color
  655.             borderRadius: BorderRadius.circular(20), // Rounded corners
  656.             border: Border.all(color: Colors.white), // White border
  657.           ),
  658.           child: const Text(
  659.             'Please write a job name',
  660.             textAlign: TextAlign.center, // Align text to center
  661.             style: TextStyle(
  662.               color: Colors.white, // White font color
  663.               fontSize: 15, // Font size
  664.             ),
  665.           ),
  666.         ),
  667.         duration: const Duration(seconds: 4),
  668.         margin: const EdgeInsets.only(bottom: 20), // Padding from bottom
  669.       ),
  670.     );
  671.   }
  672. }
  673.  
  674. void _addAction() {
  675.   final newAction = _actionController.text.trim();
  676.   if (newAction.isNotEmpty) {
  677.     setState(() {
  678.       actions.add(newAction);
  679.       _actionController.clear();
  680.     });
  681.   } else {
  682.     // Show a styled Snackbar
  683.     ScaffoldMessenger.of(context).showSnackBar(
  684.       SnackBar(
  685.         behavior: SnackBarBehavior.floating, // Makes the Snackbar float
  686.         elevation: 0, // Remove shadow
  687.         content: Container(
  688.           height: 40, // Set height to 40
  689.           alignment: Alignment.center, // Align content to center
  690.           padding: const EdgeInsets.symmetric(horizontal: 16.0), // Add horizontal padding
  691.           decoration: BoxDecoration(
  692.             color: const Color.fromARGB(133, 255, 0, 0), // Background color
  693.             borderRadius: BorderRadius.circular(20), // Rounded corners
  694.             border: Border.all(color: Colors.white), // White border
  695.           ),
  696.           child: const Text(
  697.             'Please enter an action',
  698.             textAlign: TextAlign.center, // Align text to center
  699.             style: TextStyle(
  700.               color: Colors.white, // White font color
  701.               fontSize: 15, // Font size
  702.             ),
  703.           ),
  704.         ),
  705.         duration: const Duration(seconds: 4),
  706.         margin: const EdgeInsets.only(bottom: 20), // Padding from bottom
  707.       ),
  708.     );
  709.   }
  710. }
  711.  
  712.   void _completeActions() {
  713.     setState(() {
  714.       if (jobName != null) {
  715.         for (var job in jobs) {
  716.           if (job.name == jobName) {
  717.             job.actions.addAll(actions);
  718.           }
  719.         }
  720.         jobName = null;
  721.         actions.clear();
  722.       }
  723.     });
  724.   }
  725.  
  726.   void _deleteJob(Job job) {
  727.     setState(() {
  728.       jobs.remove(job);
  729.     });
  730.   }
  731.  
  732.   void _editJob(Job job) {
  733.     // Create controllers to manage the text editing for each action
  734.     List<TextEditingController> controllers = List.generate(job.actions.length,
  735.         (index) => TextEditingController(text: job.actions[index]));
  736.  
  737.     showDialog(
  738.       context: context,
  739.       builder: (BuildContext context) {
  740.         return AlertDialog(
  741.           title: const Text('Edit Actions'),
  742.           content: Column(
  743.             mainAxisSize: MainAxisSize.min,
  744.             children: [
  745.               for (int i = 0; i < job.actions.length; i++) ...[
  746.                 TextField(
  747.                   controller: controllers[i],
  748.                   onChanged: (value) {
  749.                     // Update the corresponding action in the job actions list
  750.                     job.actions[i] = value;
  751.                   },
  752.                   onSubmitted: (newValue) {
  753.                     // Do nothing when submitted
  754.                   },
  755.                 ),
  756.                 const SizedBox(height: 10),
  757.               ],
  758.             ],
  759.           ),
  760.           actions: <Widget>[
  761.             TextButton(
  762.               onPressed: () {
  763.                 Navigator.of(context)
  764.                     .pop(); // Close the dialog without saving changes
  765.               },
  766.               child: const Text('CANCEL'),
  767.             ),
  768.             ElevatedButton(
  769.               onPressed: () {
  770.                 // Close the dialog
  771.                 Navigator.of(context).pop();
  772.               },
  773.               child: const Text('SAVE CHANGES'),
  774.             ),
  775.           ],
  776.         );
  777.       },
  778.     );
  779.   }
  780.  
  781.   void _meetingFinished() async {
  782.     // Check if meeting name is not null
  783.     if (meetingName != null) {
  784.       // Sanitize the meeting name to remove invalid characters
  785.       final sanitizedMeetingName = meetingName!
  786.           .replaceAll(RegExp(r'[^\w\s]+'),
  787.               '') // Replace non-alphanumeric characters with empty string
  788.           .replaceAll(RegExp(r'\s+'),
  789.               '_'); // Replace whitespace characters with underscore
  790.  
  791.       // Save meeting details locally
  792.       final SharedPreferences prefs = await SharedPreferences.getInstance();
  793.       final meetingDetails = <String, dynamic>{
  794.         'meetingName': meetingName,
  795.         'jobs': jobs
  796.             .map((job) => {'name': job.name, 'actions': job.actions})
  797.             .toList(),
  798.       };
  799.  
  800.       // Log the JSON data to be saved
  801.       print('JSON data to be saved: ${jsonEncode(meetingDetails)}');
  802.  
  803.       // Save meeting details to SharedPreferences
  804.       await prefs.setString('meetingDetails', jsonEncode(meetingDetails));
  805.  
  806.       // Construct the directory path
  807.       final appDocumentsDirectory = await getApplicationDocumentsDirectory();
  808.       final String directoryPath =
  809.           '/storage/emulated/0/Android/data/com.example.taskapp/files/TaskApp Data/';
  810.  
  811.       // Create the directory if it doesn't exist
  812.       final Directory workDirectory = Directory(directoryPath);
  813.       if (!await workDirectory.exists()) {
  814.         await workDirectory.create(recursive: true);
  815.       }
  816.  
  817.       // Construct the file path using the sanitized meeting name and the desired directory
  818.       final String filePath = '$directoryPath/$sanitizedMeetingName.json';
  819.  
  820.       // Write data to a file with the specified file path
  821.       final File file = File(filePath);
  822.       await file.writeAsString(jsonEncode(meetingDetails));
  823.       print('Data saved to: ${file.path}');
  824.  
  825.       // Clear current meeting details
  826.       setState(() {
  827.         meetingName = null;
  828.         jobs.clear();
  829.       });
  830.     } else {
  831.       // Show a snack bar if meeting name is null
  832.       ScaffoldMessenger.of(context).showSnackBar(
  833.         const SnackBar(
  834.           content: Text(
  835.             'Please start a meeting before finishing it',
  836.             style: TextStyle(color: Colors.white),
  837.           ),
  838.           backgroundColor: Colors.red,
  839.           duration: Duration(seconds: 2),
  840.         ),
  841.       );
  842.     }
  843.   }
  844.  
  845.   // Function to navigate to MeetingListScreen
  846.   void _viewMeetings() {
  847.     Navigator.push(
  848.       context,
  849.       MaterialPageRoute(builder: (context) => const MeetingListScreen()),
  850.     );
  851.   }
  852.  
  853.   @override
  854.   Widget build(BuildContext context) {
  855.     return Stack(
  856.       children: [
  857.         SizedBox (
  858.             width: MediaQuery.of(context).size.width,
  859.   height: MediaQuery.of(context).size.height,
  860.         child: const MovingBackground(
  861.           backgroundColor: Colors.transparent,
  862.           circles: [
  863.             MovingCircle(color: Color.fromARGB(115, 148, 0, 174), blurSigma: 170),
  864.             MovingCircle(color: Color.fromARGB(107, 131, 0, 0), blurSigma: 90),
  865.             MovingCircle(color: Color.fromARGB(129, 59, 0, 160), blurSigma: 120),
  866.             MovingCircle(color: Color.fromARGB(115, 170, 14, 0), blurSigma: 60),
  867.           ],
  868.         ),
  869.         ),
  870.         Scaffold(
  871.           backgroundColor: Colors.transparent,
  872.           appBar: PreferredSize(
  873.             preferredSize: const Size.fromHeight(90.0),
  874.             child: Column(
  875.               children: [
  876.                 AppBar(
  877.                   backgroundColor: Colors.transparent,
  878.                   title: Text(
  879.                     meetingName ?? 'Work Screen',
  880.                     style: const TextStyle(color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0),
  881.                     textAlign: TextAlign.center,
  882.                   ),
  883.                   centerTitle: true,
  884.                 ),
  885.                 if (meetingName != null)
  886.                   Container(
  887.                     alignment: Alignment.center,
  888.                     height: 30.0,
  889.                     width: double.maxFinite,
  890.                     child: ElevatedButton(
  891.                       onPressed: _meetingFinished,
  892.                       style: ButtonStyle(
  893.                         backgroundColor: MaterialStateProperty.all<Color>(
  894.                             const Color.fromARGB(255, 30, 108, 177)),
  895.                         foregroundColor: MaterialStateProperty.all<Color>(
  896.                             const Color.fromARGB(255, 255, 255, 255)),
  897.                         side: MaterialStateProperty.all<BorderSide>(
  898.                             const BorderSide(
  899.                                 color: Color.fromARGB(255, 0, 200, 255))),
  900.                         shape: MaterialStateProperty.all<OutlinedBorder>(
  901.                           RoundedRectangleBorder(
  902.                             borderRadius: BorderRadius.circular(
  903.                                 15.0), // Adjust the radius as needed
  904.                           ),
  905.                         ),
  906.                       ),
  907.                       child: const Text('Finish and Save Meeting',
  908.                           style: TextStyle(
  909.                               color: Color.fromARGB(255, 0, 0, 0),
  910.                               fontSize: 17.0,
  911.                               fontWeight: FontWeight.w700)),
  912.                     ),
  913.                   ),
  914.               ],
  915.             ),
  916.           ),
  917.           body: SingleChildScrollView(
  918.             controller: _scrollController,
  919.             child: Padding(
  920.               padding: const EdgeInsets.all(16.0),
  921.               child: Column(
  922.                 crossAxisAlignment: CrossAxisAlignment.start,
  923.                 children: [
  924.                   if (meetingName == null) ...[
  925.                     const Text(
  926.                       'Meeting Name',
  927.                       style: TextStyle(
  928.                           color: Color.fromARGB(255, 255, 255, 255), fontSize: 25.0, fontWeight: FontWeight.bold),
  929.                     ),
  930.                     TextField(
  931.                       style: const TextStyle(color: Color.fromARGB(255, 0, 200, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
  932.                       controller: _meetingNameController,
  933.                       decoration: const InputDecoration(
  934.                         hintText: 'Enter Meeting Name', hintStyle:TextStyle(fontSize: 15.0, color: Color.fromARGB(139, 107, 107, 107))
  935.                       ),
  936.                       onSubmitted: (_) {
  937.                         _startMeeting();
  938.                       },
  939.                     ),
  940.                   ],
  941.                   const SizedBox(
  942.                       height:
  943.                           20.0), // Move "Meeting Finished" button below blue meeting name header
  944.                   if (meetingName != null && jobName == null) ...[
  945.                     const Text(
  946.                       'Task to be completed -',
  947.                       style: TextStyle(
  948.                           fontSize: 20.0, color: Colors.white, fontWeight: FontWeight.bold),
  949.                     ),
  950.                     TextField(
  951.                       style: const TextStyle(fontSize: 20.0,
  952.                        color: Color.fromARGB(255, 0, 179, 255)),
  953.                       controller: _jobNameController,
  954.                       decoration: const InputDecoration(
  955.                         hintText: 'Enter Task', hintStyle:TextStyle(fontSize: 15.0, color: Color.fromARGB(139, 107, 107, 107))
  956.                       ),
  957.                       onSubmitted: (_) {
  958.                         _addJob();
  959.                       },
  960.                     ),
  961.                   ],
  962.                   if (jobName != null) ...[
  963.                     const SizedBox(height: 20.0),
  964.                     Text(
  965.                       jobName!,
  966.                       style: const TextStyle(
  967.                           color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
  968.                     ),
  969.                     const SizedBox(height: 10.0),
  970.                     const Text(
  971.                       'Actions Required',
  972.                       style: TextStyle(
  973.                           color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold),
  974.                     ),
  975.                     TextField(
  976.                       style: const TextStyle(fontSize: 20.0,
  977.                        color: Color.fromARGB(255, 0, 179, 255)),
  978.                       controller: _actionController,
  979.                       decoration: const InputDecoration(
  980.                         hintText: 'Enter Action', hintStyle:TextStyle(fontSize: 15.0, color: Color.fromARGB(139, 107, 107, 107))
  981.                       ),
  982.                       textInputAction: TextInputAction.done,
  983.                       onSubmitted: (_) {
  984.                         _addAction();
  985.                       },
  986.                     ),
  987.                     const SizedBox(height: 20.0),
  988.                     Center(
  989.   child: ElevatedButton(
  990.     onPressed: _completeActions,
  991.     style: ButtonStyle(
  992.       backgroundColor: MaterialStateProperty.all<Color>(
  993.           const Color.fromARGB(255, 30, 108, 177)),
  994.       foregroundColor: MaterialStateProperty.all<Color>(
  995.           const Color.fromARGB(255, 22, 0, 0)),
  996.       side: MaterialStateProperty.all<BorderSide>(
  997.           const BorderSide(
  998.               color: Color.fromARGB(255, 0, 200, 255))),
  999.       shape: MaterialStateProperty.all<OutlinedBorder>(
  1000.         RoundedRectangleBorder(
  1001.           borderRadius: BorderRadius.circular(
  1002.               20.0), // Adjust the radius as needed
  1003.         ),
  1004.       ),
  1005.     ),
  1006.     child: const Text('Add Actions and Save Task', style: TextStyle( fontSize: 17.0)),
  1007.   ),
  1008. ),
  1009.                     const SizedBox(height: 50.0),
  1010.                     const Text(
  1011.                       'Logged Actions:',
  1012.                       style: TextStyle(
  1013.                           color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
  1014.                     ),
  1015.                     const SizedBox(height: 15.0),
  1016.                     for (var action in actions) ...[
  1017.                       Text(
  1018.                         '- $action',
  1019.                         style: const TextStyle(color: Color.fromARGB(255, 255, 255, 255), fontSize: 20.0),
  1020.                       ),
  1021.                     ],
  1022.                   ],
  1023.                   const SizedBox(height: 80.0),
  1024.                   const Text(
  1025.                     'Task List:',
  1026.                     style:
  1027.                         TextStyle(color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
  1028.                   ),
  1029.                   const SizedBox(height: 20.0),
  1030.                   for (var job in jobs) ...[
  1031.                     const SizedBox(
  1032.                       height: 10.0,
  1033.                     ),
  1034.                     Dismissible(
  1035.                       key: Key(job.name),
  1036.                       direction: DismissDirection.horizontal,
  1037.                       background: Container(
  1038.                         color: Colors.blue,
  1039.                         alignment: Alignment.centerLeft,
  1040.                         child: const Padding(
  1041.                           padding: EdgeInsets.only(left: 20.0),
  1042.                           child: Icon(Icons.edit, color: Colors.white),
  1043.                         ),
  1044.                       ),
  1045.                       secondaryBackground: Container(
  1046.                         color: Colors.red,
  1047.                         alignment: Alignment.centerRight,
  1048.                         child: const Padding(
  1049.                           padding: EdgeInsets.only(right: 20.0),
  1050.                           child: Icon(Icons.delete, color: Colors.white),
  1051.                         ),
  1052.                       ),
  1053.                       confirmDismiss: (direction) async {
  1054.                         if (direction == DismissDirection.endToStart) {
  1055.                           // Deleting job
  1056.                           return await showDialog(
  1057.                             context: context,
  1058.                             builder: (BuildContext context) {
  1059.                               return AlertDialog(
  1060.                                 title: const Text('Confirm Delete'),
  1061.                                 content: const Text(
  1062.                                     'Are you sure you want to delete this job?'),
  1063.                                 actions: <Widget>[
  1064.                                   TextButton(
  1065.                                     onPressed: () =>
  1066.                                         Navigator.of(context).pop(false),
  1067.                                     child: const Text('CANCEL'),
  1068.                                   ),
  1069.                                   TextButton(
  1070.                                     onPressed: () =>
  1071.                                         Navigator.of(context).pop(true),
  1072.                                     child: const Text('DELETE'),
  1073.                                   ),
  1074.                                 ],
  1075.                               );
  1076.                             },
  1077.                           );
  1078.                         } else {
  1079.                           // Editing job
  1080.                           _editJob(job);
  1081.                           return false;
  1082.                         }
  1083.                       },
  1084.                       onDismissed: (direction) {
  1085.                         if (direction == DismissDirection.endToStart) {
  1086.                           _deleteJob(job);
  1087.                         }
  1088.                       },
  1089.                       child: ExpansionTile(
  1090.                         title: Text(job.name),
  1091.                         textColor: Colors.white,
  1092.                         collapsedTextColor: Colors.white,
  1093.                         collapsedIconColor: const Color.fromARGB(255, 0, 0, 0),
  1094.                         collapsedBackgroundColor:
  1095.                             const Color.fromARGB(77, 4, 155, 255),
  1096.                         collapsedShape: RoundedRectangleBorder(
  1097.                           borderRadius: BorderRadius.circular(
  1098.                               15.0), // Adjust the radius as needed
  1099.                         ),
  1100.                         shape: RoundedRectangleBorder(
  1101.                           borderRadius: BorderRadius.circular(
  1102.                               15.0), // Adjust the radius as needed
  1103.                         ),
  1104.                         backgroundColor:
  1105.                             const Color.fromARGB(101, 4, 155, 255),
  1106.                         iconColor: const Color.fromARGB(255, 0, 0, 0),
  1107.                         children: [
  1108.                           for (var action in job.actions) ...[
  1109.                             Text(
  1110.                               '- $action',
  1111.                               style: const TextStyle(color: Color.fromARGB(255, 255, 255, 255), fontSize:  20.0),
  1112.                             ),
  1113.                           ],
  1114.                         ], // Change tile color here
  1115.                       ),
  1116.                     ),
  1117.                   ],
  1118.                 ],
  1119.               ),
  1120.             ),
  1121.           ),
  1122.           floatingActionButtonLocation:
  1123.               FloatingActionButtonLocation.centerFloat,
  1124.           floatingActionButton: AnimatedOpacity(
  1125.             opacity: _isScrolled
  1126.                 ? 0.35
  1127.                 : 1, // Change opacity based on scroll position
  1128.             duration: const Duration(
  1129.                 milliseconds: 200), // Add duration for a smoother transition
  1130.             child: SizedBox(
  1131.               height: 25, // Change the height of the button
  1132.               child: ElevatedButton(
  1133.                 onPressed: _viewMeetings,
  1134.                 style: ButtonStyle(
  1135.       backgroundColor: MaterialStateProperty.all<Color>(
  1136.           const Color.fromARGB(255, 30, 108, 177)),
  1137.       foregroundColor: MaterialStateProperty.all<Color>(
  1138.           const Color.fromARGB(255, 255, 255, 255)),
  1139.       side: MaterialStateProperty.all<BorderSide>(
  1140.           const BorderSide(
  1141.               color: Color.fromARGB(255, 0, 200, 255))),
  1142.       shape: MaterialStateProperty.all<OutlinedBorder>(
  1143.         RoundedRectangleBorder(
  1144.           borderRadius: BorderRadius.circular(
  1145.               15.0), // Adjust the radius as needed
  1146.         ),
  1147.                   ),
  1148.                 ),
  1149.                 child: const Text('View Meetings',
  1150.                     style: TextStyle(
  1151.                         color: Color.fromARGB(255, 0, 0, 0),
  1152.                         fontSize: 17.0)),
  1153.               ),
  1154.             ),
  1155.           ),
  1156.         )
  1157.       ],
  1158.     );
  1159.   }
  1160. }
  1161.  
  1162. class Job {
  1163.   final String name;
  1164.   List<String> actions;
  1165.  
  1166.   Job(this.name, this.actions);
  1167. }
  1168.  
  1169. void main() {
  1170.   runApp(const MaterialApp(
  1171.     home: WorkScreen(),
  1172.   ));
  1173. }
  1174.  
  1175.  
  1176. --------------------------
  1177.    
  1178. //meeting_list_screen.dart -
  1179.  
  1180. import 'dart:convert';
  1181. import 'dart:io';
  1182. import 'package:flutter/material.dart';
  1183. import 'package:path_provider/path_provider.dart';
  1184. import 'package:enough_mail/enough_mail.dart';
  1185. import 'package:animated_glitch/animated_glitch.dart';
  1186.  
  1187. class MeetingListScreen extends StatefulWidget {
  1188.   const MeetingListScreen({Key? key}) : super(key: key);
  1189.  
  1190.   @override
  1191.   _MeetingListScreenState createState() => _MeetingListScreenState();
  1192. }
  1193.  
  1194. class _MeetingListScreenState extends State<MeetingListScreen> {
  1195.   List<Map<String, dynamic>> _meetings = [];
  1196.  
  1197.   @override
  1198.   void initState() {
  1199.     super.initState();
  1200.     _loadMeetings();
  1201.   }
  1202.  
  1203.   Future<void> _loadMeetings() async {
  1204.     Directory? externalDir = await getExternalStorageDirectory();
  1205.     if (externalDir != null) {
  1206.       const String directoryPath =
  1207.           '/storage/emulated/0/Android/data/com.example.taskapp/files/TaskApp Data/';
  1208.       final Directory directory = Directory(directoryPath);
  1209.  
  1210.       if (await directory.exists()) {
  1211.         List<FileSystemEntity> files = directory.listSync();
  1212.         for (var file in files) {
  1213.           if (file.path.endsWith('.json') &&
  1214.               FileSystemEntity.isFileSync(file.path)) {
  1215.             final String data = await File(file.path).readAsString();
  1216.             final Map<String, dynamic> meetingJson = jsonDecode(data);
  1217.             meetingJson['jobs'] =
  1218.                 List<Map<String, dynamic>>.from(meetingJson['jobs']);
  1219.             _meetings.add(meetingJson);
  1220.           }
  1221.         }
  1222.         setState(() {});
  1223.       } else {
  1224.         print('Directory does not exist.');
  1225.       }
  1226.     } else {
  1227.       print('Failed to get external storage directory.');
  1228.     }
  1229.   }
  1230.  
  1231.   Future<void> _sendEmail(
  1232.       String meetingName, List<Map<String, dynamic>> jobs) async {
  1233.     final client = SmtpClient('smtp.gmail.com', isLogEnabled: true);
  1234.     try {
  1235.       await client.connectToServer('smtp.gmail.com', 465, isSecure: true);
  1236.       await client.ehlo();
  1237.       await client.authenticate(
  1238.           '****redacted***', '**redacted**', AuthMechanism.login);
  1239.  
  1240.       String emailBody = '';
  1241.       final List<String> colors = [
  1242.         '#FF0000',
  1243.         '#FF8700',
  1244.         '#FFD300',
  1245.         '#DEFF0A',
  1246.         '#A1FF0A',
  1247.         '#0AFF99',
  1248.         '#0AEFFF',
  1249.         '#147DF5',
  1250.         '#580AFF',
  1251.         '#BE0AFF'
  1252.       ];
  1253.       int colorIndex = 0;
  1254.       for (var job in jobs) {
  1255.         final String color = colors[colorIndex];
  1256.         emailBody += '<font size="4" color="$color">${job['name']}</font><br>';
  1257.  
  1258.         for (var action in job['actions']) {
  1259.           emailBody += '&emsp; • $action<br>';
  1260.         }
  1261.         emailBody += '<br>';
  1262.  
  1263.         colorIndex = (colorIndex + 1) % colors.length;
  1264.  
  1265.         emailBody += '<div style="width: 100%; text-align: left;">';
  1266.         for (int i = 0; i < 20; i++) {
  1267.           emailBody +=
  1268.               '<span style="color: ${colors[i % colors.length]}; font-size: 3em;">-</span>';
  1269.         }
  1270.         emailBody += '</div><br>';
  1271.       }
  1272.  
  1273.       final builder = MessageBuilder.prepareMultipartAlternativeMessage(
  1274.         plainText: 'Meeting: $meetingName\n\n$emailBody',
  1275.         htmlText: '<p><b>Meeting: $meetingName</b></p>$emailBody',
  1276.       )
  1277.         ..from = [const MailAddress('TaskApp Bot', '**redacted**')]
  1278.         ..to = [const MailAddress('**C**', '**redacted**')]
  1279.         ..subject = 'Meeting: $meetingName';
  1280.  
  1281.       final mimeMessage = builder.buildMimeMessage();
  1282.       final sendResponse = await client.sendMessage(mimeMessage);
  1283.       print('Message sent: ${sendResponse.isOkStatus}');
  1284.     } catch (e) {
  1285.       print('Failed to send email: $e');
  1286.     } finally {
  1287.       await client.disconnect();
  1288.     }
  1289.   }
  1290.  
  1291.   @override
  1292.   Widget build(BuildContext context) {
  1293.     return Scaffold(
  1294.       appBar: AppBar(
  1295.         backgroundColor: const Color.fromARGB(255, 0, 0, 0),
  1296.         title: const Text(
  1297.           'Saved Meetings',
  1298.           style: TextStyle(color: Colors.white),
  1299.         ),
  1300.         iconTheme: const IconThemeData(color: Colors.white),
  1301.       ),
  1302.       body: Stack(
  1303.         children: [
  1304.           AnimatedGlitch.shader(
  1305.             child: Image.asset(
  1306.               'assets/leaf_bg.jpeg',
  1307.               fit: BoxFit.cover,
  1308.               height: double.maxFinite,
  1309.               width: double.infinity,
  1310.             ),
  1311.           ),
  1312.           const SizedBox(height: 200.0, width: 50),
  1313.           ListView.builder(
  1314.             itemCount: _meetings.length,
  1315.             itemBuilder: (context, index) {
  1316.               final meeting = _meetings[index];
  1317.               return Column(
  1318.                 children: [
  1319.                   Dismissible(
  1320.                     key: Key(meeting['meetingName']),
  1321.                     direction: DismissDirection.horizontal,
  1322.                     background: Container(
  1323.                       color: Colors.green,
  1324.                       child: const Align(
  1325.                         alignment: Alignment.centerRight,
  1326.                         child: Padding(
  1327.                           padding: EdgeInsets.only(right: 20.0),
  1328.                           child: Icon(
  1329.                             Icons.email,
  1330.                             color: Colors.white,
  1331.                           ),
  1332.                         ),
  1333.                       ),
  1334.                     ),
  1335.                     secondaryBackground: Container(
  1336.                       color: Colors.red,
  1337.                       child: const Align(
  1338.                         alignment: Alignment.centerLeft,
  1339.                         child: Padding(
  1340.                           padding: EdgeInsets.only(left: 20.0),
  1341.                           child: Icon(
  1342.                             Icons.delete,
  1343.                             color: Colors.white,
  1344.                           ),
  1345.                         ),
  1346.                       ),
  1347.                     ),
  1348.                     confirmDismiss: (direction) async {
  1349.                       if (direction == DismissDirection.startToEnd) {
  1350.                         return await showDialog(
  1351.                           context: context,
  1352.                           builder: (BuildContext context) {
  1353.                             return AlertDialog(
  1354.                               title: const Text('Email Meeting'),
  1355.                               content: Text(
  1356.                                   'Are you sure you want to email "${meeting['meetingName']}"?'),
  1357.                               actions: <Widget>[
  1358.                                 TextButton(
  1359.                                   onPressed: () =>
  1360.                                       Navigator.of(context).pop(false),
  1361.                                   child: const Text('Cancel'),
  1362.                                 ),
  1363.                                 TextButton(
  1364.                                   onPressed: () {
  1365.                                     _sendEmail(meeting['meetingName'],
  1366.                                         meeting['jobs']);
  1367.                                     Navigator.of(context).pop(true);
  1368.                                   },
  1369.                                   child: const Text('Send'),
  1370.                                 ),
  1371.                               ],
  1372.                             );
  1373.                           },
  1374.                         );
  1375.                       } else {
  1376.                         return await showDialog(
  1377.                           context: context,
  1378.                           builder: (BuildContext context) {
  1379.                             return AlertDialog(
  1380.                               title: const Text('Delete Meeting'),
  1381.                               content: Text(
  1382.                                   'Are you sure you want to delete "${meeting['meetingName']}"?'),
  1383.                               actions: <Widget>[
  1384.                                 TextButton(
  1385.                                   onPressed: () =>
  1386.                                       Navigator.of(context).pop(false),
  1387.                                   child: const Text('Cancel'),
  1388.                                 ),
  1389.                                 TextButton(
  1390.                                   onPressed: () {
  1391.                                     Navigator.of(context).pop(true);
  1392.                                   },
  1393.                                   child: const Text('Delete'),
  1394.                                 ),
  1395.                               ],
  1396.                             );
  1397.                           },
  1398.                         );
  1399.                       }
  1400.                     },
  1401.                     onDismissed: (direction) async {
  1402.                       setState(() {
  1403.                         _meetings.removeAt(index);
  1404.                       });
  1405.                       const String directoryPath =
  1406.                           '/storage/emulated/0/Android/data/com.example.taskapp/files/TaskApp Data/';
  1407.                       final String fileName = '${meeting['meetingName']}.json';
  1408.                       final File fileToDelete = File('$directoryPath$fileName');
  1409.                       print('Attempting to delete file: ${fileToDelete.path}');
  1410.                       try {
  1411.                         if (await fileToDelete.exists()) {
  1412.                           await fileToDelete.delete();
  1413.                           print('File deleted successfully: $fileName');
  1414.                         } else {
  1415.                           print('File does not exist: $fileName');
  1416.                         }
  1417.                       } catch (e) {
  1418.                         print('Error deleting file: $e');
  1419.                       }
  1420.                     },
  1421.                     child: ExpansionTile(
  1422.                       title: Text(
  1423.                         meeting['meetingName'],
  1424.                         style: const TextStyle(
  1425.                           color: Colors.white,
  1426.                         ),
  1427.                       ),
  1428.                       textColor: Colors.white,
  1429.                       collapsedTextColor: Colors.white,
  1430.                       collapsedIconColor: const Color.fromARGB(255, 0, 0, 0),
  1431.                       collapsedBackgroundColor:
  1432.                           const Color.fromARGB(143, 4, 155, 255),
  1433.                       collapsedShape: RoundedRectangleBorder(
  1434.                         borderRadius: BorderRadius.circular(
  1435.                             15.0), // Adjust the radius as needed
  1436.                       ),
  1437.                       shape: RoundedRectangleBorder(
  1438.                         borderRadius: BorderRadius.circular(
  1439.                             15.0), // Adjust the radius as needed
  1440.                       ),
  1441.                       backgroundColor: const Color.fromARGB(159, 0, 116, 194),
  1442.                       iconColor: const Color.fromARGB(255, 0, 0, 0),
  1443.                       children: [
  1444.                         for (var job in meeting['jobs']) ...[
  1445.                           ListTile(
  1446.                             title: Text(
  1447.                               job['name'],
  1448.                               style: const TextStyle(
  1449.                                 color: Colors.white,
  1450.                                 fontSize: 20.0,
  1451.                               ),
  1452.                             ),
  1453.                             subtitle: Column(
  1454.                               crossAxisAlignment: CrossAxisAlignment.start,
  1455.                               children: [
  1456.                                 const Text('Actions:',
  1457.                                     style: TextStyle(color: Colors.white)),
  1458.                                 for (var action in job['actions']) ...[
  1459.                                   Text(
  1460.                                     '- $action',
  1461.                                     style: const TextStyle(color: Colors.white),
  1462.                                   ),
  1463.                                   const SizedBox(
  1464.                                     height: 10.0,
  1465.                                   ),
  1466.                                 ],
  1467.                               ],
  1468.                             ),
  1469.                           ),
  1470.                         ],
  1471.                       ],
  1472.                     ),
  1473.                   ),
  1474.                   const SizedBox(
  1475.                       height: 20), // Add a gap between ExpansionTiles
  1476.                 ],
  1477.               );
  1478.             },
  1479.           ),
  1480.         ],
  1481.       ),
  1482.     );
  1483.   }
  1484. }
  1485.  
  1486. class _BackgroundPainter extends CustomPainter {
  1487.   @override
  1488.   void paint(Canvas canvas, Size size) {
  1489.     final paint = Paint()
  1490.       ..shader = LinearGradient(
  1491.         colors: [Colors.blue.shade300, Colors.purple.shade300],
  1492.       ).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
  1493.     canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  1494.   }
  1495.  
  1496.   @override
  1497.   bool shouldRepaint(covariant CustomPainter oldDelegate) {
  1498.     return false;
  1499.   }
  1500. }
  1501.  
Advertisement
Add Comment
Please, Sign In to add comment