Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //main.dart -
- import 'package:flutter/material.dart';
- import 'package:taskapp/work_screen.dart';
- import 'splash_page.dart';
- //import 'work_screen.dart';
- //import 'meeting_list_screen.dart';
- void main() {
- runApp(const MyApp());
- }
- class MyApp extends StatelessWidget {
- const MyApp({Key? key}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Task Manager',
- theme: ThemeData(
- primarySwatch: Colors.blue,
- ),
- home: const SplashPage(),
- );
- }
- }
- -------------------------------------
- //splash_page.dart -
- import 'package:flutter/material.dart';
- import 'login_page.dart'; // Importing LoginPage widget
- class SplashPage extends StatefulWidget {
- const SplashPage({Key? key}) : super(key: key);
- @override
- _SplashPageState createState() => _SplashPageState();
- }
- class _SplashPageState extends State<SplashPage> {
- @override
- void initState() {
- super.initState();
- // Add a delay before navigating to the LoginPage
- Future.delayed(const Duration(seconds: 3), () {
- // Navigate to the LoginPage and replace the SplashPage
- Navigator.of(context).pushReplacement(
- MaterialPageRoute(
- builder: (context) => const LoginPage(),
- ),
- );
- });
- }
- @override
- Widget build(BuildContext context) {
- return const Scaffold(
- backgroundColor: Color.fromARGB(255, 79, 16, 150),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- 'Task Manager',
- style: TextStyle(
- fontSize: 48,
- fontWeight: FontWeight.bold,
- color: Colors.white,
- ),
- ),
- SizedBox(height: 20),
- CircularProgressIndicator(
- valueColor: AlwaysStoppedAnimation<Color>(
- Colors.white,
- ),
- ),
- ],
- ),
- ),
- );
- }
- }
- -------------------------------------------
- //login_page.dart -
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:google_fonts/google_fonts.dart';
- import 'package:taskapp/home_screen.dart';
- import 'package:taskapp/work_screen.dart';
- class LoginPage extends StatefulWidget {
- const LoginPage({Key? key}) : super(key: key);
- @override
- _LoginPageState createState() => _LoginPageState();
- }
- class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver {
- final String correctUsername = '**redacted**';
- final String correctPassword = '**redacted***';
- bool _homeSelected = false;
- bool _workSelected = false;
- String enteredUsername = '';
- String enteredPassword = '';
- bool _isLoading = false;
- bool _loginFailed = false;
- String _errorPromptMessage = '';
- bool _keyboardVisible = false;
- @override
- void initState() {
- super.initState();
- WidgetsBinding.instance!.addObserver(this);
- }
- @override
- void dispose() {
- WidgetsBinding.instance!.removeObserver(this);
- super.dispose();
- }
- @override
- void didChangeMetrics() {
- final bool isKeyboardOpen = MediaQuery.of(context).viewInsets.bottom > 0;
- setState(() {
- _keyboardVisible = isKeyboardOpen;
- });
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- toolbarHeight: 15,
- backgroundColor: Color.fromARGB(255, 0, 0, 0),
- ),
- body: GestureDetector(
- onTap: () {
- FocusScope.of(context).unfocus();
- },
- child: Stack(
- children: [
- Container(
- width: double.infinity,
- height: double.infinity,
- decoration: const BoxDecoration(
- gradient: LinearGradient(
- begin: Alignment.centerLeft,
- end: Alignment.centerRight,
- colors: [
- Color.fromARGB(255, 98, 68, 87),
- Color.fromARGB(255, 28, 28, 28),
- ],
- ),
- ),
- ),
- SingleChildScrollView(
- child: Center(
- child: Padding(
- padding: const EdgeInsets.all(0.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- const SizedBox(height: 0.0),
- Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Align(
- alignment: Alignment.topLeft,
- child: Padding(
- padding: const EdgeInsets.only(
- left: 5.0, right: 5.0, top: 0.0),
- child: Container(
- transform:
- Matrix4.translationValues(10.0, -10.0, 0.0),
- child: Stack(
- children: [
- Text(
- 'Login',
- style: GoogleFonts.dancingScript(
- textStyle: TextStyle(
- fontSize: 100,
- fontWeight: FontWeight.bold,
- foreground: Paint()
- ..shader = const LinearGradient(
- colors: [
- Color.fromARGB(103, 192, 192,
- 192), // Light gray (silver-like)
- Color.fromARGB(72, 91, 91,
- 91), // Medium gray (silver-like)
- Color.fromARGB(131, 56, 56,
- 56), // Lighter gray (silver-like)
- Color.fromARGB(98, 183, 182,
- 182), // Very light gray (silver-like)
- Color.fromARGB(60, 71, 71,
- 71), // Almost white (silver-like)
- Color.fromARGB(112, 172, 172,
- 172), // Almost white (silver-like)
- ],
- ).createShader(
- const Rect.fromLTWH(
- 30.0, // left position
- 0.0, // top position
- 110, // width
- 80.0, // height
- ),
- ),
- ),
- ),
- ),
- Text(
- 'Login',
- style: GoogleFonts.dancingScript(
- textStyle: TextStyle(
- fontSize: 100,
- fontWeight: FontWeight.bold,
- foreground: Paint()
- ..style = PaintingStyle.stroke
- ..strokeWidth = 0.7
- ..color = Color.fromARGB(
- 135, 225, 211, 211),
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- const SizedBox(height: 20),
- const SizedBox(
- height: 20,
- width: 20,
- ),
- ],
- ),
- const SizedBox(height: 50.0),
- AnimatedContainer(
- duration: const Duration(milliseconds: 500),
- curve: Curves.easeInOut,
- width: 300.0,
- height: 150,
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- decoration: BoxDecoration(
- color: const Color.fromARGB(0, 0, 0, 0),
- borderRadius: BorderRadius.circular(3.0),
- border: Border.all(
- width: 2.0,
- color: const Color.fromARGB(0, 255, 255, 255),
- ),
- ),
- child: Column(
- children: [
- Container(
- decoration: BoxDecoration(
- color: const Color.fromARGB(78, 0, 0, 0),
- borderRadius: BorderRadius.circular(3.0),
- border: Border.all(
- width: 2.0,
- color:
- const Color.fromARGB(82, 176, 176, 176),
- ),
- ),
- child: TextFormField(
- textAlign: TextAlign.center,
- style: GoogleFonts.kodeMono(
- fontSize: 32,
- color: const Color.fromARGB(255, 0, 242, 255),
- ),
- decoration: InputDecoration.collapsed(
- hintText: 'Username',
- hintStyle: GoogleFonts.bebasNeue(
- fontSize: 35,
- color: const Color.fromARGB(
- 127, 152, 152, 152),
- ),
- ),
- onChanged: (value) {
- setState(() {
- enteredUsername = value;
- });
- },
- ),
- ),
- const SizedBox(height: 20.0),
- Container(
- decoration: BoxDecoration(
- color: const Color.fromARGB(78, 0, 0, 0),
- borderRadius: BorderRadius.circular(3.0),
- border: Border.all(
- width: 2.0,
- color:
- const Color.fromARGB(82, 176, 176, 176),
- ),
- ),
- child: TextFormField(
- textAlign: TextAlign.center,
- obscureText: true,
- style: GoogleFonts.kodeMono(
- fontSize: 32,
- color: const Color.fromARGB(255, 0, 242, 255),
- ),
- decoration: InputDecoration.collapsed(
- hintText: 'Password',
- hintStyle: GoogleFonts.bebasNeue(
- fontSize: 35,
- color: const Color.fromARGB(
- 127, 152, 152, 152),
- ),
- ),
- onChanged: (value) {
- setState(() {
- enteredPassword = value;
- });
- },
- ),
- ),
- ],
- ),
- ),
- const SizedBox(height: 20.0),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Checkbox(
- value: _homeSelected,
- onChanged: (value) {
- setState(() {
- _homeSelected = value!;
- if (value) {
- _workSelected = false;
- }
- });
- },
- splashRadius: 200,
- materialTapTargetSize:
- MaterialTapTargetSize.shrinkWrap,
- side: const BorderSide(
- color: Color.fromARGB(255, 141, 85, 255),
- width: 1.5),
- activeColor: const Color.fromARGB(255, 0, 183, 255),
- checkColor: const Color.fromARGB(255, 0, 0, 0),
- ),
- const Text(
- 'Home',
- style: TextStyle(
- fontSize: 25.0,
- color: Color.fromARGB(196, 255, 255, 255)),
- ),
- const SizedBox(width: 45.0),
- Checkbox(
- value: _workSelected,
- onChanged: (value) {
- setState(() {
- _workSelected = value!;
- if (value) {
- _homeSelected = false;
- }
- });
- },
- splashRadius: 200,
- materialTapTargetSize:
- MaterialTapTargetSize.shrinkWrap,
- side: const BorderSide(
- color: Color.fromARGB(255, 141, 85, 255),
- width: 1.5),
- activeColor: const Color.fromARGB(255, 0, 183, 255),
- checkColor: const Color.fromARGB(255, 0, 0, 0),
- ),
- const Text(
- 'Work',
- style: TextStyle(
- fontSize: 25.0,
- color: Color.fromARGB(196, 255, 255, 255)),
- ),
- ],
- ),
- const SizedBox(height: 40.0),
- _isLoading
- ? const CircularProgressIndicator()
- : SizedBox(
- height: 40.0,
- width: 150.0,
- child: InkWell(
- onTap: _login,
- child: Container(
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(5.0),
- color: const Color.fromARGB(95, 96, 23, 85),
- border: Border.all(
- width: 2.0,
- color: const Color.fromARGB(
- 255, 141, 85, 255),
- ),
- ),
- child: const Center(
- child: Text(
- 'Login',
- style: TextStyle(
- fontSize: 20.0,
- fontWeight: FontWeight.bold,
- color:
- Color.fromARGB(136, 255, 255, 255),
- ),
- ),
- ),
- ),
- ),
- ),
- if (_loginFailed)
- Container(
- width: double.infinity,
- alignment: Alignment.bottomCenter,
- padding: const EdgeInsets.symmetric(vertical: 20.0),
- child: Text(
- _errorPromptMessage,
- style: GoogleFonts.kodeMono(
- fontSize: 16,
- color: const Color.fromARGB(255, 255, 255, 255),
- fontWeight: FontWeight.normal,
- decoration: TextDecoration.underline,
- decorationColor:
- const Color.fromARGB(255, 255, 255, 255),
- decorationStyle: TextDecorationStyle.solid,
- decorationThickness: 1.0,
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- AnimatedPositioned(
- duration: const Duration(milliseconds: 100),
- curve: Curves.easeInOut,
- bottom: _keyboardVisible ? 0 : 0,
- left: _keyboardVisible ? 0 : 50,
- child: AnimatedContainer(
- duration: const Duration(milliseconds: 100),
- curve: Curves.easeInOut,
- width: _keyboardVisible ? 45 : 200,
- height: _keyboardVisible ? 45 : 200,
- child: Image.asset(
- 'assets/cat_galaxy.gif',
- repeat: ImageRepeat.noRepeat,
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
- void showErrorPrompt(String message) {
- setState(() {
- _loginFailed = true;
- _errorPromptMessage = message;
- });
- // Reset login failed state after 4 seconds
- Future.delayed(const Duration(seconds: 2), () {
- setState(() {
- _loginFailed = false;
- _isLoading = false;
- });
- });
- }
- void _login() {
- // Hide the keyboard
- FocusScope.of(context).unfocus();
- setState(() {
- _isLoading = true;
- });
- // Simulate login process
- Future.delayed(const Duration(seconds: 1), () {
- // Check if username and password are empty
- if (enteredUsername.isEmpty &&
- enteredPassword.isEmpty &&
- !_homeSelected &&
- !_workSelected) {
- showErrorPrompt('Please fill the form to continue');
- } else if (enteredUsername.isEmpty && enteredPassword.isEmpty) {
- showErrorPrompt('Please enter a username and password');
- }
- // Check if username is missing
- else if (enteredUsername.isEmpty) {
- showErrorPrompt('Please enter a valid username to continue');
- }
- // Check if password is missing
- else if (enteredPassword.isEmpty) {
- showErrorPrompt('Please enter a valid password to continue');
- }
- // Check if no checkbox is selected
- else if (!_homeSelected && !_workSelected) {
- showErrorPrompt('Please select a box to continue');
- }
- // Check login credentials
- else if (enteredUsername == correctUsername &&
- enteredPassword == correctPassword) {
- // Simulate loading for 4 seconds
- Future.delayed(const Duration(seconds: 2), () {
- // Navigate to HomePage with a smooth transition
- Navigator.pushReplacement(
- context,
- PageRouteBuilder(
- transitionDuration: const Duration(milliseconds: 800),
- reverseTransitionDuration: const Duration(milliseconds: 800),
- pageBuilder: (context, animation, secondaryAnimation) {
- return FadeTransition(
- opacity: animation,
- child:
- _homeSelected ? const HomeScreen() : const WorkScreen(),
- );
- },
- ),
- );
- });
- }
- // Invalid credentials
- else {
- showErrorPrompt('Username or Password is incorrect, please try again');
- }
- });
- }
- }
- ----------------------------------------
- //work_screen.dart -
- import 'dart:convert';
- import 'dart:io';
- import 'package:flutter/material.dart';
- import 'package:flutter/widgets.dart';
- import 'package:intl/intl.dart';
- import 'package:shared_preferences/shared_preferences.dart';
- import 'package:path_provider/path_provider.dart';
- import 'package:flutter_moving_background/flutter_moving_background.dart';
- // Import the MeetingListScreen
- import 'meeting_list_screen.dart';
- class WorkScreen extends StatefulWidget {
- const WorkScreen({Key? key}) : super(key: key);
- @override
- _WorkScreenState createState() => _WorkScreenState();
- }
- class _WorkScreenState extends State<WorkScreen> {
- final TextEditingController _meetingNameController = TextEditingController();
- final TextEditingController _jobNameController = TextEditingController();
- final TextEditingController _actionController = TextEditingController();
- String? meetingName;
- String? jobName;
- String? currentAction;
- List<String> actions = [];
- List<Job> jobs = [];
- ScrollController _scrollController = ScrollController();
- bool _isScrolled = false;
- @override
- void initState() {
- super.initState();
- _scrollController.addListener(_onScroll);
- }
- @override
- void dispose() {
- _scrollController.removeListener(_onScroll);
- _scrollController.dispose();
- super.dispose();
- }
- void _onScroll() {
- setState(() {
- _isScrolled =
- _scrollController.hasClients && _scrollController.offset > 0;
- });
- }
- void _startMeeting() {
- final String newMeetingName = _meetingNameController.text.trim();
- if (newMeetingName.isNotEmpty) {
- setState(() {
- final now = DateTime.now();
- final formattedDate =
- '$newMeetingName (${DateFormat.yMd().add_jms().format(now)})';
- meetingName = formattedDate;
- _meetingNameController.clear();
- });
- } else {
- // Show a styled Snackbar
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(
- behavior: SnackBarBehavior.floating, // Makes the Snackbar float
- elevation: 0, // Remove shadow
- content: Container(
- height: 40, // Set height to 40
- alignment: Alignment.center, // Align content to center
- padding: const EdgeInsets.symmetric(horizontal: 16.0), // Add horizontal padding
- decoration: BoxDecoration(
- color: const Color.fromARGB(133, 255, 0, 0), // Background color
- borderRadius: BorderRadius.circular(20), // Rounded corners
- border: Border.all(color: Colors.white), // White border
- ),
- child: const Text(
- 'Please write a meeting name',
- textAlign: TextAlign.center, // Align text to center
- style: TextStyle(
- color: Colors.white, // White font color
- fontSize: 15, // Font size
- ),
- ),
- ),
- duration: const Duration(seconds: 4),
- margin: const EdgeInsets.only(bottom: 20), // Padding from bottom
- ),
- );
- }
- }
- void _addJob() {
- final String newJobName = _jobNameController.text.trim();
- if (newJobName.isNotEmpty) {
- setState(() {
- jobName = newJobName;
- jobs.add(Job(jobName!, [])); // Add job with empty actions list
- _jobNameController.clear();
- });
- } else {
- // Show a styled Snackbar
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(
- behavior: SnackBarBehavior.floating, // Makes the Snackbar float
- elevation: 0, // Remove shadow
- content: Container(
- height: 40, // Set height to 40
- alignment: Alignment.center, // Align content to center
- padding: const EdgeInsets.symmetric(horizontal: 16.0), // Add horizontal padding
- decoration: BoxDecoration(
- color: const Color.fromARGB(133, 255, 0, 0), // Background color
- borderRadius: BorderRadius.circular(20), // Rounded corners
- border: Border.all(color: Colors.white), // White border
- ),
- child: const Text(
- 'Please write a job name',
- textAlign: TextAlign.center, // Align text to center
- style: TextStyle(
- color: Colors.white, // White font color
- fontSize: 15, // Font size
- ),
- ),
- ),
- duration: const Duration(seconds: 4),
- margin: const EdgeInsets.only(bottom: 20), // Padding from bottom
- ),
- );
- }
- }
- void _addAction() {
- final newAction = _actionController.text.trim();
- if (newAction.isNotEmpty) {
- setState(() {
- actions.add(newAction);
- _actionController.clear();
- });
- } else {
- // Show a styled Snackbar
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(
- behavior: SnackBarBehavior.floating, // Makes the Snackbar float
- elevation: 0, // Remove shadow
- content: Container(
- height: 40, // Set height to 40
- alignment: Alignment.center, // Align content to center
- padding: const EdgeInsets.symmetric(horizontal: 16.0), // Add horizontal padding
- decoration: BoxDecoration(
- color: const Color.fromARGB(133, 255, 0, 0), // Background color
- borderRadius: BorderRadius.circular(20), // Rounded corners
- border: Border.all(color: Colors.white), // White border
- ),
- child: const Text(
- 'Please enter an action',
- textAlign: TextAlign.center, // Align text to center
- style: TextStyle(
- color: Colors.white, // White font color
- fontSize: 15, // Font size
- ),
- ),
- ),
- duration: const Duration(seconds: 4),
- margin: const EdgeInsets.only(bottom: 20), // Padding from bottom
- ),
- );
- }
- }
- void _completeActions() {
- setState(() {
- if (jobName != null) {
- for (var job in jobs) {
- if (job.name == jobName) {
- job.actions.addAll(actions);
- }
- }
- jobName = null;
- actions.clear();
- }
- });
- }
- void _deleteJob(Job job) {
- setState(() {
- jobs.remove(job);
- });
- }
- void _editJob(Job job) {
- // Create controllers to manage the text editing for each action
- List<TextEditingController> controllers = List.generate(job.actions.length,
- (index) => TextEditingController(text: job.actions[index]));
- showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: const Text('Edit Actions'),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- for (int i = 0; i < job.actions.length; i++) ...[
- TextField(
- controller: controllers[i],
- onChanged: (value) {
- // Update the corresponding action in the job actions list
- job.actions[i] = value;
- },
- onSubmitted: (newValue) {
- // Do nothing when submitted
- },
- ),
- const SizedBox(height: 10),
- ],
- ],
- ),
- actions: <Widget>[
- TextButton(
- onPressed: () {
- Navigator.of(context)
- .pop(); // Close the dialog without saving changes
- },
- child: const Text('CANCEL'),
- ),
- ElevatedButton(
- onPressed: () {
- // Close the dialog
- Navigator.of(context).pop();
- },
- child: const Text('SAVE CHANGES'),
- ),
- ],
- );
- },
- );
- }
- void _meetingFinished() async {
- // Check if meeting name is not null
- if (meetingName != null) {
- // Sanitize the meeting name to remove invalid characters
- final sanitizedMeetingName = meetingName!
- .replaceAll(RegExp(r'[^\w\s]+'),
- '') // Replace non-alphanumeric characters with empty string
- .replaceAll(RegExp(r'\s+'),
- '_'); // Replace whitespace characters with underscore
- // Save meeting details locally
- final SharedPreferences prefs = await SharedPreferences.getInstance();
- final meetingDetails = <String, dynamic>{
- 'meetingName': meetingName,
- 'jobs': jobs
- .map((job) => {'name': job.name, 'actions': job.actions})
- .toList(),
- };
- // Log the JSON data to be saved
- print('JSON data to be saved: ${jsonEncode(meetingDetails)}');
- // Save meeting details to SharedPreferences
- await prefs.setString('meetingDetails', jsonEncode(meetingDetails));
- // Construct the directory path
- final appDocumentsDirectory = await getApplicationDocumentsDirectory();
- final String directoryPath =
- '/storage/emulated/0/Android/data/com.example.taskapp/files/TaskApp Data/';
- // Create the directory if it doesn't exist
- final Directory workDirectory = Directory(directoryPath);
- if (!await workDirectory.exists()) {
- await workDirectory.create(recursive: true);
- }
- // Construct the file path using the sanitized meeting name and the desired directory
- final String filePath = '$directoryPath/$sanitizedMeetingName.json';
- // Write data to a file with the specified file path
- final File file = File(filePath);
- await file.writeAsString(jsonEncode(meetingDetails));
- print('Data saved to: ${file.path}');
- // Clear current meeting details
- setState(() {
- meetingName = null;
- jobs.clear();
- });
- } else {
- // Show a snack bar if meeting name is null
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text(
- 'Please start a meeting before finishing it',
- style: TextStyle(color: Colors.white),
- ),
- backgroundColor: Colors.red,
- duration: Duration(seconds: 2),
- ),
- );
- }
- }
- // Function to navigate to MeetingListScreen
- void _viewMeetings() {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const MeetingListScreen()),
- );
- }
- @override
- Widget build(BuildContext context) {
- return Stack(
- children: [
- SizedBox (
- width: MediaQuery.of(context).size.width,
- height: MediaQuery.of(context).size.height,
- child: const MovingBackground(
- backgroundColor: Colors.transparent,
- circles: [
- MovingCircle(color: Color.fromARGB(115, 148, 0, 174), blurSigma: 170),
- MovingCircle(color: Color.fromARGB(107, 131, 0, 0), blurSigma: 90),
- MovingCircle(color: Color.fromARGB(129, 59, 0, 160), blurSigma: 120),
- MovingCircle(color: Color.fromARGB(115, 170, 14, 0), blurSigma: 60),
- ],
- ),
- ),
- Scaffold(
- backgroundColor: Colors.transparent,
- appBar: PreferredSize(
- preferredSize: const Size.fromHeight(90.0),
- child: Column(
- children: [
- AppBar(
- backgroundColor: Colors.transparent,
- title: Text(
- meetingName ?? 'Work Screen',
- style: const TextStyle(color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0),
- textAlign: TextAlign.center,
- ),
- centerTitle: true,
- ),
- if (meetingName != null)
- Container(
- alignment: Alignment.center,
- height: 30.0,
- width: double.maxFinite,
- child: ElevatedButton(
- onPressed: _meetingFinished,
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all<Color>(
- const Color.fromARGB(255, 30, 108, 177)),
- foregroundColor: MaterialStateProperty.all<Color>(
- const Color.fromARGB(255, 255, 255, 255)),
- side: MaterialStateProperty.all<BorderSide>(
- const BorderSide(
- color: Color.fromARGB(255, 0, 200, 255))),
- shape: MaterialStateProperty.all<OutlinedBorder>(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 15.0), // Adjust the radius as needed
- ),
- ),
- ),
- child: const Text('Finish and Save Meeting',
- style: TextStyle(
- color: Color.fromARGB(255, 0, 0, 0),
- fontSize: 17.0,
- fontWeight: FontWeight.w700)),
- ),
- ),
- ],
- ),
- ),
- body: SingleChildScrollView(
- controller: _scrollController,
- child: Padding(
- padding: const EdgeInsets.all(16.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- if (meetingName == null) ...[
- const Text(
- 'Meeting Name',
- style: TextStyle(
- color: Color.fromARGB(255, 255, 255, 255), fontSize: 25.0, fontWeight: FontWeight.bold),
- ),
- TextField(
- style: const TextStyle(color: Color.fromARGB(255, 0, 200, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
- controller: _meetingNameController,
- decoration: const InputDecoration(
- hintText: 'Enter Meeting Name', hintStyle:TextStyle(fontSize: 15.0, color: Color.fromARGB(139, 107, 107, 107))
- ),
- onSubmitted: (_) {
- _startMeeting();
- },
- ),
- ],
- const SizedBox(
- height:
- 20.0), // Move "Meeting Finished" button below blue meeting name header
- if (meetingName != null && jobName == null) ...[
- const Text(
- 'Task to be completed -',
- style: TextStyle(
- fontSize: 20.0, color: Colors.white, fontWeight: FontWeight.bold),
- ),
- TextField(
- style: const TextStyle(fontSize: 20.0,
- color: Color.fromARGB(255, 0, 179, 255)),
- controller: _jobNameController,
- decoration: const InputDecoration(
- hintText: 'Enter Task', hintStyle:TextStyle(fontSize: 15.0, color: Color.fromARGB(139, 107, 107, 107))
- ),
- onSubmitted: (_) {
- _addJob();
- },
- ),
- ],
- if (jobName != null) ...[
- const SizedBox(height: 20.0),
- Text(
- jobName!,
- style: const TextStyle(
- color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
- ),
- const SizedBox(height: 10.0),
- const Text(
- 'Actions Required',
- style: TextStyle(
- color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold),
- ),
- TextField(
- style: const TextStyle(fontSize: 20.0,
- color: Color.fromARGB(255, 0, 179, 255)),
- controller: _actionController,
- decoration: const InputDecoration(
- hintText: 'Enter Action', hintStyle:TextStyle(fontSize: 15.0, color: Color.fromARGB(139, 107, 107, 107))
- ),
- textInputAction: TextInputAction.done,
- onSubmitted: (_) {
- _addAction();
- },
- ),
- const SizedBox(height: 20.0),
- Center(
- child: ElevatedButton(
- onPressed: _completeActions,
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all<Color>(
- const Color.fromARGB(255, 30, 108, 177)),
- foregroundColor: MaterialStateProperty.all<Color>(
- const Color.fromARGB(255, 22, 0, 0)),
- side: MaterialStateProperty.all<BorderSide>(
- const BorderSide(
- color: Color.fromARGB(255, 0, 200, 255))),
- shape: MaterialStateProperty.all<OutlinedBorder>(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 20.0), // Adjust the radius as needed
- ),
- ),
- ),
- child: const Text('Add Actions and Save Task', style: TextStyle( fontSize: 17.0)),
- ),
- ),
- const SizedBox(height: 50.0),
- const Text(
- 'Logged Actions:',
- style: TextStyle(
- color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
- ),
- const SizedBox(height: 15.0),
- for (var action in actions) ...[
- Text(
- '- $action',
- style: const TextStyle(color: Color.fromARGB(255, 255, 255, 255), fontSize: 20.0),
- ),
- ],
- ],
- const SizedBox(height: 80.0),
- const Text(
- 'Task List:',
- style:
- TextStyle(color: Color.fromARGB(255, 0, 179, 255), fontSize: 20.0, fontWeight: FontWeight.bold),
- ),
- const SizedBox(height: 20.0),
- for (var job in jobs) ...[
- const SizedBox(
- height: 10.0,
- ),
- Dismissible(
- key: Key(job.name),
- direction: DismissDirection.horizontal,
- background: Container(
- color: Colors.blue,
- alignment: Alignment.centerLeft,
- child: const Padding(
- padding: EdgeInsets.only(left: 20.0),
- child: Icon(Icons.edit, color: Colors.white),
- ),
- ),
- secondaryBackground: Container(
- color: Colors.red,
- alignment: Alignment.centerRight,
- child: const Padding(
- padding: EdgeInsets.only(right: 20.0),
- child: Icon(Icons.delete, color: Colors.white),
- ),
- ),
- confirmDismiss: (direction) async {
- if (direction == DismissDirection.endToStart) {
- // Deleting job
- return await showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: const Text('Confirm Delete'),
- content: const Text(
- 'Are you sure you want to delete this job?'),
- actions: <Widget>[
- TextButton(
- onPressed: () =>
- Navigator.of(context).pop(false),
- child: const Text('CANCEL'),
- ),
- TextButton(
- onPressed: () =>
- Navigator.of(context).pop(true),
- child: const Text('DELETE'),
- ),
- ],
- );
- },
- );
- } else {
- // Editing job
- _editJob(job);
- return false;
- }
- },
- onDismissed: (direction) {
- if (direction == DismissDirection.endToStart) {
- _deleteJob(job);
- }
- },
- child: ExpansionTile(
- title: Text(job.name),
- textColor: Colors.white,
- collapsedTextColor: Colors.white,
- collapsedIconColor: const Color.fromARGB(255, 0, 0, 0),
- collapsedBackgroundColor:
- const Color.fromARGB(77, 4, 155, 255),
- collapsedShape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 15.0), // Adjust the radius as needed
- ),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 15.0), // Adjust the radius as needed
- ),
- backgroundColor:
- const Color.fromARGB(101, 4, 155, 255),
- iconColor: const Color.fromARGB(255, 0, 0, 0),
- children: [
- for (var action in job.actions) ...[
- Text(
- '- $action',
- style: const TextStyle(color: Color.fromARGB(255, 255, 255, 255), fontSize: 20.0),
- ),
- ],
- ], // Change tile color here
- ),
- ),
- ],
- ],
- ),
- ),
- ),
- floatingActionButtonLocation:
- FloatingActionButtonLocation.centerFloat,
- floatingActionButton: AnimatedOpacity(
- opacity: _isScrolled
- ? 0.35
- : 1, // Change opacity based on scroll position
- duration: const Duration(
- milliseconds: 200), // Add duration for a smoother transition
- child: SizedBox(
- height: 25, // Change the height of the button
- child: ElevatedButton(
- onPressed: _viewMeetings,
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all<Color>(
- const Color.fromARGB(255, 30, 108, 177)),
- foregroundColor: MaterialStateProperty.all<Color>(
- const Color.fromARGB(255, 255, 255, 255)),
- side: MaterialStateProperty.all<BorderSide>(
- const BorderSide(
- color: Color.fromARGB(255, 0, 200, 255))),
- shape: MaterialStateProperty.all<OutlinedBorder>(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 15.0), // Adjust the radius as needed
- ),
- ),
- ),
- child: const Text('View Meetings',
- style: TextStyle(
- color: Color.fromARGB(255, 0, 0, 0),
- fontSize: 17.0)),
- ),
- ),
- ),
- )
- ],
- );
- }
- }
- class Job {
- final String name;
- List<String> actions;
- Job(this.name, this.actions);
- }
- void main() {
- runApp(const MaterialApp(
- home: WorkScreen(),
- ));
- }
- --------------------------
- //meeting_list_screen.dart -
- import 'dart:convert';
- import 'dart:io';
- import 'package:flutter/material.dart';
- import 'package:path_provider/path_provider.dart';
- import 'package:enough_mail/enough_mail.dart';
- import 'package:animated_glitch/animated_glitch.dart';
- class MeetingListScreen extends StatefulWidget {
- const MeetingListScreen({Key? key}) : super(key: key);
- @override
- _MeetingListScreenState createState() => _MeetingListScreenState();
- }
- class _MeetingListScreenState extends State<MeetingListScreen> {
- List<Map<String, dynamic>> _meetings = [];
- @override
- void initState() {
- super.initState();
- _loadMeetings();
- }
- Future<void> _loadMeetings() async {
- Directory? externalDir = await getExternalStorageDirectory();
- if (externalDir != null) {
- const String directoryPath =
- '/storage/emulated/0/Android/data/com.example.taskapp/files/TaskApp Data/';
- final Directory directory = Directory(directoryPath);
- if (await directory.exists()) {
- List<FileSystemEntity> files = directory.listSync();
- for (var file in files) {
- if (file.path.endsWith('.json') &&
- FileSystemEntity.isFileSync(file.path)) {
- final String data = await File(file.path).readAsString();
- final Map<String, dynamic> meetingJson = jsonDecode(data);
- meetingJson['jobs'] =
- List<Map<String, dynamic>>.from(meetingJson['jobs']);
- _meetings.add(meetingJson);
- }
- }
- setState(() {});
- } else {
- print('Directory does not exist.');
- }
- } else {
- print('Failed to get external storage directory.');
- }
- }
- Future<void> _sendEmail(
- String meetingName, List<Map<String, dynamic>> jobs) async {
- final client = SmtpClient('smtp.gmail.com', isLogEnabled: true);
- try {
- await client.connectToServer('smtp.gmail.com', 465, isSecure: true);
- await client.ehlo();
- await client.authenticate(
- '****redacted***', '**redacted**', AuthMechanism.login);
- String emailBody = '';
- final List<String> colors = [
- '#FF0000',
- '#FF8700',
- '#FFD300',
- '#DEFF0A',
- '#A1FF0A',
- '#0AFF99',
- '#0AEFFF',
- '#147DF5',
- '#580AFF',
- '#BE0AFF'
- ];
- int colorIndex = 0;
- for (var job in jobs) {
- final String color = colors[colorIndex];
- emailBody += '<font size="4" color="$color">${job['name']}</font><br>';
- for (var action in job['actions']) {
- emailBody += '  • $action<br>';
- }
- emailBody += '<br>';
- colorIndex = (colorIndex + 1) % colors.length;
- emailBody += '<div style="width: 100%; text-align: left;">';
- for (int i = 0; i < 20; i++) {
- emailBody +=
- '<span style="color: ${colors[i % colors.length]}; font-size: 3em;">-</span>';
- }
- emailBody += '</div><br>';
- }
- final builder = MessageBuilder.prepareMultipartAlternativeMessage(
- plainText: 'Meeting: $meetingName\n\n$emailBody',
- htmlText: '<p><b>Meeting: $meetingName</b></p>$emailBody',
- )
- ..from = [const MailAddress('TaskApp Bot', '**redacted**')]
- ..to = [const MailAddress('**C**', '**redacted**')]
- ..subject = 'Meeting: $meetingName';
- final mimeMessage = builder.buildMimeMessage();
- final sendResponse = await client.sendMessage(mimeMessage);
- print('Message sent: ${sendResponse.isOkStatus}');
- } catch (e) {
- print('Failed to send email: $e');
- } finally {
- await client.disconnect();
- }
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- backgroundColor: const Color.fromARGB(255, 0, 0, 0),
- title: const Text(
- 'Saved Meetings',
- style: TextStyle(color: Colors.white),
- ),
- iconTheme: const IconThemeData(color: Colors.white),
- ),
- body: Stack(
- children: [
- AnimatedGlitch.shader(
- child: Image.asset(
- 'assets/leaf_bg.jpeg',
- fit: BoxFit.cover,
- height: double.maxFinite,
- width: double.infinity,
- ),
- ),
- const SizedBox(height: 200.0, width: 50),
- ListView.builder(
- itemCount: _meetings.length,
- itemBuilder: (context, index) {
- final meeting = _meetings[index];
- return Column(
- children: [
- Dismissible(
- key: Key(meeting['meetingName']),
- direction: DismissDirection.horizontal,
- background: Container(
- color: Colors.green,
- child: const Align(
- alignment: Alignment.centerRight,
- child: Padding(
- padding: EdgeInsets.only(right: 20.0),
- child: Icon(
- Icons.email,
- color: Colors.white,
- ),
- ),
- ),
- ),
- secondaryBackground: Container(
- color: Colors.red,
- child: const Align(
- alignment: Alignment.centerLeft,
- child: Padding(
- padding: EdgeInsets.only(left: 20.0),
- child: Icon(
- Icons.delete,
- color: Colors.white,
- ),
- ),
- ),
- ),
- confirmDismiss: (direction) async {
- if (direction == DismissDirection.startToEnd) {
- return await showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: const Text('Email Meeting'),
- content: Text(
- 'Are you sure you want to email "${meeting['meetingName']}"?'),
- actions: <Widget>[
- TextButton(
- onPressed: () =>
- Navigator.of(context).pop(false),
- child: const Text('Cancel'),
- ),
- TextButton(
- onPressed: () {
- _sendEmail(meeting['meetingName'],
- meeting['jobs']);
- Navigator.of(context).pop(true);
- },
- child: const Text('Send'),
- ),
- ],
- );
- },
- );
- } else {
- return await showDialog(
- context: context,
- builder: (BuildContext context) {
- return AlertDialog(
- title: const Text('Delete Meeting'),
- content: Text(
- 'Are you sure you want to delete "${meeting['meetingName']}"?'),
- actions: <Widget>[
- TextButton(
- onPressed: () =>
- Navigator.of(context).pop(false),
- child: const Text('Cancel'),
- ),
- TextButton(
- onPressed: () {
- Navigator.of(context).pop(true);
- },
- child: const Text('Delete'),
- ),
- ],
- );
- },
- );
- }
- },
- onDismissed: (direction) async {
- setState(() {
- _meetings.removeAt(index);
- });
- const String directoryPath =
- '/storage/emulated/0/Android/data/com.example.taskapp/files/TaskApp Data/';
- final String fileName = '${meeting['meetingName']}.json';
- final File fileToDelete = File('$directoryPath$fileName');
- print('Attempting to delete file: ${fileToDelete.path}');
- try {
- if (await fileToDelete.exists()) {
- await fileToDelete.delete();
- print('File deleted successfully: $fileName');
- } else {
- print('File does not exist: $fileName');
- }
- } catch (e) {
- print('Error deleting file: $e');
- }
- },
- child: ExpansionTile(
- title: Text(
- meeting['meetingName'],
- style: const TextStyle(
- color: Colors.white,
- ),
- ),
- textColor: Colors.white,
- collapsedTextColor: Colors.white,
- collapsedIconColor: const Color.fromARGB(255, 0, 0, 0),
- collapsedBackgroundColor:
- const Color.fromARGB(143, 4, 155, 255),
- collapsedShape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 15.0), // Adjust the radius as needed
- ),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- 15.0), // Adjust the radius as needed
- ),
- backgroundColor: const Color.fromARGB(159, 0, 116, 194),
- iconColor: const Color.fromARGB(255, 0, 0, 0),
- children: [
- for (var job in meeting['jobs']) ...[
- ListTile(
- title: Text(
- job['name'],
- style: const TextStyle(
- color: Colors.white,
- fontSize: 20.0,
- ),
- ),
- subtitle: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const Text('Actions:',
- style: TextStyle(color: Colors.white)),
- for (var action in job['actions']) ...[
- Text(
- '- $action',
- style: const TextStyle(color: Colors.white),
- ),
- const SizedBox(
- height: 10.0,
- ),
- ],
- ],
- ),
- ),
- ],
- ],
- ),
- ),
- const SizedBox(
- height: 20), // Add a gap between ExpansionTiles
- ],
- );
- },
- ),
- ],
- ),
- );
- }
- }
- class _BackgroundPainter extends CustomPainter {
- @override
- void paint(Canvas canvas, Size size) {
- final paint = Paint()
- ..shader = LinearGradient(
- colors: [Colors.blue.shade300, Colors.purple.shade300],
- ).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
- canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
- }
- @override
- bool shouldRepaint(covariant CustomPainter oldDelegate) {
- return false;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment