diff --git a/.gitignore b/.gitignore index f3eab124..8e83c6be 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,13 @@ allocator/test/bin/*.db allocator/test/bin/*.exe allocator/test/reports/*.db allocator/test/logs/*.txt +ehsa_frontend/build/windows/runner/Debug/ehsa_frontend.exe +ehsa_frontend/build/windows/runner/Debug/flutter_windows.dll +ehsa_frontend/build/windows/runner/Debug/url_launcher_windows_plugin.dll +ehsa_frontend/linux/flutter/generated_plugin_registrant.cc +ehsa_frontend/linux/flutter/generated_plugin_registrant.h +ehsa_frontend/linux/flutter/generated_plugins.cmake +ehsa_frontend/macos/Flutter/GeneratedPluginRegistrant.swift +ehsa_frontend/windows/flutter/generated_plugin_registrant.cc +ehsa_frontend/windows/flutter/generated_plugin_registrant.h +ehsa_frontend/windows/flutter/generated_plugins.cmake diff --git a/EHSA_V3/bin/config.txt b/EHSA_V3/bin/config.txt index a8eedf53..9ef79206 100644 --- a/EHSA_V3/bin/config.txt +++ b/EHSA_V3/bin/config.txt @@ -1,3 +1,3 @@ [exam info] -name="Marian Engineering College" -title="Internal Examination" \ No newline at end of file +name=Marian Engineering College +title=Internal Examination \ No newline at end of file diff --git a/README.md b/README.md index 7331dc05..ac396d8c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ExamHall-SeatAllocator -A GUI application built in Flutter, Rust, and Python that automates the assignment of student seats in examinations and generates appropriate PDFs +A GUI application built in Flutter, Rust, and Python that automates the assignment of student seats in examinations and generates appropriate PDFs. # Requirements Windows 10 and above @@ -8,7 +8,7 @@ MSVC++ Redist. ( packaged with installer ) # How to use - go to [releases](https://github.com/Govind-S-B/ExamHall-SeatAllocator/releases) - get the latest installer and run it -- to learn more about usage refer the (wiki)[todo: write wikipage and add link] +- to learn more about usage refer the [wiki](https://github.com/Govind-S-B/ExamHall-SeatAllocator/wiki) # Algorithm the seat assignment algorithm has 3 modes: `subject`, `class`, and `any` diff --git a/allocator/src/args.rs b/allocator/src/args.rs index be4bd612..a8ac78a9 100644 --- a/allocator/src/args.rs +++ b/allocator/src/args.rs @@ -14,9 +14,9 @@ pub fn get() -> Arguments { "-r" | "--randomize" => { delta = Some( args.next() - .expect("no argument after -r flag") + .expect("[ no argument after -r flag ]") .parse() - .expect("invalid argument for delta"), + .expect("[ invalid argument for delta ]"), ) } _ => paths.push(arg), @@ -26,7 +26,7 @@ pub fn get() -> Arguments { let [_, input_db_path, output_db_path] = paths.as_slice() else { eprintln!("args given are {paths:?}"); - panic!("INVALID ARGUMENTS: arguments should be \" ./allocator [-r | --randomize]"); + panic!("[ INVALID ARGUMENTS: arguments should be \" ./allocator [-r | --randomize] ]"); }; Arguments { diff --git a/allocator/src/db.rs b/allocator/src/db.rs index 2b62e367..fad919ab 100644 --- a/allocator/src/db.rs +++ b/allocator/src/db.rs @@ -4,7 +4,7 @@ use sqlite as sq; use std::collections::hash_map::HashMap; pub fn read_halls_table(conn: &Connection) -> Vec { - let query = "SELECT * FROM halls ORDER BY capacity DESC"; + let query = "SELECT name, capacity FROM halls ORDER BY capacity DESC"; let mut halls: Vec = vec![]; conn.iterate(query, |pair| { //pair is an array slice of the columns and the values in the colums @@ -14,12 +14,12 @@ pub fn read_halls_table(conn: &Connection) -> Vec { let &(_, Some(hall_name)) = iter.next().unwrap() else { - panic!("DATABASE NOT VALID") + panic!("[ HALL DATABASE NOT VALID ]") }; let &(_, Some(capacity)) = iter.next().unwrap() else { - panic!("DATABASE NOT VALID") + panic!("[ HALL DATABASE NOT VALID ]") }; halls.push(Hall::new(hall_name, capacity.parse().unwrap())); @@ -30,7 +30,7 @@ pub fn read_halls_table(conn: &Connection) -> Vec { halls } pub fn read_students_table(conn: &Connection) -> HashMap> { - let query = "SELECT * FROM students"; + let query = "SELECT id, subject FROM students"; let mut students: HashMap> = HashMap::new(); conn.iterate(query, |pair| { //pair is an array slice of the columns and the values in the colums @@ -39,11 +39,11 @@ pub fn read_students_table(conn: &Connection) -> HashMap> { let mut iter = pair.iter(); let &(_, Some(id)) = iter.next().unwrap() else { - panic!("DATABASE NOT VALID") + panic!("[ STUDENT DATABASE NOT VALID ]") }; let &(_, Some(subject)) = iter.next().unwrap() else { - panic!("DATABASE NOT VALID") + panic!("[ STUDENT DATABASE NOT VALID ]") }; let student = Student::new(id.to_owned(), subject.to_owned()); @@ -65,7 +65,8 @@ pub fn read_students_table(conn: &Connection) -> HashMap> { } pub fn write_report_table(conn: &Connection, halls: &Vec) { let query = "DROP TABLE IF EXISTS report"; - conn.execute(query).expect("error dropping report table"); + conn.execute(query) + .expect("[ error dropping report table ]"); let command = " CREATE TABLE report (id CHAR(15) PRIMARY KEY NOT NULL, @@ -75,7 +76,8 @@ pub fn write_report_table(conn: &Connection, halls: &Vec) { seat_no INT NOT NULL, subject CHAR(50) NOT NULL)"; - conn.execute(command).expect("error creating report table"); + conn.execute(command) + .expect("[ error creating report table ]"); let mut command = "INSERT INTO report (id,class,roll_no,subject,hall,seat_no) VALUES".to_owned(); @@ -102,5 +104,5 @@ pub fn write_report_table(conn: &Connection, halls: &Vec) { command.pop(); command += ";"; conn.execute(command) - .expect("error inserting row into report table"); + .expect("[ error inserting row into report table ]"); } diff --git a/allocator/src/main.rs b/allocator/src/main.rs index 1456ffd4..a16bd53d 100644 --- a/allocator/src/main.rs +++ b/allocator/src/main.rs @@ -15,12 +15,12 @@ enum AllocationMode { fn main() { let args = args::get(); - let conn = sqlite::open(args.input_db_path).expect("Error connecting to input.db"); + let conn = sqlite::open(args.input_db_path).expect("[ Error connecting to input.db ]"); let mut students = db::read_students_table(&conn); let mut halls = db::read_halls_table(&conn); if let Some(delta) = args.randomize { if delta == 0 { - panic!("delta is 0") + panic!("[ delta(CLI Argument) is 0 ]") } let mut rng = rand::thread_rng(); halls = { @@ -78,9 +78,8 @@ fn main() { let mut extra_seats = { let total_seats: usize = halls.iter().map(|h| h.seats_left()).sum(); let total_students: usize = students.values().map(|s| s.len()).sum(); - if total_students > total_seats { - panic!("ERROR: more students than seats") + panic!("[ more students than seats ]") } total_seats - total_students }; @@ -95,7 +94,7 @@ fn main() { let next_student = get_next_student(&mut students, &next_key); hall.push(next_student) - .expect("tried to push student into full hall"); + .expect("[ tried to push student into full hall ]"); placed_keys.insert(next_key.clone()); previously_placed_key = Some(next_key); continue; @@ -104,7 +103,7 @@ fn main() { // run out of subjects and now must leave empty seats between students if extra_seats > 0 { hall.push_empty() - .expect("tried to push empty on full hall (error should never happer)"); + .expect("[ tried to push empty on full hall (error should never happer) ]"); previously_placed_key = None; extra_seats -= 1; continue; @@ -158,7 +157,7 @@ fn main() { } } - let conn = sqlite::open(args.output_db_path).expect("Error connecting to report.db"); + let conn = sqlite::open(args.output_db_path).expect("[ Error connecting to report.db ]"); db::write_report_table(&conn, &halls); log_sparse_halls(&halls); } @@ -167,11 +166,11 @@ fn main() { fn get_next_student(students: &mut HashMap>, key: &str) -> Student { let students_in_key = students .get_mut(key) - .expect("trying to take a student from subject that doesn't exist"); + .expect("[ trying to take a student from subject that doesn't exist ]"); let next_student = students_in_key .pop() - .expect("trying to take student from empty subject list"); + .expect("[ trying to take student from empty subject list ]"); if students_in_key.is_empty() { students.remove(key); @@ -218,7 +217,7 @@ pub fn log_sparse_halls(halls: &[Hall]) { .create(true) .append(true) .open("logs\\logs.txt") - .expect("err opening log file"); + .expect("[ err opening log file ]"); let mut sparse_hall_count = 0; for hall in halls { let num_students = hall.students().len(); @@ -226,16 +225,17 @@ pub fn log_sparse_halls(halls: &[Hall]) { sparse_hall_count += 1; let content = format!("{}: {}, ", hall.name(), num_students); file.write_all(content.as_bytes()) - .expect("file write error"); + .expect("[ file write error ]"); } } if sparse_hall_count == 0 { let content = format!("No sparse halls :D"); file.write_all(content.as_bytes()) - .expect("file write error") + .expect("[ file write error ]") } - file.write_all("\n".as_bytes()).expect("file write error") + file.write_all("\n".as_bytes()) + .expect("[ file write error ]") } #[cfg(not(debug_assertions))] diff --git a/allocator/src/student.rs b/allocator/src/student.rs index cea735c1..bd84f15a 100644 --- a/allocator/src/student.rs +++ b/allocator/src/student.rs @@ -9,8 +9,16 @@ pub struct Student { impl Student { pub fn new(id: String, subject: String) -> Self { let id_clone = id.clone(); - let (class, roll_no) = id_clone.split_once('-').expect("invalid id format"); - let roll_no: i32 = roll_no.parse().expect("invalid roll number"); + let (class, roll_no) = id_clone + .split_once('-') + .unwrap_or_else(|| panic!("[ invalid id format (id is {})]", id)); + let roll_no: i32 = roll_no.parse().unwrap_or_else(|e| { + panic!( + "[ invalid roll number (id is {}) (error is {1:?}; {1})]", + id, e + ) + }); + // expect("[ invalid roll number ]"); let class = class.to_owned(); Self { id, diff --git a/build_flutter_win.bat b/build_flutter_win.bat index cbb0fe44..a3f6855b 100644 --- a/build_flutter_win.bat +++ b/build_flutter_win.bat @@ -1,2 +1,2 @@ rmdir /s /q EHSA_V3\bin\data && del /q EHSA_V3\bin\ehsa_frontend.exe del /q EHSA_V3\bin\flutter_windows.dll del /q EHSA_V3\bin\url_launcher_windows_plugin.dll -cd ehsa_frontend && flutter build windows && cd ../ && move ehsa_frontend\build\windows\runner\Release\data EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\ehsa_frontend.exe EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\flutter_windows.dll EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\url_launcher_windows_plugin.dll EHSA_V3\bin +cd ehsa_frontend && flutter build windows && cd ../ && move ehsa_frontend\build\windows\runner\Release\data EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\ehsa_frontend.exe EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\flutter_windows.dll EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\url_launcher_windows_plugin.dll EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\window_manager_plugin.dll EHSA_V3\bin && move ehsa_frontend\build\windows\runner\Release\screen_retriever_plugin.dll EHSA_V3\bin diff --git a/ehsa_frontend/.gitignore b/ehsa_frontend/.gitignore index 24476c5d..4a06677d 100644 --- a/ehsa_frontend/.gitignore +++ b/ehsa_frontend/.gitignore @@ -9,7 +9,9 @@ .history .svn/ migrate_working_dir/ - +*.exe +*.txt +*.db # IntelliJ related *.iml *.ipr diff --git a/ehsa_frontend/build/windows/runner/Debug/ehsa_frontend.exe b/ehsa_frontend/build/windows/runner/Debug/ehsa_frontend.exe new file mode 100644 index 00000000..ced542a5 Binary files /dev/null and b/ehsa_frontend/build/windows/runner/Debug/ehsa_frontend.exe differ diff --git a/ehsa_frontend/build/windows/runner/Debug/flutter_windows.dll b/ehsa_frontend/build/windows/runner/Debug/flutter_windows.dll new file mode 100644 index 00000000..9350375a Binary files /dev/null and b/ehsa_frontend/build/windows/runner/Debug/flutter_windows.dll differ diff --git a/ehsa_frontend/build/windows/runner/Debug/url_launcher_windows_plugin.dll b/ehsa_frontend/build/windows/runner/Debug/url_launcher_windows_plugin.dll new file mode 100644 index 00000000..54bb372e Binary files /dev/null and b/ehsa_frontend/build/windows/runner/Debug/url_launcher_windows_plugin.dll differ diff --git a/ehsa_frontend/input.db b/ehsa_frontend/input.db deleted file mode 100644 index dcfd153d..00000000 Binary files a/ehsa_frontend/input.db and /dev/null differ diff --git a/ehsa_frontend/ios/Flutter/Debug.xcconfig b/ehsa_frontend/ios/Flutter/Debug.xcconfig index 592ceee8..ec97fc6f 100644 --- a/ehsa_frontend/ios/Flutter/Debug.xcconfig +++ b/ehsa_frontend/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ehsa_frontend/ios/Flutter/Release.xcconfig b/ehsa_frontend/ios/Flutter/Release.xcconfig index 592ceee8..c4855bfe 100644 --- a/ehsa_frontend/ios/Flutter/Release.xcconfig +++ b/ehsa_frontend/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ehsa_frontend/ios/Podfile b/ehsa_frontend/ios/Podfile new file mode 100644 index 00000000..fdcc671e --- /dev/null +++ b/ehsa_frontend/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ehsa_frontend/lib/bloc/main_screen/main_screen_cubit.dart b/ehsa_frontend/lib/bloc/main_screen/main_screen_cubit.dart new file mode 100644 index 00000000..e0dde434 --- /dev/null +++ b/ehsa_frontend/lib/bloc/main_screen/main_screen_cubit.dart @@ -0,0 +1,25 @@ +import 'package:bloc/bloc.dart'; +import 'package:ehsa_frontend/enums/page_type.dart'; +import 'package:flutter/material.dart'; + +part 'main_screen_state.dart'; + +class MainScreenCubit extends Cubit { + MainScreenCubit() + : super(MainScreenInitial( + isOverlayOpen: true, + isDrawerOpen: false, + pagesection: Pages.HALLS)); + + void showOverlay(bool show) { + emit(state.copyWith(isOverlayOpen: show)); + } + + void openDrawer(bool open) { + emit(state.copyWith(isDrawerOpen: open)); + } + + void setPageSection(Pages pagesection) { + emit(state.copyWith(pagesection: pagesection)); + } +} diff --git a/ehsa_frontend/lib/bloc/main_screen/main_screen_state.dart b/ehsa_frontend/lib/bloc/main_screen/main_screen_state.dart new file mode 100644 index 00000000..f46390ca --- /dev/null +++ b/ehsa_frontend/lib/bloc/main_screen/main_screen_state.dart @@ -0,0 +1,25 @@ +part of 'main_screen_cubit.dart'; + +@immutable +class MainScreenInitial { + bool isOverlayOpen; + bool isDrawerOpen; + Pages pagesection; + + MainScreenInitial( + {required this.isOverlayOpen, + required this.isDrawerOpen, + required this.pagesection}); + + MainScreenInitial copyWith({ + bool? isOverlayOpen, + bool? isDrawerOpen, + Pages? pagesection, + }) { + return MainScreenInitial( + isOverlayOpen: isOverlayOpen ?? this.isOverlayOpen, + isDrawerOpen: isDrawerOpen ?? this.isDrawerOpen, + pagesection: pagesection ?? this.pagesection, + ); + } +} diff --git a/ehsa_frontend/lib/constants/contributordata.dart b/ehsa_frontend/lib/constants/contributordata.dart new file mode 100644 index 00000000..1102e30b --- /dev/null +++ b/ehsa_frontend/lib/constants/contributordata.dart @@ -0,0 +1,59 @@ +import 'package:ehsa_frontend/models/contributor.dart'; + +List CONTRIBUTOR_DATA = [ + Contributor( + name: "Govind S B", + role: "Architect / Lead ", + profile: "https://github.com/Govind-S-B", + avatar: "https://github.com/Govind-S-B.png"), + Contributor( + name: "Siby C R", + role: "Backend", + profile: "https://github.com/sibycr18", + avatar: "https://github.com/sibycr18.png"), + Contributor( + name: "Jayadev B S", + role: "Frontend", + profile: "https://github.com/jydv402", + avatar: "https://github.com/jydv402.png"), + Contributor( + name: "Karthik Kumar", + role: "Frontend", + profile: "https://github.com/Karthi-R-K", + avatar: "https://github.com/Karthi-R-K.png"), + Contributor( + name: "Ameer Al Hisham", + role: "Misc./Minor Early Contributions", + profile: "https://github.com/Ameer-Al-Hisham", + avatar: "https://github.com/Ameer-Al-Hisham.png"), + Contributor( + name: "Arjun Pratap", + role: "Backend", + profile: "https://github.com/officiallyaninja", + avatar: "https://github.com/officiallyaninja.png"), + Contributor( + name: "Dheeraj R", + role: "UI Design", + profile: "https://github.com/Dheerajr2003", + avatar: "https://github.com/Dheerajr2003.png"), + Contributor( + name: "Amina Fayaz", + role: "Frontend", + profile: "https://github.com/aminafayaz", + avatar: "https://github.com/aminafayaz.png"), + Contributor( + name: "Adithya A R", + role: "Frontend", + profile: "https://github.com/AdithyaRajesh10", + avatar: "https://github.com/AdithyaRajesh10.png"), + Contributor( + name: "Aasish R R", + role: "Misc./Minor Early Contributions", + profile: "https://github.com/tsuAquila", + avatar: "https://github.com/tsuAquila.png"), + Contributor( + name: "Vishnu VS", + role: "Developer / Application architect ", + profile: "https://github.com/vishnuxx", + avatar: "https://github.com/vishnuxx.png"), +]; diff --git a/ehsa_frontend/lib/enums/page_type.dart b/ehsa_frontend/lib/enums/page_type.dart new file mode 100644 index 00000000..63f12071 --- /dev/null +++ b/ehsa_frontend/lib/enums/page_type.dart @@ -0,0 +1,7 @@ +export 'page_type.dart'; + +enum Pages { + HALLS, + STUDENTS, + GENERATE, +} diff --git a/ehsa_frontend/lib/generate_page.dart b/ehsa_frontend/lib/generate_page.dart index 2f13d227..d31bed14 100644 --- a/ehsa_frontend/lib/generate_page.dart +++ b/ehsa_frontend/lib/generate_page.dart @@ -1,11 +1,12 @@ import 'dart:io'; +import 'package:ehsa_frontend/manual_edit.dart'; import 'package:flutter/material.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:awesome_snackbar_content/awesome_snackbar_content.dart'; class GeneratePage extends StatefulWidget { - const GeneratePage({super.key}); + const GeneratePage({Key? key}) : super(key: key); @override State createState() => _GeneratePageState(); @@ -38,7 +39,6 @@ class _GeneratePageState extends State { } Future _setSessionIdValue() async { - //function to check if the metadata table has a key containing SESSION_NAME var val = await _database.query("metadata", where: "key = 'session_name'"); _sessionId = (val.isEmpty ? "Undefined" : val[0]["value"]).toString(); setState(() {}); @@ -50,15 +50,46 @@ class _GeneratePageState extends State { }); } + void onSubmitSessionId(String input) { + // var input = _sessionIdFieldController.text.trim(); + if (RegExp(r'\d\d-\d\d-\d\d\d\d [AF]N').hasMatch(input)) { + _sessionId = input; + } else { + final snackBar = SnackBar( + elevation: 0, + behavior: SnackBarBehavior.floating, + backgroundColor: Colors.transparent, + content: AwesomeSnackbarContent( + title: 'Invalid Session ID', + message: + 'Please Recheck the Session ID entered if of proper format and try again. format is DD-MM-YYYY [A/F]N ', + contentType: ContentType.failure, + ), + ); + + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar(snackBar); + } + + _database.execute( + "INSERT OR REPLACE INTO metadata (key, value) VALUES ('session_name', '$_sessionId')", + ); + _sessionIdFieldController.clear(); + setState(() {}); + } + @override Widget build(BuildContext context) { return Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Container( + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Container( decoration: BoxDecoration( borderRadius: const BorderRadius.vertical( - top: Radius.circular(16), bottom: Radius.circular(16)), + top: Radius.circular(16), + bottom: Radius.circular(16), + ), color: Colors.blue.shade300.withAlpha(50), ), child: Column( @@ -84,48 +115,20 @@ class _GeneratePageState extends State { border: InputBorder.none, contentPadding: const EdgeInsets.all(10), ), + onSubmitted: onSubmitSessionId, ), ), - ), // enter session name + ), Padding( padding: const EdgeInsets.all(10), child: ElevatedButton( onPressed: () { - var input = _sessionIdFieldController.text.trim(); - if (RegExp(r'\d\d-\d\d-\d\d\d\d [AF]N') - .hasMatch(input)) { - _sessionId = input; - } else { - final snackBar = SnackBar( - /// need to set following properties for best effect of awesome_snackbar_content - elevation: 0, - behavior: SnackBarBehavior.floating, - backgroundColor: Colors.transparent, - content: AwesomeSnackbarContent( - title: 'Invalid Session ID', - message: - 'Please Recheck the Session ID entered if of proper format and try again.', - - /// change contentType to ContentType.success, ContentType.warning or ContentType.help for variants - contentType: ContentType.failure, - ), - ); - - ScaffoldMessenger.of(context) - ..hideCurrentSnackBar() - ..showSnackBar(snackBar); - } - - // write a function to update the metadata table with the new session name - _database.execute( - "INSERT OR REPLACE INTO metadata (key, value) VALUES ('session_name', '$_sessionId')", - ); - _sessionIdFieldController.clear(); - setState(() {}); + onSubmitSessionId( + _sessionIdFieldController.text.trim()); }, child: const Icon(Icons.settings), ), - ) + ), ], ), ), // set session name @@ -148,11 +151,6 @@ class _GeneratePageState extends State { padding: const EdgeInsets.all(8.0), child: ElevatedButton( onPressed: () async { - // async function to launch rust allocator and wait for its response exit code - // if exit code is 0 then show a success message - // else show an error message - - // by default show failure message var content_type = ContentType.failure; var title = "PDF Generation Failed"; var msg = "PDF Generation Failed"; @@ -176,12 +174,10 @@ class _GeneratePageState extends State { allocator_args); if (result.exitCode == 0) { - // Executable executed successfully - // launch pdf generator - final result2 = await Process.run( - '${Directory.current.path}\\pdf_generator.exe', - []); + '${Directory.current.path}\\pdf_generator.exe', + [], + ); if (result2.exitCode == 0) { // pdf generated successfully @@ -193,24 +189,22 @@ class _GeneratePageState extends State { } else { // pdf generation failed - msg = "PDF Generator Failed : ${result2.exitCode} ${result2.stderr}"; + msg = + "PDF Generator Failed : ${result2.exitCode} ${result2.stderr}"; } - } - else if(result.exitCode == 101){ // THIS IS NOT WORKING AS ARJUN SAID IT WOULD . FIX IT OR REMOVE IT - - msg = "Allocator Failed : " + result.stderr; - - } - else { + } else { // Executable failed - - msg = "Allocator Failed : Unhandled exception ${result.exitCode} ${result.stderr}"; + String rawMessage = result.stderr; + var relevantErrorMessage = RegExp(r"\[(.+)\]") + .firstMatch(rawMessage) + ?.group(0); + var message = relevantErrorMessage ?? rawMessage; + msg = "Allocator Failed : $message"; } } catch (e) { // Handle any exceptions here msg = "You shouldnt be seeing this : $e"; - } final snackBar = SnackBar( @@ -234,16 +228,66 @@ class _GeneratePageState extends State { padding: const EdgeInsets.all(8.0), child: ElevatedButton( onPressed: () { - final Uri fileLocation = Uri.parse( - "file:" '${Directory.current.path}/../output/'); - launchUrl(fileLocation); + // new screen + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ManualEdit())); }, - child: const Icon(Icons.folder_open)), - ) + child: const Text("Manual Edit")), + ), ], - ) // generate button + ), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + onPressed: () { + // check if generated files exist + + List files = [ + '${Directory.current.path}/../output/Halls $_sessionId.pdf', + '${Directory.current.path}/../output/Seating $_sessionId.pdf', + '${Directory.current.path}/../output/Packaging $_sessionId.pdf' + ]; + + bool allExist = true; + + for (String filePath in files) { + if (!File(filePath).existsSync()) { + allExist = false; + break; + } + } + + if (allExist) { + // open files using default handler + for (String filePath in files) { + launchUrl(Uri.parse("file:" '$filePath')); + } + } else { + print("Error : Files not found , try regenerate"); + } + }, + child: const Icon(Icons.remove_red_eye), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + onPressed: () { + final Uri fileLocation = Uri.parse( + "file:" '${Directory.current.path}/../output/'); + launchUrl(fileLocation); + }, + child: const Icon(Icons.folder_open), + ), + ), + ]), ], - )), - )); + ), + ), + ), + ); } } diff --git a/ehsa_frontend/lib/hall_page.dart b/ehsa_frontend/lib/hall_page.dart index 107ad18a..318b5b45 100644 --- a/ehsa_frontend/lib/hall_page.dart +++ b/ehsa_frontend/lib/hall_page.dart @@ -1,26 +1,8 @@ import 'dart:io'; +import 'package:ehsa_frontend/models/Hall.dart'; import 'package:flutter/material.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; -class Hall { - final String hallName; - final int capacity; - String editedHallName; // Added variable to hold edited hallName - int editedCapacity; // Added variable to hold edited capacity - - Hall(this.hallName, this.capacity) - : editedHallName = hallName, - editedCapacity = - capacity; // Initialize editedHallName and editedCapacity - - Map toMap() { - return { - 'name': editedHallName, // Use editedHallName in toMap method - 'capacity': editedCapacity, // Use editedCapacity in toMap method - }; - } -} - class HallPage extends StatefulWidget { const HallPage({super.key}); @@ -35,8 +17,10 @@ class _HallPageState extends State { List halls = []; List editedHalls = []; - final TextEditingController _formtextController1 = TextEditingController(); - final TextEditingController _formtextController2 = TextEditingController(); + final TextEditingController _hallNameTextController = TextEditingController(); + final TextEditingController _capacityTextController = TextEditingController(); + final FocusNode _hallNameFocusNode = FocusNode(); + final FocusNode _capacityFocusNode = FocusNode(); @override void initState() { @@ -117,12 +101,58 @@ class _HallPageState extends State { } } + // function called on submitting form + // either by pressing button or pressing enter when all values are filled + void trySubmitForm() { + int capacity; + try { + capacity = int.parse(_capacityTextController.text); + } on FormatException { + //TODO: create error snackbar + _capacityTextController.clear(); + rethrow; + } + _database.insert( + 'halls', {"name": _hallNameTextController.text, "capacity": capacity}); + _hallNameTextController.clear(); + _capacityTextController.clear(); + _fetchHalls(); + } + @override void dispose() { _database.close(); super.dispose(); } + void showClearConfirmationDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + content: const Text("Are you sure you want to clear the table?"), + actions: [ + TextButton( + child: const Text("Cancel"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: const Text("Clear"), + onPressed: () { + _dropTable(); + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + @override Widget build( BuildContext context, @@ -147,7 +177,25 @@ class _HallPageState extends State { child: SizedBox( width: 200, child: TextField( - controller: _formtextController1, + onSubmitted: (value) { + if (_capacityTextController.text.isNotEmpty) { + try { + trySubmitForm(); + } on FormatException { + _capacityFocusNode.requestFocus(); + return; + } + _hallNameFocusNode.requestFocus(); + } else { + FocusNode node = + _hallNameTextController.text.isNotEmpty + ? _capacityFocusNode + : _hallNameFocusNode; + node.requestFocus(); + } + }, + focusNode: _hallNameFocusNode, + controller: _hallNameTextController, decoration: const InputDecoration( labelText: 'Hall Name', ), @@ -160,7 +208,23 @@ class _HallPageState extends State { SizedBox( width: 150, child: TextField( - controller: _formtextController2, + onSubmitted: (value) { + if (_capacityTextController.text.isEmpty) { + _hallNameFocusNode.requestFocus(); + return; + } + if (_hallNameTextController.text.isNotEmpty) { + try { + trySubmitForm(); + } on FormatException { + _capacityFocusNode.requestFocus(); + return; + } + } + _hallNameFocusNode.requestFocus(); + }, + focusNode: _capacityFocusNode, + controller: _capacityTextController, decoration: const InputDecoration( labelText: 'Capacity', ), @@ -171,13 +235,7 @@ class _HallPageState extends State { ), ElevatedButton( onPressed: () { - _database.insert('halls', { - "name": _formtextController1.text, - "capacity": int.parse(_formtextController2.text) - }); - _formtextController1.clear(); - _formtextController2.clear(); - _fetchHalls(); + trySubmitForm(); }, child: const Padding( padding: EdgeInsets.all(4), @@ -297,7 +355,7 @@ class _HallPageState extends State { child: Padding( padding: const EdgeInsets.all(10.0), child: ElevatedButton( - onPressed: _dropTable, + onPressed: showClearConfirmationDialog, child: const Text('Clear Table')), )), ], diff --git a/ehsa_frontend/lib/main.dart b/ehsa_frontend/lib/main.dart index 67ac3e3c..6abbd1cf 100644 --- a/ehsa_frontend/lib/main.dart +++ b/ehsa_frontend/lib/main.dart @@ -1,74 +1,59 @@ +import 'dart:io'; +import 'package:ehsa_frontend/bloc/main_screen/main_screen_cubit.dart'; +import 'package:ehsa_frontend/widgets/stateless/contributor_grid.dart'; + import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'generate_page.dart'; import 'hall_page.dart'; import 'students_page.dart'; -import 'package:url_launcher/url_launcher.dart'; - -void main() { - runApp(const MyApp()); -} -class MyApp extends StatefulWidget { - const MyApp({Key? key}) : super(key: key); +import 'package:window_manager/window_manager.dart'; +import "./enums/page_type.dart"; - @override - MyAppState createState() => MyAppState(); +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + databaseFactory = databaseFactoryFfi; + await windowManager.ensureInitialized(); + if (Platform.isWindows) { + WindowManager.instance.setMinimumSize(const Size(950, 700)); + } + runApp(BlocProvider.value( + value: MainScreenCubit(), + child: MyApp(), + )); } -enum Page { - halls, - students, - generate, -} +class MyApp extends StatelessWidget { + MyApp({Key? key}) : super(key: key); -class MyAppState extends State { - String _getPageTitle(Page page) { - switch (page) { - case Page.halls: - return 'Halls Page'; - case Page.students: - return 'Students Page'; - case Page.generate: - return 'Generate Page'; - default: - return ''; - } - } - - Page _selectedPage = Page.halls; + Pages _selectedPage = Pages.HALLS; bool _showCreditsOverlay = true; final GlobalKey _scaffoldKey = GlobalKey(); - final Map> _navigatorKeys = { - Page.halls: GlobalKey(), - Page.students: GlobalKey(), - Page.generate: GlobalKey(), - }; + // final Map> _navigatorKeys = { + // Pages.HALLS: GlobalKey(), + // Pages.STUDENTS: GlobalKey(), + // Pages.GENERATE: GlobalKey(), + // }; - void _selectPage(Page page) { - setState(() { - _selectedPage = page; - }); - } - - void _closeCreditsOverlay() { - setState(() { - _showCreditsOverlay = false; - }); + String getPageSectionTitle(Pages pagesection) { + switch (pagesection) { + case Pages.HALLS: + return 'Halls Pages'; + case Pages.STUDENTS: + return 'Students Pages'; + case Pages.GENERATE: + return 'Generate Pages'; + default: + return ''; + } } @override Widget build(BuildContext context) { - final Uri url1 = Uri.parse("https://github.com/Govind-S-B"); - final Uri url2 = Uri.parse("https://github.com/officiallyaninja"); - final Uri url3 = Uri.parse("https://github.com/sibycr18"); - final Uri url4 = Uri.parse("https://github.com/jydv402"); - final Uri url5 = Uri.parse("https://github.com/Karthi-R-K"); - final Uri url6 = Uri.parse("https://github.com/aminafayaz"); - final Uri url7 = Uri.parse("https://github.com/tsuAquila"); - final Uri url8 = Uri.parse("https://github.com/Ameer-Al-Hisham"); - return MaterialApp( title: 'EHSA', theme: ThemeData( @@ -80,12 +65,18 @@ class MyAppState extends State { primarySwatch: Colors.blue, ), home: Scaffold( + onDrawerChanged: (isOpened) => + context.read().openDrawer(isOpened), + onEndDrawerChanged: (isOpened) => + context.read().openDrawer(false), key: _scaffoldKey, appBar: AppBar( - elevation: 0, - centerTitle: true, - title: Text(_getPageTitle(_selectedPage)), - ), + elevation: 0, + centerTitle: true, + title: BlocBuilder( + builder: (context, state) => + Text(getPageSectionTitle(state.pagesection)), + )), drawer: Padding( padding: const EdgeInsets.only( bottom: 14, @@ -114,22 +105,21 @@ class MyAppState extends State { borderRadius: BorderRadius.all(Radius.circular(16)), color: Colors.blue, ), - child: GestureDetector( - onTap: () { - _scaffoldKey.currentState?.closeDrawer(); - }, - child: Center( - child: TextButton( - onPressed: (){ - _showCreditsOverlay = true; - setState(() {}); - }, - child: Text( - 'EHSA', - style: TextStyle( - color: Colors.white, - fontSize: 40, - ), + child: Center( + child: TextButton( + style: ButtonStyle( + fixedSize: MaterialStateProperty.all( + const Size(600, 300))), + onPressed: () { + context.read().showOverlay(true); + + _scaffoldKey.currentState?.closeDrawer(); + }, + child: const Text( + 'EHSA', + style: TextStyle( + color: Colors.white, + fontSize: 40, ), ), ), @@ -137,182 +127,91 @@ class MyAppState extends State { ), ), ), - Padding( - padding: const EdgeInsets.only( - left: 8, - right: 8, - top: 1, - bottom: 4, - ), - child: ListTile( - leading: _selectedPage == Page.halls - ? const Icon(Icons.add_home_rounded) - : const Icon(Icons.add_home_outlined), - title: const Text('Halls'), - selected: _selectedPage == Page.halls, - onTap: () { - _selectPage(Page.halls); - _scaffoldKey.currentState?.closeDrawer(); - }, - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 8, - right: 8, - top: 4, - bottom: 4, - ), - child: ListTile( - leading: _selectedPage == Page.students - ? const Icon(Icons.person_add_alt_1_rounded) - : const Icon(Icons.person_add_alt_1_outlined), - title: const Text('Students'), - selected: _selectedPage == Page.students, - onTap: () { - _selectPage(Page.students); - _scaffoldKey.currentState?.closeDrawer(); - }, - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 8, - right: 8, - top: 4, - bottom: 4, - ), - child: ListTile( - leading: _selectedPage == Page.generate - ? const Icon(Icons.create_rounded) - : const Icon(Icons.create_outlined), - title: const Text('Generate'), - selected: _selectedPage == Page.generate, - onTap: () { - _selectPage(Page.generate); - _scaffoldKey.currentState?.closeDrawer(); - }, - ), - ), + drawerItem( + text: "Halls", + section: Pages.HALLS, + icon: Icon(Icons.add_home_rounded), + activeIcon: const Icon(Icons.add_home_outlined)), + drawerItem( + text: "Students", + section: Pages.STUDENTS, + icon: Icon(Icons.person_add_alt_1_rounded), + activeIcon: const Icon(Icons.person_add_alt_1_outlined)), + drawerItem( + text: "Generate", + section: Pages.GENERATE, + icon: Icon(Icons.create_rounded), + activeIcon: const Icon(Icons.create_outlined)), ], ), ), ), body: Stack( children: [ - _buildOffstageNavigator(Page.halls), - _buildOffstageNavigator(Page.students), - _buildOffstageNavigator(Page.generate), - if (_showCreditsOverlay) - GestureDetector( - onTap: _closeCreditsOverlay, - child: Container( - color: Colors.black.withOpacity(0.5), - child: Center( + //DrawerTabs + BlocBuilder( + builder: (context, state) { + return IndexedStack( + index: state.pagesection.index, + children: const [HallPage(), StudentsPage(), GeneratePage()], + ); + }), + + //contributors grid + BlocBuilder( + builder: (context, state) { + if (state.isOverlayOpen) { + return GestureDetector( + onTap: () { + context.read().showOverlay(false); + }, child: Container( - height: MediaQuery.of(context).size.height * 0.4, - width: MediaQuery.of(context).size.width * 0.4, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - ), - child: Padding( - padding: const EdgeInsets.only(top: 20), + color: Colors.black.withOpacity(0.5), + child: Center( child: Column( - children: [ - const SizedBox( - height: 10, - ), - const Text( - 'EHSA', - style: TextStyle( - fontSize: 50, - fontWeight: FontWeight.bold, - ), - ), - const Text( - "by protoRes", - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 50), - Wrap( - children: [ - TextButton( - onPressed: () { - launchUrl(url1); - }, - child: const Text("Govind S B")), - TextButton( - onPressed: () { - launchUrl(url2); - }, - child: const Text("Arjun Pratap")), - TextButton( - onPressed: () { - launchUrl(url3); - }, - child: const Text("Siby C.R")), - TextButton( - onPressed: () { - launchUrl(url4); - }, - child: const Text("Jayadev B.S")), - TextButton( - onPressed: () { - launchUrl(url5); - }, - child: const Text("Karthik Kumar")), - TextButton( - onPressed: () { - launchUrl(url6); - }, - child: const Text("Amina Fayaz")), - TextButton( - onPressed: () { - launchUrl(url8); - }, - child: const Text("Ameer Al Hisham")), - TextButton( - onPressed: () { - launchUrl(url7); - }, - child: const Text("Aasish R R")), - ], - ), - ], + mainAxisAlignment: MainAxisAlignment.center, + children: [ContributorGrid()], ), ), ), - ), - ), - ), + ); + } else { + return Text(""); + } + }, + ), ], ), ), ); } - Widget _buildOffstageNavigator(Page page) { - return Offstage( - offstage: _selectedPage != page, - child: Navigator( - key: _navigatorKeys[page], - onGenerateRoute: (routeSettings) { - return MaterialPageRoute(builder: (context) { - switch (page) { - case Page.halls: - return const HallPage(); - case Page.students: - return const StudentsPage(); - case Page.generate: - return const GeneratePage(); - default: - return Container(); - } - }); + Widget drawerItem( + {required String text, + required Pages section, + required Icon icon, + required Icon activeIcon}) { + return Padding( + padding: const EdgeInsets.only( + left: 8, + right: 8, + top: 1, + bottom: 4, + ), + child: BlocBuilder( + builder: (context, state) { + return ListTile( + leading: state.pagesection == section ? icon : activeIcon, + title: Text(text), + selected: state.pagesection == section, + onTap: () { + context.read().setPageSection(section); + + context.read().openDrawer(false); + // _selectPage(Pages.HALLS); + _scaffoldKey.currentState?.closeDrawer(); + }, + ); }, ), ); diff --git a/ehsa_frontend/lib/manual_edit.dart b/ehsa_frontend/lib/manual_edit.dart new file mode 100644 index 00000000..a154e8b3 --- /dev/null +++ b/ehsa_frontend/lib/manual_edit.dart @@ -0,0 +1,608 @@ +// ignore_for_file: avoid_print + +import 'dart:io'; +import 'package:awesome_snackbar_content/awesome_snackbar_content.dart'; +import 'package:flutter/material.dart'; +import 'package:sqflite_common_ffi/sqflite_ffi.dart'; + +class ManualEdit extends StatefulWidget { + const ManualEdit({super.key}); + + @override + State createState() => _ManualEditState(); +} + +List myList = []; +List> seatsList = []; + +class _ManualEditState extends State { + String? sourceSide; + + Set> transferredSet = {}; + + String selectedIndex = ''; + var databaseFactory = databaseFactoryFfi; + var halls_info; + + //To add to the database while drag n drop + Future addToDatabase(Map seat) async { + final path = ('${Directory.current.path}/report.db'); + try { + final database = await openDatabase(path, version: 1, + onCreate: (Database db, int version) async { + await db.execute( + 'CREATE TABLE IF NOT EXISTS report (id TEXT, class TEXT, roll_no TEXT, hall TEXT, seat_no TEXT, subject TEXT)'); + }); + + await database.insert('report', seat, + conflictAlgorithm: ConflictAlgorithm.replace); + + await database.close(); + print('Seat added to the database: $seat'); + } catch (e) { + print('Error adding seat to the database: $e'); + } + } + + //To remove to the database while drag n drop + Future removeFromDatabase(Map seat) async { + final path = ('${Directory.current.path}/report.db'); + try { + final database = await openDatabase(path, version: 1, + onCreate: (Database db, int version) async { + await db.execute( + 'CREATE TABLE IF NOT EXISTS report (id TEXT, class TEXT, roll_no TEXT, hall TEXT, seat_no TEXT, subject TEXT)'); + }); + + await database.delete('report', + where: + 'id = ? AND class = ? AND roll_no = ? AND hall = ? AND seat_no = ? AND subject = ?', + whereArgs: [ + seat['id'], + seat['class'], + seat['roll_no'], + seat['hall'], + seat['seat_no'], + seat['subject'], + ]); + + await database.close(); + print('Seat removed from the database: $seat'); + } catch (e) { + print('Error removing seat from the database: $e'); + } + } + + void updateSeatsList(Map transferredItem, + {bool isReverting = false}) { + final seatNo = transferredItem['seat_no'].toString(); + final updatedSeatsList = List>.from(seatsList); + final index = updatedSeatsList + .indexWhere((seat) => seat['seat_no'].toString() == seatNo); + + if (index != -1) { + updatedSeatsList[index] = isReverting + ? transferredItem + : { + 'id': 'Unallocated', + 'class': transferredItem['class'], + 'roll_no': transferredItem['roll_no'], + 'hall': transferredItem['hall'], + 'seat_no': seatNo, + 'subject': 'Unallocated', + }; + setState(() { + seatsList = updatedSeatsList; + }); + } + } + + void getHallsInfo() async { + final path = ('${Directory.current.path}/report.db'); + try { + var database = await databaseFactory.openDatabase(path); + halls_info = await database.rawQuery('SELECT hall FROM report'); + database.close(); + Set uniqueValues = {}; + + for (var hallInfo in halls_info) { + uniqueValues.add(hallInfo['hall'].toString()); + } + myList = uniqueValues.toList(); + setState(() {}); + + print('Updated List: $myList'); + } catch (e) { + print('Error fetching data from database: $e'); + } + } + + void getSeatsInfo(String hall) async { + final path = ('${Directory.current.path}/report.db'); + try { + var database = await databaseFactory.openDatabase(path); + + seatsList = await database + .rawQuery('SELECT * FROM report WHERE hall = ?', [hall]); + database.close(); + + int maxSeatNumber = seatsList.isEmpty + ? 0 + : seatsList + .map( + (entry) => int.tryParse(entry['seat_no'].toString()) ?? 0) + .reduce((value, element) => value > element ? value : element); + + List> fullSeatsList = []; + + for (var i = 1; i <= maxSeatNumber; i++) { + var foundSeat = seatsList.firstWhere( + (seat) => int.tryParse(seat['seat_no'].toString()) == i, + orElse: () => {}); + + if (foundSeat.isEmpty) { + fullSeatsList.add({ + 'id': 'Unallocated', + 'class': 'Unallocated', + 'roll_no': 'Unallocated', + 'hall': hall, + 'seat_no': i.toString(), + 'subject': 'Unallocated' + }); + } else { + fullSeatsList.add(foundSeat); + } + } + + seatsList = fullSeatsList; + + setState(() {}); + } catch (e) { + print('Error fetching seats data from database: $e'); + } + } + + @override + void initState() { + super.initState(); + sqfliteFfiInit(); + getHallsInfo(); + } + + @override + Widget build(BuildContext context) { + if (myList.isNotEmpty && selectedIndex.isEmpty) { + selectedIndex = myList.first; + getSeatsInfo(selectedIndex); + } + + return Scaffold( + appBar: AppBar( + elevation: 0, + centerTitle: true, + title: const Text("Manual Edit"), + ), + body: Row( + children: [ + Expanded( + flex: 13, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.vertical( + top: Radius.circular(16), + bottom: Radius.circular(16), + ), + color: Colors.blue.shade300.withAlpha(50), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + DropdownButton( + focusColor: Colors.transparent, + menuMaxHeight: MediaQuery.of(context).size.height * 0.6, + elevation: 4, + dropdownColor: Colors.blue.shade50, + borderRadius: BorderRadius.circular(16), + padding: const EdgeInsets.symmetric(horizontal: 16), + value: selectedIndex, + onChanged: (String? value) { + setState(() { + selectedIndex = value!; + }); + getSeatsInfo(selectedIndex); + }, + items: myList + .map>((String value) { + return DropdownMenuItem( + alignment: Alignment.center, + value: value, + child: Text( + value, + style: const TextStyle( + fontWeight: FontWeight.w600, fontSize: 17), + ), + ); + }).toList(), + ), + Padding( + padding: const EdgeInsets.all(4), + child: Container( + height: 60, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + border: Border.all( + style: BorderStyle.solid, + width: 1, + color: Colors.blue), + color: Colors.white, + ), + child: const Row( + children: [ + Expanded( + flex: 2, + child: Text( + " Seat No.", + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 18, + color: Colors.black), + )), + Expanded( + flex: 2, + child: Text( + "Roll No.", + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 18, + color: Colors.black), + )), + Expanded( + flex: 4, + child: Text( + " Subject", + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 18, + color: Colors.black), + )), + ], + ), + ), + ), + Expanded( + child: ListView.builder( + itemCount: seatsList.length, + itemBuilder: (context, index) { + final seat = seatsList[index]; + bool isUnallocated = seat['id'] == 'Unallocated' && + seat['subject'] == 'Unallocated'; + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0)), + elevation: 4.0, + margin: const EdgeInsets.symmetric( + horizontal: 4.0, vertical: 4.0), + color: + isUnallocated ? Colors.blue.shade100 : null, + child: isUnallocated + ? DragTarget>( + onWillAccept: (data) => isUnallocated, + onAccept: (transferredItem) { + if (sourceSide == 'right') { + setState(() { + final newSeat = { + 'id': transferredItem['id'], + 'class': transferredItem['class'], + 'roll_no': + transferredItem['roll_no'], + 'hall': seat['hall'], + 'seat_no': seat['seat_no'], + 'subject': + transferredItem['subject'] + }; + seatsList[index] = newSeat; + transferredSet + .remove(transferredItem); + addToDatabase(newSeat); + }); + } + }, + builder: (context, candidateData, + rejectedData) { + return ListTile( + contentPadding: + const EdgeInsets.all(4), + title: Row( + children: [ + Text( + " ${seat['seat_no']}", + textAlign: TextAlign.start, + ), + const Expanded( + child: Text( + "Unallocated", + textAlign: TextAlign.center, + ), + ), + ], + ), + ); + }, + ) + : Draggable>( + onDragStarted: () { + setState(() { + sourceSide = 'left'; + }); + }, + dragAnchorStrategy: + (draggable, context, position) { + return const Offset(0, 0); + }, + data: seat, + feedback: Material( + borderRadius: BorderRadius.circular(16), + elevation: 8, + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade100, + borderRadius: + BorderRadius.circular(16)), + child: Text( + "${seat['id']} - ${seat['subject']}", + style: const TextStyle( + color: Colors.black, + fontSize: 16.0, + ), + ), + ), + ), + child: ListTile( + contentPadding: const EdgeInsets.all(4), + title: Row( + children: [ + Expanded( + flex: 2, + child: Text( + " ${seat['seat_no']}")), + Expanded( + flex: 2, + child: Text( + "${seat['id']}", + )), + Expanded( + flex: 4, + child: Text( + "${seat['subject']}", + )), + ], + ), + ), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ), + ), + Expanded( + flex: 7, + child: Column( + children: [ + Expanded( + flex: 27, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.vertical( + top: Radius.circular(16), + bottom: Radius.circular(16), + ), + color: Colors.blue.shade300.withAlpha(50), + ), + child: DragTarget>( + onAccept: (transferredItem) { + if (sourceSide == 'left') { + setState(() { + transferredSet.add(transferredItem); + updateSeatsList(transferredItem); + removeFromDatabase(transferredItem); + }); + } + }, + builder: (context, candidateData, rejectedData) { + return transferredSet.isEmpty + ? const Center( + child: Text( + "Drag and Drop here", + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16), + ), + ) + : ListView.builder( + itemCount: transferredSet.length, + itemBuilder: (context, index) { + final transferredItem = + transferredSet.elementAt(index); + return Card( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(16), + ), + elevation: 4.0, + margin: const EdgeInsets.symmetric( + vertical: 4.0, + horizontal: 4.0, + ), + child: Draggable>( + onDragStarted: () { + setState(() { + sourceSide = 'right'; + }); + }, + // onDragCompleted: () { + // setState(() { + // transferredSet + // .remove(transferredItem); + // addToDatabase(transferredItem); + // }); + // }, + dragAnchorStrategy: + (draggable, context, position) { + return const Offset(0, 0); + }, + data: transferredItem, + feedback: Material( + borderRadius: + BorderRadius.circular(16), + elevation: 8, + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade100, + borderRadius: + BorderRadius.circular(16), + ), + child: Text( + "${transferredItem['id']} - ${transferredItem['subject']}", + style: const TextStyle( + color: Colors.black, + fontSize: 16.0, + ), + ), + ), + ), + child: ListTile( + contentPadding: + const EdgeInsets.all(4), + title: Center( + child: Text( + "${transferredItem['id']} - ${transferredItem['subject']}", + style: const TextStyle( + color: Colors.black, + fontSize: 16.0, + ), + ), + ), + ), + ), + ); + }, + ); + }, + ), + ), + )), + Expanded( + flex: 3, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 8, 8), + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: FilledButton( + style: FilledButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + )), + onPressed: () async { + try { + final result = await Process.run( + '${Directory.current.path}\\pdf_generator.exe', + ['report.db'], + ); + + if (result.exitCode == 0) { + // pdf generated successfully + var title = "PDF Generated"; + var msg = + "PDF Generated, please check the output folder."; + var contentType = ContentType.success; + + final snackBar = SnackBar( + elevation: 0, + behavior: SnackBarBehavior.floating, + backgroundColor: Colors.transparent, + content: AwesomeSnackbarContent( + title: title, + message: msg, + contentType: contentType, + ), + ); + + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar(snackBar); + } else { + // pdf generation failed + var title = "PDF Generation Failed"; + var msg = + "PDF Generator Failed: ${result.exitCode} ${result.stderr}"; + var contentType = ContentType.failure; + + final snackBar = SnackBar( + elevation: 0, + behavior: SnackBarBehavior.floating, + backgroundColor: Colors.transparent, + content: AwesomeSnackbarContent( + title: title, + message: msg, + contentType: contentType, + ), + ); + + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar(snackBar); + } + } catch (e) { + // Handle any exceptions here + var msg = "You shouldn't be seeing this: $e"; + + final snackBar = SnackBar( + elevation: 0, + behavior: SnackBarBehavior.floating, + backgroundColor: Colors.transparent, + content: AwesomeSnackbarContent( + title: "Error", + message: msg, + contentType: ContentType.failure, + ), + ); + + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar(snackBar); + } + }, + child: const Text( + 'Generate', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500, + fontSize: 18, + ), + )), + ), + )), + ], + ), + ), + ], + ), + ); + } +} diff --git a/ehsa_frontend/lib/models/Hall.dart b/ehsa_frontend/lib/models/Hall.dart new file mode 100644 index 00000000..92307cae --- /dev/null +++ b/ehsa_frontend/lib/models/Hall.dart @@ -0,0 +1,18 @@ +class Hall { + final String hallName; + final int capacity; + String editedHallName; // Added variable to hold edited hallName + int editedCapacity; // Added variable to hold edited capacity + + Hall(this.hallName, this.capacity) + : editedHallName = hallName, + editedCapacity = + capacity; // Initialize editedHallName and editedCapacity + + Map toMap() { + return { + 'name': editedHallName, // Use editedHallName in toMap method + 'capacity': editedCapacity, // Use editedCapacity in toMap method + }; + } +} diff --git a/ehsa_frontend/lib/models/contributor.dart b/ehsa_frontend/lib/models/contributor.dart new file mode 100644 index 00000000..4aa7fabe --- /dev/null +++ b/ehsa_frontend/lib/models/contributor.dart @@ -0,0 +1,8 @@ +class Contributor { + String name, role, profile, avatar; + Contributor( + {required this.name, + required this.role, + required this.profile, + required this.avatar}); +} diff --git a/ehsa_frontend/lib/service/database/Halls.dart b/ehsa_frontend/lib/service/database/Halls.dart new file mode 100644 index 00000000..34e270a4 --- /dev/null +++ b/ehsa_frontend/lib/service/database/Halls.dart @@ -0,0 +1,19 @@ +import 'package:sqflite_common_ffi/sqflite_ffi.dart'; + +class HallsDatabase { + late Database _database; + HallsDatabase(); + + Future initHallsDatabase(String input_path) async { + // final path = ('${Directory.current.path}/input.db'); + _database = await databaseFactory.openDatabase(input_path); + _database.execute("""CREATE TABLE IF NOT EXISTS halls + (name CHAR(8) PRIMARY KEY NOT NULL, + capacity INT NOT NULL)"""); + } + + + Future _fetchHalls() async { + return await _database.query('halls'); + } +} diff --git a/ehsa_frontend/lib/students_page.dart b/ehsa_frontend/lib/students_page.dart index 6eeb0b1b..76641fd8 100644 --- a/ehsa_frontend/lib/students_page.dart +++ b/ehsa_frontend/lib/students_page.dart @@ -34,6 +34,28 @@ class SubjectViewRow { } } +class ClassViewRow { + String + className; // variable name cant be a keyword, so can't use just 'class' + String subject; + String rollList; + String editedClassName; // holds edited class + String editedSubject; // hold edited Subject + String editedRollList; // hold edited Roll list + + ClassViewRow(this.className, this.subject, this.rollList) + : editedClassName = className, + editedSubject = subject, + editedRollList = rollList; + + Map toMap() { + return { + 'class': editedClassName, // Use edited Student in toMap method + 'subject': editedSubject, // Use edited Subject in toMap method + }; + } +} + class StudentsPage extends StatefulWidget { const StudentsPage({super.key}); @@ -48,16 +70,21 @@ class _StudentsPageState extends State { List subjects = []; List filteredSubjects = []; - final TextEditingController _subjectTextEditingController = - TextEditingController(); - String selectedSubject = ''; + // String _subjectTextController.text = ''; - final TextEditingController _classTextEditingController = - TextEditingController(); - final TextEditingController _rollsTextEditingController = - TextEditingController(); + final TextEditingController _classTextController = TextEditingController(); + final TextEditingController _subjectTextController = TextEditingController(); + final TextEditingController _rollsTextController = TextEditingController(); - List isSelected = [true, false]; + // class + final FocusNode _classFocusNode = FocusNode(); + // subject + final FocusNode _subjectFocusNode = FocusNode(); + // rolls + final FocusNode _rollsFocusNode = FocusNode(); + + //TODO: change the ToggleButtons to radial buttons to remove this monstrosity + List isSelected = [true, false, false]; int selectedOption = 1; List subjectViewRows = []; @@ -66,6 +93,9 @@ class _StudentsPageState extends State { List tableViewRows = []; List editedTableViewRows = []; + List classViewRows = []; + List editedClassViewRows = []; + @override void initState() { super.initState(); @@ -78,9 +108,12 @@ class _StudentsPageState extends State { _database = await databaseFactory.openDatabase(path); _database.execute("""CREATE TABLE IF NOT EXISTS students (id CHAR(8) PRIMARY KEY NOT NULL, - subject TEXT NOT NULL)"""); + subject TEXT NOT NULL, + class CHAR(8), + rollno CHAR(8))"""); _fetchTableViewRows(); _subjectListinit(); + _fetchClassViewRows(); } Future _subjectListinit() async { @@ -122,18 +155,33 @@ class _StudentsPageState extends State { }); } + Future _fetchClassViewRows() async { + List> tableData = await _database.rawQuery(''' + SELECT class, subject, GROUP_CONCAT(rollno) AS rolls + FROM students + GROUP BY class, subject; + '''); + setState(() { + classViewRows = tableData.map((row) { + return ClassViewRow( + row['class'], + row['subject'], + sortedRollList(row['rolls']), + ); + }).toList(); + }); + } + Future _updateTableViewRow(TableViewRow row) async { - await _database.update( - 'students', - row.toMap(), - where: 'id = ?', - whereArgs: [row.student_id], - ); + List sID = row.editedStudent_id.split('-'); + await _database.execute( + "UPDATE students SET id = '${row.editedStudent_id}' , subject = '${row.editedSubject}' , class = '${sID[0]}' , rollno = '${sID[1]}' WHERE id = '${row.student_id}'"); if (row.subject != row.editedSubject) { subjects.add(row.editedSubject); } _fetchTableViewRows(); _fetchSubjectViewRows(); + _fetchClassViewRows(); } Future _updateSubjectViewRow(SubjectViewRow row) async { @@ -144,13 +192,108 @@ class _StudentsPageState extends State { } _fetchTableViewRows(); _fetchSubjectViewRows(); + _fetchClassViewRows(); } - Future _dropTable() async { + Future _updateClassViewRowClass(ClassViewRow row) async { + List updateClass = convertStringToList(row.editedRollList); + for (int i in updateClass) { + await _database.execute( + "UPDATE students SET id = '${row.editedClassName}-$i' , class = '${row.editedClassName}' WHERE rollno = '$i' AND class = '${row.className}'"); + } + _fetchTableViewRows(); + _fetchSubjectViewRows(); + _fetchClassViewRows(); + } + + Future _updateClassViewRowSubject(ClassViewRow row) async { await _database.execute( - "DELETE FROM students"); + "UPDATE students SET subject = '${row.editedSubject}' WHERE class = '${row.editedClassName}' AND rollno IN (${row.editedRollList})"); + if (row.subject != row.editedSubject) { + subjects.add(row.editedSubject); + } + _fetchTableViewRows(); + _fetchSubjectViewRows(); + _fetchClassViewRows(); + } + + String expandRanges(String string) { + List result = []; + List ranges = string.split(","); + for (String r in ranges) { + if (r.trim().isNotEmpty) { + // Ignore empty elements + if (r.contains("-")) { + List parts = r.split("-"); + int start = int.parse(parts[0]); + int end = int.parse(parts[1]); + for (int i = start; i <= end; i++) { + result.add(i.toString()); + } + } else { + result.add(r); + } + } + } + return result.join(","); + } + + List> compareLists(List oldList, List newList) { + List commonValues = []; + List removedValues = []; + List addedValues = []; + + // Find common values + for (int value in oldList) { + if (newList.contains(value)) { + commonValues.add(value); + } else { + removedValues.add(value); + } + } + + // Find added values + for (int value in newList) { + if (!oldList.contains(value)) { + addedValues.add(value); + } + } + + return [commonValues, removedValues, addedValues]; + } + + Future _updateClassViewRowrollList(ClassViewRow row) async { + List oldList = convertStringToList(row.rollList); + List newList = convertStringToList(row.editedRollList); + List> rollIdentifier = compareLists(oldList, newList); + // List commonValues = rollIdentifier[0]; + List removedValues = rollIdentifier[1]; + List addedValues = rollIdentifier[2]; + + //delete removed students from db + for (int value in removedValues) { + await _database.execute( + "DELETE FROM students WHERE rollno = '$value' AND subject = '${row.editedSubject}' AND class = '${row.editedClassName}'"); + } + //insert students into db + for (int value in addedValues) { + await _database.execute( + "INSERT INTO students (id, subject, class, rollno) VALUES ('${row.editedClassName}-$value', '${row.editedSubject}', '${row.editedClassName}', $value)"); + } + + if (row.subject != row.editedSubject) { + subjects.add(row.editedSubject); + } + _fetchTableViewRows(); + _fetchSubjectViewRows(); + _fetchClassViewRows(); + } + + Future _dropTable() async { + await _database.execute("DELETE FROM students"); _fetchTableViewRows(); _subjectListinit(); + _fetchClassViewRows(); } Future _deleteTableViewRow(String studentId) async { @@ -161,13 +304,32 @@ class _StudentsPageState extends State { ); _fetchTableViewRows(); _fetchSubjectViewRows(); + _fetchClassViewRows(); } - void updateTableViewRow(TableViewRow row) { - if (!editedTableViewRows.contains(row)) { - setState(() { - editedTableViewRows.add(row); - }); + Future _deleteClassViewRow(ClassViewRow row) async { + await _database.execute( + "DELETE FROM students WHERE rollno IN (${row.editedRollList}) AND class = '${row.editedClassName}'"); + _fetchTableViewRows(); + _fetchSubjectViewRows(); + _fetchClassViewRows(); + } + + void sortList(List values) { + values.sort((a, b) { + final aValue = _getSortValue(a); + final bValue = _getSortValue(b); + return aValue.compareTo(bValue); + }); + } + + int _getSortValue(String value) { + final hyphenIndex = value.indexOf('-'); + if (hyphenIndex != -1) { + final beforeHyphen = value.substring(0, hyphenIndex); + return int.parse(beforeHyphen); + } else { + return int.parse(value); } } @@ -199,13 +361,147 @@ class _StudentsPageState extends State { } } + List convertStringToList(String numbersString) { + // Remove trailing comma if present + if (numbersString.endsWith(',')) { + numbersString = numbersString.substring(0, numbersString.length - 1); + } + + // Split the string into individual numbers + List numberStrings = numbersString.split(','); + + // Convert each number string to an integer + List numbers = + numberStrings.map((numberString) => int.parse(numberString)).toList(); + + // Sort the numbers in ascending order + numbers.sort(); + + return numbers; + } + + String sortedRollList(String numberString) { + List list = convertStringToList(numberString); + list.sort(); + return list.join(','); + } + + void addSubjectToSubjectList() { + String newSubject = _subjectTextController.text.trim(); + if (subjects.contains(newSubject)) { + setState(() { + _subjectTextController.text = newSubject; + }); + _classFocusNode.requestFocus(); + } else if (newSubject.isNotEmpty) { + setState(() { + subjects.add(newSubject); + filteredSubjects = subjects; + }); + } + } + + FocusNode? nextUnfilledTextField() { + if (_classTextController.text.isEmpty) { + return _classFocusNode; + } + if (_subjectTextController.text.isEmpty) { + return _subjectFocusNode; + } + if (_rollsTextController.text.isEmpty) { + return _rollsFocusNode; + } + return null; + } + + void trySubmitForm() { + var studentClass = _classTextController.text; + var rollList = _rollsTextController.text.split(","); + sortList(rollList); + var rollNoRegex = RegExp(r'^(\d+)$|^(\d+-\d+)$'); + var insertValues = ""; + for (var roll in rollList) { + if (!rollNoRegex.hasMatch(roll)) { + //todo: add error snackbar + continue; + } + if (roll.contains("-")) { + var rollNumRange = roll.split("-"); + + for (var i = int.parse(rollNumRange[0]); + i <= int.parse(rollNumRange[1]); + i++) { + insertValues += + "('$studentClass-$i', '${_subjectTextController.text}', '$studentClass', $i), "; + } + } else { + insertValues += + "('$studentClass-$roll', '${_subjectTextController.text}', '$studentClass', $roll), "; + } + } + if (insertValues.isNotEmpty) { + var insertValuesWithoutTrailing = + insertValues.substring(0, insertValues.length - 2); + var command = + "INSERT INTO students (id, subject, class, rollno) VALUES $insertValuesWithoutTrailing"; + _database.execute(command); + } + _classTextController.clear(); + _rollsTextController.clear(); + _subjectTextController.clear(); + _classFocusNode.requestFocus(); + filteredSubjects = subjects; + _fetchSubjectViewRows(); + _fetchTableViewRows(); + _fetchClassViewRows(); + setState(() {}); + } + + void onPressEnter() { + var node = nextUnfilledTextField(); + if (node == null) { + trySubmitForm(); + } else { + node.requestFocus(); + } + } + + void showClearConfirmationDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + content: const Text("Are you sure you want to clear the table?"), + actions: [ + TextButton( + child: const Text("Cancel"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: const Text("Clear"), + onPressed: () { + _dropTable(); + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + @override void dispose() { - _subjectTextEditingController.dispose(); + _subjectTextController.dispose(); _database.close(); super.dispose(); } + int selectedDataCell = 0; Widget buildOptionContainer(int option) { switch (option) { case 1: @@ -233,7 +529,7 @@ class _StudentsPageState extends State { onChanged: (value) { setState(() { row.editedStudent_id = - value; // Update editedHallName + value; // Update editedStudent_id }); }, ) @@ -246,7 +542,7 @@ class _StudentsPageState extends State { onChanged: (value) { setState(() { row.editedSubject = - value; // Update editedCapacity + value; // Update editedSubject }); }, ) @@ -275,7 +571,11 @@ class _StudentsPageState extends State { IconButton( icon: const Icon(Icons.edit), onPressed: () { - updateTableViewRow(row); + if (!editedTableViewRows.contains(row)) { + setState(() { + editedTableViewRows.add(row); + }); + } }, ), IconButton( @@ -367,6 +667,293 @@ class _StudentsPageState extends State { ], ), ); + case 3: + return SizedBox( + width: double.infinity, + child: DataTable( + columns: const [ + DataColumn(label: Text('Class')), + DataColumn(label: Text('Subjects')), + DataColumn(label: Text('Roll List')), + DataColumn(label: Text('Actions')), + DataColumn(label: Text(' ')), + ], + rows: [ + for (var row in classViewRows) + DataRow( + color: editedClassViewRows.contains(row) + ? MaterialStateColor.resolveWith( + (states) => Colors.grey.withOpacity(0.8)) + : MaterialStateColor.resolveWith( + (states) => Colors.transparent), + cells: [ + DataCell( + editedClassViewRows.contains(row) && selectedDataCell == 1 + ? Row( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * + 1 / + 16, + child: TextFormField( + initialValue: row.editedClassName, + onChanged: (value) { + setState(() { + row.editedClassName = + value; // Update editedClassName + }); + }, + ), + ), + IconButton( + icon: const Icon(Icons.done), + onPressed: () { + // Save changes + setState(() { + selectedDataCell = 0; + // Update the changes in the database + _updateClassViewRowClass(row); + editedClassViewRows.remove(row); + }); + }, + ), + IconButton( + icon: const Icon(Icons.cancel), + onPressed: () { + // Cancel edit + setState(() { + selectedDataCell = 0; + row.editedClassName = row.className; + row.editedSubject = row.subject; + row.editedRollList = row.rollList; + editedClassViewRows.remove(row); + }); + }, + ), + ], + ) + : Row( + children: [ + Text(row.editedClassName), + const SizedBox(width: 30), + editedClassViewRows.contains(row) && + selectedDataCell != 0 + ? const SizedBox(width: 5) + : Container( + constraints: const BoxConstraints( + maxHeight: 25, maxWidth: 50), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + Colors.blue.shade400), + shape: MaterialStateProperty.all( + const StadiumBorder())), + child: + const Icon(Icons.edit, size: 18), + onPressed: () { + setState(() { + selectedDataCell = 1; + editedClassViewRows.add(row); + }); + }, + ), + ), + ], + ), + ), + DataCell( + editedClassViewRows.contains(row) && selectedDataCell == 2 + ? Row( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * + 1 / + 16, + child: TextFormField( + initialValue: row.editedSubject, + onChanged: (value) { + setState(() { + row.editedSubject = + value; // Update editedSubject + }); + }, + ), + ), + IconButton( + icon: const Icon(Icons.done), + onPressed: () { + // Save changes + setState(() { + selectedDataCell = 0; + row.rollList = row.editedRollList; + // Update the changes in the database + _updateClassViewRowSubject(row); + editedClassViewRows.remove(row); + }); + }, + ), + IconButton( + icon: const Icon(Icons.cancel), + onPressed: () { + // Cancel edit + setState(() { + selectedDataCell = 0; + row.editedClassName = row.className; + row.editedSubject = row.subject; + row.editedRollList = row.rollList; + editedClassViewRows.remove(row); + }); + }, + ), + ], + ) + : Row( + children: [ + Text(row.editedSubject), + const SizedBox(width: 30), + editedClassViewRows.contains(row) && + selectedDataCell != 0 + ? const SizedBox(width: 5) + : Container( + constraints: const BoxConstraints( + maxHeight: 25, maxWidth: 50), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + Colors.blue.shade400), + shape: MaterialStateProperty.all( + const StadiumBorder())), + child: + const Icon(Icons.edit, size: 18), + onPressed: () { + setState(() { + selectedDataCell = 2; + editedClassViewRows.add(row); + }); + }, + ), + ), + ], + ), + ), + DataCell( + editedClassViewRows.contains(row) && selectedDataCell == 3 + ? Row( + children: [ + SizedBox( + height: double.infinity, + width: 380, + child: TextFormField( + initialValue: row.editedRollList, + onChanged: (value) { + setState(() { + row.editedRollList = + value; // Update editedRollList + }); + }, + ), + ), + IconButton( + icon: const Icon(Icons.done), + onPressed: () { + // Save changes + setState(() { + selectedDataCell = 0; + row.editedRollList = + expandRanges(row.editedRollList); + row.editedRollList = + sortedRollList(row.editedRollList); + // Update the changes in the database + // left to implement + _updateClassViewRowrollList(row); + editedClassViewRows.remove(row); + }); + }, + ), + IconButton( + icon: const Icon(Icons.cancel), + onPressed: () { + // Cancel edit + setState(() { + selectedDataCell = 0; + row.editedRollList = row.rollList; + editedClassViewRows.remove(row); + }); + }, + ), + ], + ) + : Row( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 4), + child: Container( + constraints: const BoxConstraints( + maxWidth: 350, minWidth: 350), + child: ListView.builder( + physics: + const AlwaysScrollableScrollPhysics(), + itemCount: 1, + itemBuilder: (context, index) { + return SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Text( + row.editedRollList + .split(',') + .join(', '), + overflow: TextOverflow.visible, + ), + ); + })), + ), + const SizedBox(width: 30), + editedClassViewRows.contains(row) && + selectedDataCell != 0 + ? const SizedBox(width: 5) + : Container( + constraints: const BoxConstraints( + maxHeight: 25, maxWidth: 50), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty.all( + Colors.blue.shade400), + shape: MaterialStateProperty.all( + const StadiumBorder())), + child: + const Icon(Icons.edit, size: 18), + onPressed: () { + selectedDataCell = 3; + setState(() { + editedClassViewRows.add(row); + }); + }, + ), + ), + ], + ), + ), + DataCell( + IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + setState(() { + // Remove the row from the database + _deleteClassViewRow(row); + }); + }, + ), + ), + const DataCell(SizedBox(width: 2)) + ], + ), + ], + ), + ); + default: return Container(); } @@ -390,8 +977,8 @@ class _StudentsPageState extends State { child: Padding( padding: const EdgeInsets.only(left: 20, right: 20, top: 8), child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( width: 300, @@ -400,17 +987,24 @@ class _StudentsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( - controller: _classTextEditingController, + focusNode: _classFocusNode, + controller: _classTextController, + onSubmitted: (value) { + onPressEnter(); + }, decoration: const InputDecoration( hintText: 'Enter Class', ), ), TextField( - controller: _rollsTextEditingController, + focusNode: _rollsFocusNode, + controller: _rollsTextController, + onSubmitted: (value) { + onPressEnter(); + }, decoration: const InputDecoration( hintText: 'Enter Roll List', ), - maxLines: null, ) ], ), @@ -426,7 +1020,12 @@ class _StudentsPageState extends State { children: [ Expanded( child: TextField( - controller: _subjectTextEditingController, + focusNode: _subjectFocusNode, + controller: _subjectTextController, + onSubmitted: (value) { + addSubjectToSubjectList(); + onPressEnter(); + }, onChanged: (value) { setState(() { filteredSubjects = subjects @@ -444,55 +1043,13 @@ class _StudentsPageState extends State { IconButton( icon: const Icon(Icons.add), onPressed: () { - String newSubject = - _subjectTextEditingController.text - .trim(); - if (newSubject.isNotEmpty && - !subjects.contains(newSubject)) { - setState(() { - subjects.add(newSubject); - filteredSubjects = subjects; - _subjectTextEditingController.clear(); - }); - } + addSubjectToSubjectList(); }, ), ElevatedButton( child: const Text('Submit'), onPressed: () { - var studentClass = - _classTextEditingController.text; - var rollList = _rollsTextEditingController - .text - .split(","); - - for (var roll in rollList) { - if (roll.contains("-")) { - var rollNumRange = roll.split("-"); - - for (var i = int.parse(rollNumRange[0]); - i <= int.parse(rollNumRange[1]); - i++) { - _database.insert('students', { - "id": "$studentClass-$i", - "subject": selectedSubject, - }); - } - } else { - _database.insert('students', { - "id": "$studentClass-$roll", - "subject": selectedSubject, - }); - } - } - - _classTextEditingController.clear(); - _rollsTextEditingController.clear(); - _subjectTextEditingController.clear(); - filteredSubjects = subjects; - _fetchSubjectViewRows(); - _fetchTableViewRows(); - setState(() {}); + trySubmitForm(); }, ), ], @@ -516,11 +1073,10 @@ class _StudentsPageState extends State { dense: true, onTap: () { setState(() { - selectedSubject = + _subjectTextController.text = filteredSubjects[index]; - _subjectTextEditingController.text = - selectedSubject; filteredSubjects = []; + _subjectFocusNode.requestFocus(); }); }, ); @@ -539,8 +1095,9 @@ class _StudentsPageState extends State { ), SizedBox( width: 150, - height: 40, + height: 25, child: ToggleButtons( + borderRadius: const BorderRadius.all(Radius.elliptical(8, 8)), isSelected: isSelected, onPressed: (index) { setState(() { @@ -552,15 +1109,16 @@ class _StudentsPageState extends State { }, children: const [ Text('1'), // Students - Text('2'), // Subjects + Text('2'), + Text('3'), // Subjects ], ), ), Expanded( flex: 3, child: Padding( - padding: const EdgeInsets.only( - left: 16, right: 16, top: 16, bottom: 8), + padding: + const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 8), child: Container( decoration: BoxDecoration( borderRadius: const BorderRadius.vertical( @@ -576,7 +1134,8 @@ class _StudentsPageState extends State { child: Padding( padding: const EdgeInsets.all(10.0), child: ElevatedButton( - onPressed: _dropTable, child: const Text('Clear Table')), + onPressed: showClearConfirmationDialog, + child: const Text('Clear Table')), )), ], ), diff --git a/ehsa_frontend/lib/widgets/stateless/contributor_grid.dart b/ehsa_frontend/lib/widgets/stateless/contributor_grid.dart new file mode 100644 index 00000000..13aa1da3 --- /dev/null +++ b/ehsa_frontend/lib/widgets/stateless/contributor_grid.dart @@ -0,0 +1,115 @@ +import 'package:ehsa_frontend/constants/contributordata.dart'; +import 'package:ehsa_frontend/widgets/stateless/contributor_tile.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class ContributorGrid extends StatelessWidget { + @override + Widget build(BuildContext context) { + int crossAxisCount = 1; + + double width = 2000; + + double screenWidth = MediaQuery.of(context).size.width; + if (screenWidth > 350) { + crossAxisCount = 1; // Display 3 columns on desktop size + width = 400; + } + + if (screenWidth > 750) { + crossAxisCount = 2; // Display 3 columns on desktop size + width = 700; + } + + if (screenWidth > 900) { + crossAxisCount = 3; // Display 3 columns on desktop size + width = 1000; + } + + return Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: MediaQuery.of(context).size.height * 0.170, + width: MediaQuery.of(context).size.width * 0.6, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + ), + child: const Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'EHSA', + style: TextStyle( + height: 1, + fontSize: 50, + fontWeight: FontWeight.bold, + ), + ), + Text( + "by protoRes", + style: TextStyle( + height: 0.8, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 14), + Text( + "Contributors", + style: TextStyle( + fontSize: 15, + ), + ), + ], + ), + ), + const SizedBox(height: 8), + Container( + width: width, + child: Scrollbar( + child: GridView.builder( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + crossAxisSpacing: 4.0, + mainAxisSpacing: 4.0, + childAspectRatio: 2.9, + ), + itemCount: CONTRIBUTOR_DATA.length, + itemBuilder: (context, index) { + return GridItem(data: CONTRIBUTOR_DATA[index]); + }, + ), + ), + ) + ], + ), + ); + } +} + +class GridItem extends StatelessWidget { + final dynamic data; + + const GridItem({Key? key, required this.data}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + launchUrl(Uri.parse(data.profile)); + }, + child: ContributorTile( + name: data.name, + role: data.role, + profile: data.profile, + avatar: data.avatar, + ), + ); + } +} diff --git a/ehsa_frontend/lib/widgets/stateless/contributor_tile.dart b/ehsa_frontend/lib/widgets/stateless/contributor_tile.dart new file mode 100644 index 00000000..36da961c --- /dev/null +++ b/ehsa_frontend/lib/widgets/stateless/contributor_tile.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +class ContributorTile extends StatelessWidget { + final String name; + final String role, profile, avatar; + + ContributorTile( + {Key? key, + required this.name, + required this.role, + required this.profile, + required this.avatar}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Card( + elevation: 0, // Control the elevation/shadow of the card + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CircleAvatar( + foregroundImage: NetworkImage(avatar), + radius: 30, + // You can add avatar properties here + ), + const SizedBox(width: 8), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + name, + style: const TextStyle(fontSize: 18), + ), + Text( + role, + style: const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/ehsa_frontend/linux/flutter/generated_plugin_registrant.cc b/ehsa_frontend/linux/flutter/generated_plugin_registrant.cc index f6f23bfe..0cacc750 100644 --- a/ehsa_frontend/linux/flutter/generated_plugin_registrant.cc +++ b/ehsa_frontend/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,18 @@ #include "generated_plugin_registrant.h" +#include #include +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) screen_retriever_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); + screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); } diff --git a/ehsa_frontend/linux/flutter/generated_plugins.cmake b/ehsa_frontend/linux/flutter/generated_plugins.cmake index f16b4c34..62f151fd 100644 --- a/ehsa_frontend/linux/flutter/generated_plugins.cmake +++ b/ehsa_frontend/linux/flutter/generated_plugins.cmake @@ -3,7 +3,9 @@ # list(APPEND FLUTTER_PLUGIN_LIST + screen_retriever url_launcher_linux + window_manager ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/ehsa_frontend/macos/Flutter/Flutter-Debug.xcconfig b/ehsa_frontend/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b6..4b81f9b2 100644 --- a/ehsa_frontend/macos/Flutter/Flutter-Debug.xcconfig +++ b/ehsa_frontend/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/ehsa_frontend/macos/Flutter/Flutter-Release.xcconfig b/ehsa_frontend/macos/Flutter/Flutter-Release.xcconfig index c2efd0b6..5caa9d15 100644 --- a/ehsa_frontend/macos/Flutter/Flutter-Release.xcconfig +++ b/ehsa_frontend/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/ehsa_frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/ehsa_frontend/macos/Flutter/GeneratedPluginRegistrant.swift index 8236f572..ea24344c 100644 --- a/ehsa_frontend/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/ehsa_frontend/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,12 @@ import FlutterMacOS import Foundation +import screen_retriever import url_launcher_macos +import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) } diff --git a/ehsa_frontend/macos/Podfile b/ehsa_frontend/macos/Podfile new file mode 100644 index 00000000..c795730d --- /dev/null +++ b/ehsa_frontend/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/ehsa_frontend/macos/Podfile.lock b/ehsa_frontend/macos/Podfile.lock new file mode 100644 index 00000000..2538244e --- /dev/null +++ b/ehsa_frontend/macos/Podfile.lock @@ -0,0 +1,34 @@ +PODS: + - FlutterMacOS (1.0.0) + - screen_retriever (0.0.1): + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + - window_manager (0.2.0): + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + screen_retriever: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + window_manager: + :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + +SPEC CHECKSUMS: + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 + url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451 + window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.11.2 diff --git a/ehsa_frontend/macos/Runner.xcodeproj/project.pbxproj b/ehsa_frontend/macos/Runner.xcodeproj/project.pbxproj index 397bb1fa..2f4ce461 100644 --- a/ehsa_frontend/macos/Runner.xcodeproj/project.pbxproj +++ b/ehsa_frontend/macos/Runner.xcodeproj/project.pbxproj @@ -21,14 +21,24 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 6958AD8F7EF76610C61C6F0B /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CDF126327CE8BA86840A58D /* Pods_RunnerTests.framework */; }; + 7FE3DEBB68B425C4511C5742 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62F05F154D1234B52170F01B /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; @@ -52,9 +62,11 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* ehsa_frontend.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ehsa_frontend.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -66,21 +78,46 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 5BACFF2D9FEDCA1A140E43DD /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 62F05F154D1234B52170F01B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 68275AA144CFEBA952696F8D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8CDF126327CE8BA86840A58D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + AA9A5AE5ABAC8354562D1E72 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + C5956AA15E98B6235D0DD326 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + D26A6F885D3AC3FDC364F6F5 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + FF6C8464585A9354AFF9871E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6958AD8F7EF76610C61C6F0B /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7FE3DEBB68B425C4511C5742 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( @@ -97,15 +134,18 @@ children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + F625B1556823007135E54959 /* Pods */, ); sourceTree = ""; }; 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* ehsa_frontend.app */, + 33CC10ED2044A3C60003C045 /* example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -148,22 +188,59 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 62F05F154D1234B52170F01B /* Pods_Runner.framework */, + 8CDF126327CE8BA86840A58D /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; + F625B1556823007135E54959 /* Pods */ = { + isa = PBXGroup; + children = ( + 68275AA144CFEBA952696F8D /* Pods-Runner.debug.xcconfig */, + C5956AA15E98B6235D0DD326 /* Pods-Runner.release.xcconfig */, + FF6C8464585A9354AFF9871E /* Pods-Runner.profile.xcconfig */, + D26A6F885D3AC3FDC364F6F5 /* Pods-RunnerTests.debug.xcconfig */, + 5BACFF2D9FEDCA1A140E43DD /* Pods-RunnerTests.release.xcconfig */, + AA9A5AE5ABAC8354562D1E72 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + BCD9CA57EBAB41E460F4BE27 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + B5571F070F01D7A77DFDE5B8 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 092D3C3A0410C205265B6419 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -172,7 +249,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* ehsa_frontend.app */; + productReference = 33CC10ED2044A3C60003C045 /* example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -185,6 +262,10 @@ LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; @@ -215,12 +296,20 @@ projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -233,6 +322,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 092D3C3A0410C205265B6419 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -271,9 +377,61 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + B5571F070F01D7A77DFDE5B8 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + BCD9CA57EBAB41E460F4BE27 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -287,6 +445,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; @@ -307,6 +470,51 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D26A6F885D3AC3FDC364F6F5 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5BACFF2D9FEDCA1A140E43DD /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AA9A5AE5ABAC8354562D1E72 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Profile; + }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; @@ -537,6 +745,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ehsa_frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ehsa_frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3672a9e3..8fedab68 100644 --- a/ehsa_frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ehsa_frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,12 +31,23 @@ + + + + @@ -71,7 +82,7 @@ diff --git a/ehsa_frontend/macos/Runner.xcworkspace/contents.xcworkspacedata b/ehsa_frontend/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/ehsa_frontend/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/ehsa_frontend/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/ehsa_frontend/macos/Runner/Configs/AppInfo.xcconfig b/ehsa_frontend/macos/Runner/Configs/AppInfo.xcconfig index 521bbd13..dda192bc 100644 --- a/ehsa_frontend/macos/Runner/Configs/AppInfo.xcconfig +++ b/ehsa_frontend/macos/Runner/Configs/AppInfo.xcconfig @@ -5,10 +5,10 @@ // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = ehsa_frontend +PRODUCT_NAME = example // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.ehsaFrontend +PRODUCT_BUNDLE_IDENTIFIER = com.example.example // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/ehsa_frontend/macos/Runner/DebugProfile.entitlements b/ehsa_frontend/macos/Runner/DebugProfile.entitlements index dddb8a30..8cb7022e 100644 --- a/ehsa_frontend/macos/Runner/DebugProfile.entitlements +++ b/ehsa_frontend/macos/Runner/DebugProfile.entitlements @@ -8,5 +8,7 @@ com.apple.security.network.server + com.apple.security.network.client + diff --git a/ehsa_frontend/macos/Runner/MainFlutterWindow.swift b/ehsa_frontend/macos/Runner/MainFlutterWindow.swift index 2722837e..3cc05eb2 100644 --- a/ehsa_frontend/macos/Runner/MainFlutterWindow.swift +++ b/ehsa_frontend/macos/Runner/MainFlutterWindow.swift @@ -3,7 +3,7 @@ import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() + let flutterViewController = FlutterViewController() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) diff --git a/ehsa_frontend/macos/Runner/Release.entitlements b/ehsa_frontend/macos/Runner/Release.entitlements index 852fa1a4..48271acc 100644 --- a/ehsa_frontend/macos/Runner/Release.entitlements +++ b/ehsa_frontend/macos/Runner/Release.entitlements @@ -4,5 +4,7 @@ com.apple.security.app-sandbox + com.apple.security.network.client + diff --git a/ehsa_frontend/macos/RunnerTests/RunnerTests.swift b/ehsa_frontend/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..5418c9f5 --- /dev/null +++ b/ehsa_frontend/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/ehsa_frontend/pubspec.lock b/ehsa_frontend/pubspec.lock index 1f0e7b54..0da7ded6 100644 --- a/ehsa_frontend/pubspec.lock +++ b/ehsa_frontend/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.3" + bloc: + dependency: transitive + description: + name: bloc + sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + url: "https://pub.dev" + source: hosted + version: "8.1.2" boolean_selector: dependency: transitive description: @@ -73,11 +81,27 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + fluent_ui: + dependency: "direct main" + description: + name: fluent_ui + sha256: "9957c04c0b73f366f94dea1422c80c2c21511453e727d7b1b5836dc457add5bf" + url: "https://pub.dev" + source: hosted + version: "4.7.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + url: "https://pub.dev" + source: hosted + version: "8.1.3" flutter_lints: dependency: "direct dev" description: @@ -91,14 +115,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_neumorphic: - dependency: "direct main" - description: - name: flutter_neumorphic - sha256: "02606d937a3ceaa497b8a7c25f3efa95188bf93d77ebf0bd6552e432db4c2ec6" - url: "https://pub.dev" - source: hosted - version: "3.2.0" flutter_svg: dependency: transitive description: @@ -157,6 +173,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + math_expressions: + dependency: transitive + description: + name: math_expressions + sha256: "3576593617c3870d75728a751f6ec6e606706d44e363f088ac394b5a28a98064" + url: "https://pub.dev" + source: hosted + version: "2.4.0" meta: dependency: transitive description: @@ -165,6 +189,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -197,6 +229,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + provider: + dependency: transitive + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + screen_retriever: + dependency: transitive + description: + name: screen_retriever + sha256: "4931f226ca158123ccd765325e9fbf360bfed0af9b460a10f960f9bb13d58323" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + scroll_pos: + dependency: transitive + description: + name: scroll_pos + sha256: "4246bff3afc779d87cdf650a67d42d67ae71b23ff020d14592e6b89e28a7f9cc" + url: "https://pub.dev" + source: hosted + version: "0.4.0" sky_engine: dependency: transitive description: flutter @@ -378,6 +442,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + window_manager: + dependency: "direct main" + description: + name: window_manager + sha256: "95096fede562cbb65f30d38b62d819a458f59ba9fe4a317f6cee669710f6676b" + url: "https://pub.dev" + source: hosted + version: "0.3.4" xml: dependency: transitive description: @@ -388,4 +460,4 @@ packages: version: "6.3.0" sdks: dart: ">=3.0.0 <4.0.0" - flutter: ">=3.7.0-0" + flutter: ">=3.10.0" diff --git a/ehsa_frontend/pubspec.yaml b/ehsa_frontend/pubspec.yaml index 9cce3ed0..92001e40 100644 --- a/ehsa_frontend/pubspec.yaml +++ b/ehsa_frontend/pubspec.yaml @@ -32,8 +32,10 @@ dependencies: sdk: flutter sqflite_common_ffi: ^2.2.5 url_launcher: ^6.1.11 - flutter_neumorphic: ^3.0.0 awesome_snackbar_content: ^0.1.3 + window_manager: ^0.3.4 + fluent_ui: ^4.4.0 + flutter_bloc: ^8.1.3 dev_dependencies: flutter_test: diff --git a/ehsa_frontend/windows/flutter/generated_plugin_registrant.cc b/ehsa_frontend/windows/flutter/generated_plugin_registrant.cc index 4f788487..fe7ec1cb 100644 --- a/ehsa_frontend/windows/flutter/generated_plugin_registrant.cc +++ b/ehsa_frontend/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,15 @@ #include "generated_plugin_registrant.h" +#include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + ScreenRetrieverPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); + WindowManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowManagerPlugin")); } diff --git a/ehsa_frontend/windows/flutter/generated_plugins.cmake b/ehsa_frontend/windows/flutter/generated_plugins.cmake index 88b22e5c..fb2dea6b 100644 --- a/ehsa_frontend/windows/flutter/generated_plugins.cmake +++ b/ehsa_frontend/windows/flutter/generated_plugins.cmake @@ -3,7 +3,9 @@ # list(APPEND FLUTTER_PLUGIN_LIST + screen_retriever url_launcher_windows + window_manager ) list(APPEND FLUTTER_FFI_PLUGIN_LIST