From 2941d52a1d10f6a25e8823910ea2803e552ba3ea Mon Sep 17 00:00:00 2001 From: Shivanshu Gupta Date: Mon, 14 Aug 2023 16:11:37 +0530 Subject: [PATCH] Changed many things --- lib/firebase_options.dart | 1 + lib/main.dart | 84 ++++++---- .../notifications/notifications.dart | 40 +++++ lib/providers/settings.dart | 2 +- .../admin_panel/admin_panel_screen.dart | 17 ++- lib/screens/drawers/main_drawer.dart | 144 +++++++++++------- lib/screens/main_screen.dart | 30 ++-- .../attendance/attendance_request_screen.dart | 10 +- .../requests/mess/menu_change_screen.dart | 28 ++-- .../requests/other/other_request_screen.dart | 28 ++-- lib/screens/requests/requests_screen.dart | 4 +- .../vehicle/vehicle_request_form_screen.dart | 33 ++-- lib/screens/settings/settings_screen.dart | 111 +++++--------- lib/screens/vehicle/vehicle_screen.dart | 13 +- .../complaints/complaint_category_view.dart | 2 + lib/widgets/complaints/complaint_form.dart | 27 ++-- lib/widgets/requests/request_info.dart | 4 +- lib/widgets/settings/current_user_tile.dart | 4 +- pubspec.yaml | 2 + 19 files changed, 341 insertions(+), 243 deletions(-) create mode 100644 lib/providers/notifications/notifications.dart diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart index fadaa98..f60effb 100644 --- a/lib/firebase_options.dart +++ b/lib/firebase_options.dart @@ -56,6 +56,7 @@ class DefaultFirebaseOptions { projectId: 'hustle-stay', authDomain: 'hustle-stay.firebaseapp.com', storageBucket: 'hustle-stay.appspot.com', + measurementId: 'G-5SHV2ZPSH9', ); static const FirebaseOptions android = FirebaseOptions( diff --git a/lib/main.dart b/lib/main.dart index 157f648..48b60f0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -31,38 +32,24 @@ SharedPreferences? prefs; final auth = FirebaseAuth.instance; final firestore = FirebaseFirestore.instance; final storage = FirebaseStorage.instance; +final firebaseMessaging = FirebaseMessaging.instance; /// Main function void main() async { - // Just to show errors not so rudely - ErrorWidget.builder = (FlutterErrorDetails details) { - return Material( - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - ':-( Something went wrong!', - style: TextStyle(fontSize: 20), - textAlign: TextAlign.center, - ), - Text( - '\n${details.exception}', - style: const TextStyle(color: Colors.red), - textAlign: TextAlign.center, - ), - const Text( - 'Contact shivanshukgupta or sanidhayasharma141 on linkedin for support\n', - textAlign: TextAlign.center, - ), - ], - )); - }; - WidgetsFlutterBinding.ensureInitialized(); + /// Just to show errors not so rudely + setErrorWidget(); + // Initializing Firebase SDK + WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); + + /// Setting up firebase messaging + final fcmToken = await firebaseMessaging.getToken(); + debugPrint("fcmToken = $fcmToken"); + initializeFCM(); + // Initializing prefs here in main to avoid any delay in activating settings prefs = await SharedPreferences.getInstance(); try { @@ -86,6 +73,45 @@ void main() async { runApp(const ProviderScope(child: HustleStayApp())); } +void initializeFCM() { + firebaseMessaging.onTokenRefresh.listen((fcmToken) { + debugPrint("FCM Token was refreshed. The new token is: $fcmToken"); + // TODO: If necessary send token to application server. + + // Note: This callback is fired at each app startup and whenever a new + // token is generated. + }).onError((err) { + debugPrint("Error: $err"); + // Error getting token. + }); +} + +void setErrorWidget() { + ErrorWidget.builder = (FlutterErrorDetails details) { + return Material( + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + ':-( Something went wrong!', + style: TextStyle(fontSize: 20), + textAlign: TextAlign.center, + ), + Text( + '\n${details.exception}', + style: const TextStyle(color: Colors.red), + textAlign: TextAlign.center, + ), + const Text( + 'Contact shivanshukgupta or sanidhayasharma141 on linkedin for support\n', + textAlign: TextAlign.center, + ), + ], + )); + }; +} + /// The main app widget class HustleStayApp extends ConsumerWidget { const HustleStayApp({super.key}); @@ -182,7 +208,11 @@ Future initializeEverything() async { await initializeComplaints(); everythingInitialized.value = "Fetching requests"; await initializeRequests(); - everythingInitialized.value = "Fetching vehicle requests"; - await initializeVehicleRequests(); + + if (currentUser.type == 'warden' || + currentUser.email == 'vehicle@iiitr.ac.in') { + everythingInitialized.value = "Fetching vehicle requests"; + await initializeVehicleRequests(); + } everythingInitialized.value = null; } diff --git a/lib/providers/notifications/notifications.dart b/lib/providers/notifications/notifications.dart new file mode 100644 index 0000000..7937132 --- /dev/null +++ b/lib/providers/notifications/notifications.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; + +Future sendNotification({ + String? title, + String? body, + String to = '/topics/all', +}) async { + /// TODO: Dangerous!!! the fcm API key is here and should be moved to a backend + /// ERR: + const String serverKey = + 'AAAAmUIGOT0:APA91bEVQn5IIBwUrIG8Brgf3vzZ-KxaGnDYY_8ElgZq65t909kx_EzFz6l613Kny_4Jh0JTcbm-EE3dvWGWM7dMISwseQ_wF0iYPDX9ti-nJKqrxKOXt3sKtXWh-VXSX_e3fsapadQO'; + const String fcmUrl = 'https://fcm.googleapis.com/fcm/send'; + + final Map notification = { + 'to': to, + 'notification': { + 'title': title, + 'body': body, + }, + }; + + final headers = { + 'Content-Type': 'application/json', + 'Authorization': 'key=$serverKey', + }; + + final response = await http.post( + Uri.parse(fcmUrl), + headers: headers, + body: jsonEncode(notification), + ); + + if (response.statusCode == 200) { + print('Notification sent successfully'); + } else { + print('Failed to send notification: ${response.body}'); + } +} diff --git a/lib/providers/settings.dart b/lib/providers/settings.dart index 427f14a..b88641c 100644 --- a/lib/providers/settings.dart +++ b/lib/providers/settings.dart @@ -12,7 +12,7 @@ class _Settings { bool autoDarkMode = true; /// the last visited page - int currentPage = 3; + int currentPage = 2; /// Introduction screen visisted bool introductionScreenVisited = false; diff --git a/lib/screens/admin_panel/admin_panel_screen.dart b/lib/screens/admin_panel/admin_panel_screen.dart index 242f2c9..24e37e2 100644 --- a/lib/screens/admin_panel/admin_panel_screen.dart +++ b/lib/screens/admin_panel/admin_panel_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hustle_stay/screens/admin_panel/manage_categories.dart'; import 'package:hustle_stay/screens/admin_panel/manage_requests.dart'; import 'package:hustle_stay/screens/admin_panel/manage_user_permission.dart'; +import 'package:hustle_stay/screens/vehicle/vehicle_screen.dart'; import '../../models/common/operation.dart'; import 'manage_hostel_attendance.dart'; @@ -30,7 +31,11 @@ class _AdminPanelState extends State { Operations( cardColor: const Color.fromARGB(255, 0, 146, 69), operationName: 'Manage Hostels & Attendance', - icon: const Icon(Icons.calendar_month)) + icon: const Icon(Icons.calendar_month)), + Operations( + cardColor: const Color.fromARGB(255, 0, 136, 146), + operationName: 'Vehicle Schedule', + icon: const Icon(Icons.airport_shuttle_rounded)), ]; @override @@ -41,16 +46,16 @@ class _AdminPanelState extends State { return Scaffold( appBar: AppBar( - title: Text('Admin Panel'), + title: const Text('Admin Panel'), ), body: SafeArea( child: GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1, ), itemBuilder: (context, index) { - final Color cardColor = catList[index].cardColor!; + final Color cardColor = catList[index].cardColor; final LinearGradient gradient = LinearGradient( begin: Alignment.topCenter, @@ -84,6 +89,10 @@ class _AdminPanelState extends State { Navigator.of(context).push(MaterialPageRoute( builder: (_) => const ManageHostelPage())); break; + case 'Vehicle Schedule': + Navigator.of(context).push(MaterialPageRoute( + builder: (_) => const VehicleScreen())); + break; default: } }, diff --git a/lib/screens/drawers/main_drawer.dart b/lib/screens/drawers/main_drawer.dart index 134d47d..6485420 100644 --- a/lib/screens/drawers/main_drawer.dart +++ b/lib/screens/drawers/main_drawer.dart @@ -1,8 +1,15 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:hustle_stay/main.dart'; +import 'package:hustle_stay/providers/notifications/notifications.dart'; +import 'package:hustle_stay/screens/about/about_screen.dart'; import 'package:hustle_stay/screens/category/edit_category_screen.dart'; import 'package:hustle_stay/screens/complaints/resolved_complaints_screen.dart'; +import 'package:hustle_stay/screens/help/help_screen.dart'; import 'package:hustle_stay/tools.dart'; +import 'package:hustle_stay/widgets/other/loading_elevated_button.dart'; import 'package:hustle_stay/widgets/settings/current_user_tile.dart'; +import 'package:hustle_stay/widgets/settings/sign_out_button.dart'; class MainDrawer extends StatelessWidget { const MainDrawer({super.key}); @@ -32,38 +39,39 @@ class MainDrawer extends StatelessWidget { children: [ const CurrentUserTile(), const Divider(), - _drawerTile( - context, - title: "Resolved Complaints", - icon: Icons.person_add_rounded, - subtitle: "View resolved complaints", - onTap: () async { - navigatorPush( - context, - ResolvedComplaintsScreen(), - ); - }, - ), - _drawerTile( - context, - title: "Add a new category", - icon: Icons.person_add_rounded, - subtitle: "Categories are used in complaints and requests", - onTap: () async { - navigatorPush( - context, - const EditCategoryScreen(), - ); - }, - ), + if (kDebugMode) + _drawerTile( + context, + title: "Resolved Complaints", + icon: Icons.person_add_rounded, + subtitle: "View resolved complaints", + onTap: () async { + navigatorPush( + context, + ResolvedComplaintsScreen(), + ); + }, + ), + if (kDebugMode) + _drawerTile( + context, + title: "Add a new category", + icon: Icons.person_add_rounded, + subtitle: "Categories are used in complaints and requests", + onTap: () async { + navigatorPush( + context, + const EditCategoryScreen(), + ); + }, + ), _drawerTile( context, title: "How to use?", icon: Icons.help_rounded, subtitle: "Help on how to use the app", onTap: () { - // TODO: Add a help screen - showMsg(context, "TODO: Add a Help Screen"); + navigatorPush(context, const HelpScreen()); }, ), _drawerTile( @@ -72,8 +80,7 @@ class MainDrawer extends StatelessWidget { icon: Icons.info_rounded, subtitle: "Know more about us and the app", onTap: () { - // TODO: add a about us page - showMsg(context, "TODO: Add a About us Screen"); + navigatorPush(context, const AboutScreen()); }, ), ], @@ -84,31 +91,66 @@ class MainDrawer extends StatelessWidget { return Column( mainAxisSize: MainAxisSize.min, children: [ - const Divider(), - ListTile( - contentPadding: - const EdgeInsets.only(left: 15, right: 15, bottom: 10), - leading: const Icon( - Icons.emergency_share_rounded, - color: Colors.red, - ), - title: Text( - 'Medical Emergency', - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(color: Colors.red), - ), - subtitle: Text( - 'Make emergency vehicle request and inform all wardens', - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.primary, + LayoutBuilder( + builder: (context, constraints) => SizedBox( + width: constraints.maxWidth, + child: Wrap( + alignment: WrapAlignment.spaceAround, + children: [ + if (kDebugMode) + LoadingElevatedButton( + icon: const Icon(Icons.abc_rounded), + label: const Text('Send notification'), + onPressed: () async => await sendNotification( + title: "Not Title", + body: "Description", + ), + ), + // if (kDebugMode) + // LoadingElevatedButton( + // icon: const Icon(Icons.temple_buddhist_rounded), + // label: const Text('Edit Category'), + // onPressed: () async { + // await navigatorPush( + // context, + // const EditCategoryScreen( + // id: 'Bullying', + // ), + // ); + // }, + // ), + ValueListenableBuilder( + valueListenable: everythingInitialized, + builder: (context, value, child) { + return LoadingElevatedButton( + loading: value != null, + errorHandler: (err) { + everythingInitialized.value = null; + }, + icon: const Icon(Icons.refresh_rounded), + label: Text(value ?? 'Refresh Local Database'), + onPressed: initializeEverything, + ); + }, ), + // ElevatedButton.icon( + // onPressed: () { + // navigatorPush(context, const AboutScreen()); + // }, + // icon: const Icon(Icons.info_outline_rounded), + // label: const Text('About Us'), + // ), + // ElevatedButton.icon( + // onPressed: () { + // navigatorPush(context, const HelpScreen()); + // }, + // icon: const Icon(Icons.help_outline_outlined), + // label: const Text('Help'), + // ), + if (kDebugMode) const SignOutButton(), + ], + ), ), - onTap: () { - // TODO: add a medical emergency screen - showMsg(context, 'TODO: add a medical emergency screen'); - }, ), ], ); diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index 9ab5836..eacc7ed 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -45,10 +45,16 @@ class _HomeScreenState extends ConsumerState { ? const AttendanceScreen() : const HostelScreen(), const ComplaintsScreen(), - VehicleScreen(), - const RequestsScreen(), const SettingsScreen(), + const RequestsScreen(), + if (currentUser.type == 'warden' || + currentUser.email == 'vehicle@iiitr.ac.in') + const VehicleScreen(), ]; + if (settings.currentPage >= bodyList.length) { + settings.currentPage = bodyList.length - 1; + settingsClass.saveSettings(); + } return WillPopScope( onWillPop: () async { if (canExit) return true; @@ -103,9 +109,9 @@ class _HomeScreenState extends ConsumerState { ), GButton( icon: settings.currentPage == i++ - ? Icons.airport_shuttle_rounded - : Icons.airport_shuttle_outlined, - text: 'Vehicle', + ? Icons.person_rounded + : Icons.person_outlined, + text: 'Profile', ), GButton( icon: settings.currentPage == i++ @@ -113,12 +119,14 @@ class _HomeScreenState extends ConsumerState { : Icons.assignment_turned_in_outlined, text: 'Requests', ), - GButton( - icon: settings.currentPage == i++ - ? Icons.settings_rounded - : Icons.settings_outlined, - text: 'Settings', - ), + if (currentUser.type == 'warden' || + currentUser.email == 'vehicle@iiitr.ac.in') + GButton( + icon: settings.currentPage == i++ + ? Icons.airport_shuttle_rounded + : Icons.airport_shuttle_outlined, + text: 'Vehicle', + ), ], ), ), diff --git a/lib/screens/requests/attendance/attendance_request_screen.dart b/lib/screens/requests/attendance/attendance_request_screen.dart index c2f1bc1..e7137fa 100644 --- a/lib/screens/requests/attendance/attendance_request_screen.dart +++ b/lib/screens/requests/attendance/attendance_request_screen.dart @@ -20,7 +20,7 @@ class AttendanceRequestScreen extends StatelessWidget { appBar: AppBar( title: shaderText( context, - title: 'Attendance Request', + title: 'Hostel Request', style: theme.textTheme.titleLarge!.copyWith(fontWeight: FontWeight.bold), ), @@ -33,9 +33,9 @@ class AttendanceRequestScreen extends StatelessWidget { onTap: () async { Navigator.of(context).pop(); }, - title: 'Attendance', + title: 'Hostel', icon: Icon( - requestMainPageElements['Attendance']!['icon'], + requestMainPageElements['Hostel']!['icon'], size: 50, ), color: theme.colorScheme.background, @@ -86,7 +86,7 @@ class AttendanceRequestScreen extends StatelessWidget { ), GridTileLogo( onTap: () async { - await navigatorPush(context, UpdateRoom()); + await navigatorPush(context, const UpdateRoom()); }, title: 'Change Room', icon: Icon( @@ -103,7 +103,7 @@ class AttendanceRequestScreen extends StatelessWidget { onTap: () async { await navigatorPush( context, - UpdateRoom( + const UpdateRoom( isSwap: true, )); }, diff --git a/lib/screens/requests/mess/menu_change_screen.dart b/lib/screens/requests/mess/menu_change_screen.dart index 091e8dd..c1ed455 100644 --- a/lib/screens/requests/mess/menu_change_screen.dart +++ b/lib/screens/requests/mess/menu_change_screen.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:hustle_stay/models/chat/message.dart'; import 'package:hustle_stay/models/requests/mess/menu_change_request.dart'; import 'package:hustle_stay/models/user/user.dart'; -import 'package:hustle_stay/screens/chat/chat_screen.dart'; import 'package:hustle_stay/tools.dart'; -import 'package:hustle_stay/widgets/chat/template_messages.dart'; import 'package:hustle_stay/widgets/other/select_one.dart'; import 'package:hustle_stay/widgets/requests/grid_tile_logo.dart'; @@ -184,18 +181,19 @@ class _MenuChangeRequestScreenState extends State { Navigator.of(context).pop(true); } if (!isUpdate) { - navigatorPush( - context, - ChatScreen( - chat: widget.request!.chatData, - initialMsg: MessageData( - id: DateTime.now().millisecondsSinceEpoch.toString(), - from: currentUser.email!, - createdAt: DateTime.now(), - txt: messMenuChangeMessage(widget.request!), - ), - ), - ); + /// TODO: These lines of code allow us to navigate to the chat screen with a template message for the request + // navigatorPush( + // context, + // ChatScreen( + // chat: widget.request!.chatData, + // initialMsg: MessageData( + // id: DateTime.now().millisecondsSinceEpoch.toString(), + // from: currentUser.email!, + // createdAt: DateTime.now(), + // txt: messMenuChangeMessage(widget.request!), + // ), + // ), + // ); } } } diff --git a/lib/screens/requests/other/other_request_screen.dart b/lib/screens/requests/other/other_request_screen.dart index e6d590d..af8fe0d 100644 --- a/lib/screens/requests/other/other_request_screen.dart +++ b/lib/screens/requests/other/other_request_screen.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:hustle_stay/models/chat/message.dart'; import 'package:hustle_stay/models/requests/other/other_request.dart'; import 'package:hustle_stay/models/user/user.dart'; -import 'package:hustle_stay/screens/chat/chat_screen.dart'; import 'package:hustle_stay/screens/filter_screen/filter_choser_screen.dart'; import 'package:hustle_stay/tools.dart'; -import 'package:hustle_stay/widgets/chat/template_messages.dart'; import 'package:hustle_stay/widgets/requests/grid_tile_logo.dart'; // ignore: must_be_immutable @@ -144,18 +141,19 @@ class _OtherRequestScreenState extends State { Navigator.of(context).pop(true); } if (!isUpdate) { - navigatorPush( - context, - ChatScreen( - chat: widget.request!.chatData, - initialMsg: MessageData( - id: DateTime.now().millisecondsSinceEpoch.toString(), - from: currentUser.email!, - createdAt: DateTime.now(), - txt: otherRequestMessage(widget.request!), - ), - ), - ); + /// TODO: These lines of code allow us to navigate to the chat screen with a template message for the request + // navigatorPush( + // context, + // ChatScreen( + // chat: widget.request!.chatData, + // initialMsg: MessageData( + // id: DateTime.now().millisecondsSinceEpoch.toString(), + // from: currentUser.email!, + // createdAt: DateTime.now(), + // txt: otherRequestMessage(widget.request!), + // ), + // ), + // ); } } } diff --git a/lib/screens/requests/requests_screen.dart b/lib/screens/requests/requests_screen.dart index 8a4f357..181144e 100644 --- a/lib/screens/requests/requests_screen.dart +++ b/lib/screens/requests/requests_screen.dart @@ -7,9 +7,9 @@ import 'package:hustle_stay/screens/requests/vehicle/vehicle_requests_screen.dar import 'package:hustle_stay/widgets/requests/requests_list.dart'; const requestMainPageElements = >{ - 'Attendance': { + 'Hostel': { 'color': Colors.red, - 'icon': Icons.calendar_month_rounded, + 'icon': Icons.account_balance_outlined, 'route': AttendanceRequestScreen.routeName, }, 'Vehicle': { diff --git a/lib/screens/requests/vehicle/vehicle_request_form_screen.dart b/lib/screens/requests/vehicle/vehicle_request_form_screen.dart index e7165bd..45facfd 100644 --- a/lib/screens/requests/vehicle/vehicle_request_form_screen.dart +++ b/lib/screens/requests/vehicle/vehicle_request_form_screen.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:hustle_stay/models/chat/message.dart'; import 'package:hustle_stay/models/requests/vehicle/vehicle_request.dart'; import 'package:hustle_stay/models/user/user.dart'; -import 'package:hustle_stay/screens/chat/chat_screen.dart'; import 'package:hustle_stay/tools.dart'; -import 'package:hustle_stay/widgets/chat/template_messages.dart'; import 'package:hustle_stay/widgets/other/select_one.dart'; import 'package:hustle_stay/widgets/requests/grid_tile_logo.dart'; @@ -208,20 +205,22 @@ class _VehicleRequestFormScreenState extends State { while (Navigator.of(context).canPop()) { Navigator.of(context).pop(true); } - if (!isAnUpdate) { - navigatorPush( - context, - ChatScreen( - chat: widget.request!.chatData, - initialMsg: MessageData( - id: DateTime.now().millisecondsSinceEpoch.toString(), - from: currentUser.email!, - createdAt: DateTime.now(), - txt: vanRequestTemplateMessage(widget.request!, widget.title), - ), - ), - ); - } + + /// TODO: These lines of code allow us to navigate to the chat screen with a template message for the request + // if (!isAnUpdate) { + // navigatorPush( + // context, + // ChatScreen( + // chat: widget.request!.chatData, + // initialMsg: MessageData( + // id: DateTime.now().millisecondsSinceEpoch.toString(), + // from: currentUser.email!, + // createdAt: DateTime.now(), + // txt: vanRequestTemplateMessage(widget.request!, widget.title), + // ), + // ), + // ); + // } } } } diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart index e3405c6..024d672 100644 --- a/lib/screens/settings/settings_screen.dart +++ b/lib/screens/settings/settings_screen.dart @@ -1,18 +1,15 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:hustle_stay/main.dart'; import 'package:hustle_stay/models/user/user.dart'; -import 'package:hustle_stay/screens/about/about_screen.dart'; import 'package:hustle_stay/screens/admin_panel/admin_panel_screen.dart'; import 'package:hustle_stay/screens/chat/private_chats.dart'; +import 'package:hustle_stay/screens/drawers/main_drawer.dart'; import 'package:hustle_stay/screens/filter_screen/stats_screen.dart'; -import 'package:hustle_stay/screens/help/help_screen.dart'; import 'package:hustle_stay/screens/medical_screen/medical_screen.dart'; import 'package:hustle_stay/screens/profile/profile_preview.dart'; import 'package:hustle_stay/screens/requests/stats/requests_stats_screen.dart'; import 'package:hustle_stay/tools.dart'; import 'package:hustle_stay/widgets/other/dark_light_mode_icon_button.dart'; -import 'package:hustle_stay/widgets/other/loading_elevated_button.dart'; -import 'package:hustle_stay/widgets/settings/sign_out_button.dart'; class SettingsScreen extends StatelessWidget { const SettingsScreen({super.key}); @@ -33,7 +30,6 @@ class SettingsScreen extends StatelessWidget { // title: 'Other Features', // style: Theme.of(context).textTheme.bodyLarge), // ), - ListTile( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), @@ -46,6 +42,19 @@ class SettingsScreen extends StatelessWidget { navigatorPush(context, const ChatsScreen()); }, ), + ListTile( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + leading: const Icon(Icons.medical_information_rounded), + title: const Text('Filter Medical Info'), + subtitle: + const Text('Filter people based on their medical information'), + tileColor: Theme.of(context).colorScheme.primary.withOpacity(0.1), + onTap: () { + navigatorPush(context, const MedicalScreen()); + }, + ), if (currentUser.isAdmin) ListTile( shape: RoundedRectangleBorder( @@ -86,75 +95,35 @@ class SettingsScreen extends StatelessWidget { navigatorPush(context, const RequestsStatisticsPage()); }, ), - - const Divider(), - SizedBox( - width: MediaQuery.of(context).size.width, - child: Wrap( - alignment: WrapAlignment.spaceAround, - children: [ - ElevatedButton.icon( - onPressed: () { - navigatorPush(context, const AboutScreen()); - }, - icon: const Icon(Icons.info_outline_rounded), - label: const Text('About Us'), - ), - ElevatedButton.icon( - onPressed: () { - navigatorPush(context, const HelpScreen()); - }, - icon: const Icon(Icons.help_outline_rounded), - label: const Text('Help'), - ), - ValueListenableBuilder( - valueListenable: everythingInitialized, - builder: (context, value, child) { - return LoadingElevatedButton( - loading: value != null, - errorHandler: (err) { - everythingInitialized.value = null; - }, - icon: const Icon(Icons.refresh_rounded), - label: Text(value ?? 'Refresh Local Database'), - onPressed: initializeEverything, - ); - }, - ), - const SignOutButton(), - ElevatedButton.icon( - onPressed: () { - navigatorPush(context, const MedicalScreen()); - }, - style: ElevatedButton.styleFrom(foregroundColor: Colors.red), - icon: const Icon(Icons.warning_amber_rounded), - label: const Text('Medical Emergency'), - ), - ], - ), - ), ]; return Scaffold( appBar: AppBar( - // backgroundColor: Colors.transparent, - // elevation: 0, - title: shaderText( - context, - style: Theme.of(context).textTheme.titleLarge!.copyWith( - fontWeight: FontWeight.bold, - ), - title: 'Settings', - ), - actions: const [DarkLightModeIconButton()], + // title: shaderText( + // context, + // style: Theme.of(context).textTheme.titleLarge!.copyWith( + // fontWeight: FontWeight.bold, + // ), + // title: 'Your Profile', + // ), + actions: const [ + DarkLightModeIconButton(), + ], ), - // drawer: const MainDrawer(), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: ListView.separated( - itemCount: children.length, - separatorBuilder: (ctx, index) => const SizedBox(height: 15), - itemBuilder: (ctx, index) => children[index], - ), + drawer: kDebugMode ? const MainDrawer() : null, + body: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: ListView.separated( + itemCount: children.length, + separatorBuilder: (ctx, index) => const SizedBox(height: 5), + itemBuilder: (ctx, index) => children[index], + ), + ), + ), + ], ), ); } diff --git a/lib/screens/vehicle/vehicle_screen.dart b/lib/screens/vehicle/vehicle_screen.dart index 68482a2..2750e5a 100644 --- a/lib/screens/vehicle/vehicle_screen.dart +++ b/lib/screens/vehicle/vehicle_screen.dart @@ -18,6 +18,7 @@ class VehicleScreen extends StatefulWidget { class _VehicleScreenState extends State { Map savePoint = {}; + int i = 0; @override Widget build(BuildContext context) { @@ -28,7 +29,7 @@ class _VehicleScreenState extends State { backgroundColor: Colors.transparent, title: shaderText( context, - title: 'Vehicle', + title: 'Vehicle Schedule', style: Theme.of(context).textTheme.titleLarge!.copyWith( fontWeight: FontWeight.bold, ), @@ -44,6 +45,7 @@ class _VehicleScreenState extends State { onPressed: () async { await initializeVehicleRequests(); setState(() { + i++; savePoint.clear(); }); }, @@ -62,8 +64,7 @@ class _VehicleScreenState extends State { }, child: Container(), ), - key: UniqueKey(), - reverse: true, + key: ValueKey(i), loader: (ctx, start, limit) async { final requests = await fetchVehicleRequests( limit: limit, @@ -101,14 +102,14 @@ class _VehicleScreenState extends State { Text( request.dateTime!.day.toString(), style: Theme.of(context).textTheme.bodyMedium!.copyWith( - // fontWeight: FontWeight.bold, + fontWeight: FontWeight.bold, ), ), Text( getMonth(request.dateTime!.month), style: Theme.of(context).textTheme.labelSmall!.copyWith( - fontSize: 8, - // fontWeight: FontWeight.bold, + fontSize: 10, + fontWeight: FontWeight.bold, ), ), ], diff --git a/lib/widgets/complaints/complaint_category_view.dart b/lib/widgets/complaints/complaint_category_view.dart index 491615d..f8468ff 100644 --- a/lib/widgets/complaints/complaint_category_view.dart +++ b/lib/widgets/complaints/complaint_category_view.dart @@ -46,6 +46,8 @@ class ComplaintCategoryView extends StatelessWidget { groups[category.parent!]!.add(category); } } + // TODO: Removed other here, just from the UI + parents.remove('Other'); return GridView.extent( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, diff --git a/lib/widgets/complaints/complaint_form.dart b/lib/widgets/complaints/complaint_form.dart index df1d8ce..76efba3 100644 --- a/lib/widgets/complaints/complaint_form.dart +++ b/lib/widgets/complaints/complaint_form.dart @@ -5,8 +5,6 @@ import 'package:hustle_stay/models/chat/message.dart'; import 'package:hustle_stay/models/complaint/complaint.dart'; import 'package:hustle_stay/models/user/user.dart'; import 'package:hustle_stay/tools.dart'; -import 'package:hustle_stay/widgets/chat/template_messages.dart'; -import 'package:hustle_stay/widgets/complaints/complaint_list_item.dart'; import 'package:hustle_stay/widgets/other/select_one.dart'; import 'package:hustle_stay/widgets/other/selection_vault.dart'; import 'package:hustle_stay/widgets/requests/grid_tile_logo.dart'; @@ -109,18 +107,19 @@ class _ComplaintFormState extends State { ); } } else { - if (context.mounted) { - await showComplaintChat( - context, - complaint, - initialMsg: MessageData( - id: DateTime.now().millisecondsSinceEpoch.toString(), - from: currentUser.email!, - createdAt: DateTime.now(), - txt: complaintTemplateMessage(complaint), - ), - ); - } + /// TODO: These lines of code allow us to navigate to the chat screen with a template message for the complaint + // if (context.mounted) { + // await showComplaintChat( + // context, + // complaint, + // initialMsg: MessageData( + // id: DateTime.now().millisecondsSinceEpoch.toString(), + // from: currentUser.email!, + // createdAt: DateTime.now(), + // txt: complaintTemplateMessage(complaint), + // ), + // ); + // } } if (widget.afterSubmit != null) { widget.afterSubmit!(complaint); diff --git a/lib/widgets/requests/request_info.dart b/lib/widgets/requests/request_info.dart index e60971a..efe5bc0 100644 --- a/lib/widgets/requests/request_info.dart +++ b/lib/widgets/requests/request_info.dart @@ -130,7 +130,7 @@ class _RequestInfoState extends State { TextButton.icon( onPressed: () async { final response = await askUser( - context, 'Do you really want to withdraw this request?', + context, 'Do you really want to deactivate this request?', yes: true, no: true); if (response == 'yes') { try { @@ -147,7 +147,7 @@ class _RequestInfoState extends State { } }, icon: const Icon(Icons.close_rounded), - label: const Text('Withdraw'), + label: const Text('Deactivate'), style: TextButton.styleFrom(foregroundColor: Colors.red), ), if (currentUser.type != 'student') diff --git a/lib/widgets/settings/current_user_tile.dart b/lib/widgets/settings/current_user_tile.dart index 9432a2e..dba10fd 100644 --- a/lib/widgets/settings/current_user_tile.dart +++ b/lib/widgets/settings/current_user_tile.dart @@ -4,8 +4,8 @@ import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hustle_stay/models/user/user.dart'; import 'package:hustle_stay/providers/settings.dart'; -import 'package:hustle_stay/screens/auth/edit_profile_screen.dart'; import 'package:hustle_stay/screens/chat/image_preview.dart'; +import 'package:hustle_stay/screens/profile/profile_details_screen.dart'; import 'package:hustle_stay/tools.dart'; class CurrentUserTile extends ConsumerWidget { @@ -74,7 +74,7 @@ class CurrentUserTile extends ConsumerWidget { // ignore: use_build_context_synchronously if (await Navigator.of(context).push( MaterialPageRoute( - builder: (ctx) => EditProfile( + builder: (ctx) => ProfileDetailsScreen( user: currentUser, ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 38ba6a7..5a9c4cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,8 @@ dependencies: flutter_colorpicker: ^1.0.3 syncfusion_flutter_charts: ^22.1.37 rive: ^0.7.16 + firebase_messaging: ^14.6.5 + firebase_analytics: ^10.4.4 dev_dependencies: flutter_test: