diff --git a/.gitignore b/.gitignore index a7b2b06b..fe1246bb 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ app.*.symbols # Obfuscation related app.*.map.json +# Keystore file path when building apk on windows +/android/app/onestop-keystore.jks + # Android Studio will place build artifacts here /android/app/debug /android/app/profile diff --git a/android/app/build.gradle b/android/app/build.gradle index 9e6e40ee..7cbf5298 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -34,6 +34,7 @@ if (project.hasProperty('dart-defines')) { apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" @@ -67,6 +68,7 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName manifestPlaceholders['GMAP_KEY'] = dartEnvironmentVariables.GMAP_KEY + multiDexEnabled true } signingConfigs { @@ -90,5 +92,6 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation "com.android.support:multidex:1.0.3" } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..ab204a0f --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,46 @@ +{ + "project_info": { + "project_number": "755380116666", + "project_id": "onestopiitg-2", + "storage_bucket": "onestopiitg-2.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:755380116666:android:93baf948818388bfe2f683", + "android_client_info": { + "package_name": "com.swciitg.onestop2" + } + }, + "oauth_client": [ + { + "client_id": "755380116666-8eqlpn3rnrp3j4v1unhonm6qldqhek2c.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBsoG-Xp8P2FGth4pE38cUyT2ljSjrAfLE" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "755380116666-8eqlpn3rnrp3j4v1unhonm6qldqhek2c.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "755380116666-7glnointr5aktgrk2rvsonjlfjvuoqpq.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.example.testNotification" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d68f0ebc..89c795cf 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -17,7 +17,9 @@ android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" - android:windowSoftInputMode="adjustResize"> + android:windowSoftInputMode="adjustResize" + android:showWhenLocked="true" + android:turnScreenOn="true"> + + + + diff --git a/android/app/src/main/res/drawable-hdpi/ic_stat_notification_icon.png b/android/app/src/main/res/drawable-hdpi/ic_stat_notification_icon.png new file mode 100644 index 00000000..7df3134f Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_stat_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_stat_notification_icon.png b/android/app/src/main/res/drawable-mdpi/ic_stat_notification_icon.png new file mode 100644 index 00000000..5690b961 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_stat_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_stat_notification_icon.png b/android/app/src/main/res/drawable-xhdpi/ic_stat_notification_icon.png new file mode 100644 index 00000000..8eb46c1d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_stat_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_stat_notification_icon.png b/android/app/src/main/res/drawable-xxhdpi/ic_stat_notification_icon.png new file mode 100644 index 00000000..16159e73 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_stat_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_stat_notification_icon.png b/android/app/src/main/res/drawable-xxxhdpi/ic_stat_notification_icon.png new file mode 100644 index 00000000..b6e72cda Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_stat_notification_icon.png differ diff --git a/android/app/src/main/res/drawable/notification_icon.png b/android/app/src/main/res/drawable/notification_icon.png new file mode 100644 index 00000000..766b161a Binary files /dev/null and b/android/app/src/main/res/drawable/notification_icon.png differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index e71cfdea..4602a4e2 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -1,4 +1,5 @@ - + #001B3E + #76ACFF \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 83ae2200..35e8b225 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,6 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.8.22' + repositories { google() mavenCentral() @@ -8,6 +9,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.13' } } @@ -26,6 +28,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/assets/images/profile_placeholder.png b/assets/images/profile_placeholder.png new file mode 100644 index 00000000..3fe20584 Binary files /dev/null and b/assets/images/profile_placeholder.png differ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 52e10fba..f9797b07 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 797FFB145D937626B7EA4ADA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9822E429D96AFE0F8D730785 /* GoogleService-Info.plist */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -46,7 +47,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9822E429D96AFE0F8D730785 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; C05463DD6012FC0ED5AB6BC0 /* 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 = ""; }; + D800439E29DB5F970022C839 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -98,6 +101,7 @@ 97C146EF1CF9000F007C117D /* Products */, 94BCE952F797F377FEC6B694 /* Pods */, 550921A1AB19070431638329 /* Frameworks */, + 9822E429D96AFE0F8D730785 /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -112,6 +116,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + D800439E29DB5F970022C839 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -192,6 +197,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + 797FFB145D937626B7EA4ADA /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -222,6 +228,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -374,6 +381,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -506,6 +514,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -532,6 +541,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 435706da..7473d1f9 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,6 +1,8 @@ import UIKit import Flutter import GoogleMaps +import flutter_local_notifications + @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { @@ -8,6 +10,12 @@ import GoogleMaps _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate + } + FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in + GeneratedPluginRegistrant.register(with: registry) + } let dartDefinesString = Bundle.main.infoDictionary!["DART_DEFINES"] as! String var dartDefinesDictionary = [String:String]() for definedValue in dartDefinesString.components(separatedBy: ",") { diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..4194fa6c --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 755380116666-if5jvrpuk5hja4qtlqoaa5eil2nlhmaa.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.755380116666-if5jvrpuk5hja4qtlqoaa5eil2nlhmaa + API_KEY + AIzaSyDwfpfZYu7h93Ze4XfU00EdYA-b2Tr39Kk + GCM_SENDER_ID + 755380116666 + PLIST_VERSION + 1 + BUNDLE_ID + com.swciitg.onestop2swc2022 + PROJECT_ID + onestopiitg-2 + STORAGE_BUCKET + onestopiitg-2.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:755380116666:ios:2fde1264d6300380e2f683 + + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 10967e83..d43565b1 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -58,6 +58,13 @@ This app needs access to location to show you the nearest bus stops, ferry ghats, restaurants etc. NSPhotoLibraryUsageDescription This app requires Photo Library access for Lost/Found or Buy/Sell images + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + fetch + remote-notification + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -77,7 +84,5 @@ UIViewControllerBasedStatusBarAppearance - UIApplicationSupportsIndirectInputEvents - diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 00000000..903def2a --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/ios/firebase_app_id_file.json b/ios/firebase_app_id_file.json new file mode 100644 index 00000000..afae3c1b --- /dev/null +++ b/ios/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:755380116666:ios:2fde1264d6300380e2f683", + "FIREBASE_PROJECT_ID": "onestopiitg-2", + "GCM_SENDER_ID": "755380116666" +} \ No newline at end of file diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 00000000..02293bc0 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,69 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyBsoG-Xp8P2FGth4pE38cUyT2ljSjrAfLE', + appId: '1:755380116666:android:93baf948818388bfe2f683', + messagingSenderId: '755380116666', + projectId: 'onestopiitg-2', + storageBucket: 'onestopiitg-2.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyDwfpfZYu7h93Ze4XfU00EdYA-b2Tr39Kk', + appId: '1:755380116666:ios:2fde1264d6300380e2f683', + messagingSenderId: '755380116666', + projectId: 'onestopiitg-2', + storageBucket: 'onestopiitg-2.appspot.com', + iosClientId: '755380116666-if5jvrpuk5hja4qtlqoaa5eil2nlhmaa.apps.googleusercontent.com', + iosBundleId: 'com.swciitg.onestop2swc2022', + ); +} diff --git a/lib/functions/buysell/get_items.dart b/lib/functions/buysell/get_items.dart index 426daa32..8304f443 100644 --- a/lib/functions/buysell/get_items.dart +++ b/lib/functions/buysell/get_items.dart @@ -1,8 +1,8 @@ -import 'package:onestop_dev/services/api.dart'; - -Future getBuySellItems(mail) async { - var list1 = await APIService.getBuyItems(); - var list2 = await APIService.getSellItems(); - var list3 = await APIService.getBnsMyItems(mail); - return [list1, list2, list3]; -} +// import 'package:onestop_dev/services/api.dart'; +// +// Future getBuySellItems(mail) async { +// var list1 = await APIService().getBuyItems(); +// var list2 = await APIService.getSellItems(); +// var list3 = await APIService.getBnsMyItems(mail); +// return [list1, list2, list3]; +// } diff --git a/lib/functions/food/get_day.dart b/lib/functions/food/get_day.dart index 141fd3ee..b38e2be8 100644 --- a/lib/functions/food/get_day.dart +++ b/lib/functions/food/get_day.dart @@ -4,3 +4,7 @@ String getFormattedDay() { DateTime now = DateTime.now(); return DateFormat("EEE").format(now); } +String getFormattedDayForMess() { + DateTime now = DateTime.now(); + return DateFormat("EEEE").format(now); +} diff --git a/lib/functions/home/action_button.dart b/lib/functions/home/action_button.dart index 0b7ca7e6..38dbbbb4 100644 --- a/lib/functions/home/action_button.dart +++ b/lib/functions/home/action_button.dart @@ -2,9 +2,11 @@ import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; import 'package:onestop_dev/functions/timetable/show_dialog.dart'; import 'package:onestop_dev/globals/my_colors.dart'; +import 'package:onestop_dev/stores/login_store.dart'; +import 'package:provider/provider.dart'; Widget homeActionButton(BuildContext context, int index) { - return (index == 3) + return (index == 3 && !LoginStore.isGuest) ? FloatingActionButton( backgroundColor: lBlue2, shape: diff --git a/lib/functions/notifications/get_notifications.dart b/lib/functions/notifications/get_notifications.dart new file mode 100644 index 00000000..90d3caf6 --- /dev/null +++ b/lib/functions/notifications/get_notifications.dart @@ -0,0 +1,27 @@ +import 'dart:convert'; + +import 'package:onestop_dev/pages/notifications/notifications.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +Future> getSavedNotifications(bool changeReadStatus) async { + List n = []; + List newNotifList = []; + n.clear(); + final SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.reload(); + List result = prefs.getStringList('notifications')!; + for (String r in result) { + Map notifData = jsonDecode(r); + print("Notif Data = $notifData"); + n.add(NotifsModel(notifData['header'], notifData['body'], + notifData['read'], notifData['category'], DateTime.parse(notifData['time']), notifData['messageId'])); + if (changeReadStatus) { + // Set Read Recipient to True and then save to prefs + notifData['read'] = true; + } + newNotifList.add(jsonEncode(notifData)); + } + + prefs.setStringList('notifications', newNotifList); + return n.reversed.toList(); +} diff --git a/lib/functions/travel/has_left.dart b/lib/functions/travel/has_left.dart index d5e96dc0..68a94c81 100644 --- a/lib/functions/travel/has_left.dart +++ b/lib/functions/travel/has_left.dart @@ -1,44 +1,46 @@ -import 'package:intl/intl.dart'; - -bool hasLeft(String inputTime) { - var currentTime = DateTime.now(); - List currentHour = - DateFormat.j().format(currentTime).toString().split(' '); - List inputHour = inputTime.split(' '); - - //Checking if both AM or both PM - if (inputHour[1] == currentHour[1]) { - List hm = inputHour[0].split(':'); - int a = int.parse(hm[0]); - int b = int.parse(currentHour[0]); - - if (a == 12) { - a = 0; - } - if (b == 12) { - b = 0; - } - - //Checking if both have same hour - if (a > b) { - return false; - } else if (a < b) { - return true; - } else { - //Checking if both have same minute - a = int.parse(hm[1]); - b = int.parse(DateFormat.m().format(currentTime)); - if (a > b) { - return false; - } else { - return true; - } - } - } else { - if (inputHour[1] == 'AM') { - return true; - } else { - return false; - } - } +bool hasLeft(DateTime s) { + DateTime x = DateTime.now(); + return x.isBefore(s); } +// bool hasLeft(String inputTime) { +// var currentTime = DateTime.now(); +// List currentHour = +// DateFormat.j().format(currentTime).toString().split(' '); +// List inputHour = inputTime.split(' '); +// +// //Checking if both AM or both PM +// if (inputHour[1] == currentHour[1]) { +// List hm = inputHour[0].split(':'); +// int a = int.parse(hm[0]); +// int b = int.parse(currentHour[0]); +// +// if (a == 12) { +// a = 0; +// } +// if (b == 12) { +// b = 0; +// } +// +// //Checking if both have same hour +// if (a > b) { +// return false; +// } else if (a < b) { +// return true; +// } else { +// //Checking if both have same minute +// a = int.parse(hm[1]); +// b = int.parse(DateFormat.m().format(currentTime)); +// if (a > b) { +// return false; +// } else { +// return true; +// } +// } +// } else { +// if (inputHour[1] == 'AM') { +// return true; +// } else { +// return false; +// } +// } +// } diff --git a/lib/functions/travel/next_time.dart b/lib/functions/travel/next_time.dart index f9d7784b..167b869d 100644 --- a/lib/functions/travel/next_time.dart +++ b/lib/functions/travel/next_time.dart @@ -1,23 +1,32 @@ import 'package:onestop_dev/functions/travel/has_left.dart'; - -String nextTime(List timings, {String firstTime = ''}) { - String answer = "Nothing"; - for (String time in timings) { +String nextTime(List timings, {String firstTime = ''}) { + DateTime answer = DateTime.now(); + bool changed = false; + for (var time in timings) { if (!hasLeft(time)) { answer = time; + changed = true; break; } } - if (answer == "Nothing") { + + if (!changed) { if (firstTime == '') { answer = timings[0]; } else { - answer = firstTime; + answer = DateTime.parse(firstTime); } } - return answer; + String a= formatTime(answer); + return a; +} +String formatTime(DateTime dateTime) { + var hour = dateTime.hour; + hour=hour>12?hour-12:hour; + final minute = dateTime.minute.toString().padLeft(2, '0'); + final period = dateTime.hour < 12 ? 'AM' : 'PM'; + return '$hour:$minute $period'; } - int parseTime(String time) { var components = time.split(RegExp('[: ]')); if (components.length != 3) { @@ -41,3 +50,46 @@ int parseTime(String time) { return hours * 100 + minutes; } + +// +// String nextTime(List timings, {String firstTime = ''}) { +// String answer = "Nothing"; +// for (String time in timings) { +// if (!hasLeft(time)) { +// answer = time; +// break; +// } +// } +// if (answer == "Nothing") { +// if (firstTime == '') { +// answer = timings[0]; +// } else { +// answer = firstTime; +// } +// } +// return answer; +// } +// +// int parseTime(String time) { +// var components = time.split(RegExp('[: ]')); +// if (components.length != 3) { +// throw FormatException('Time not in the expected format: $time'); +// } +// var hours = int.parse(components[0]); +// var minutes = int.parse(components[1]); +// var period = components[2].toUpperCase(); +// +// if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) { +// throw FormatException('Time not in the expected format: $time'); +// } +// +// if (hours == 12) { +// hours = 0; +// } +// +// if (period == 'PM') { +// hours += 12; +// } +// +// return hours * 100 + minutes; +// } diff --git a/lib/functions/utility/auth_user_helper.dart b/lib/functions/utility/auth_user_helper.dart new file mode 100644 index 00000000..11044e9d --- /dev/null +++ b/lib/functions/utility/auth_user_helper.dart @@ -0,0 +1,24 @@ +import 'package:onestop_dev/globals/database_strings.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class AuthUserHelpers{ + static Future getAccessToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(BackendHelper.accesstoken) ?? " "; + } + + static Future setAccessToken(String value) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString(BackendHelper.accesstoken, value); + } + + static Future getRefreshToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(BackendHelper.refreshtoken) ?? " "; + } + + static Future setRefreshToken(String value) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString(BackendHelper.refreshtoken, value); + } +} \ No newline at end of file diff --git a/lib/functions/utility/check_last_updated.dart b/lib/functions/utility/check_last_updated.dart index f31677d6..46de44d6 100644 --- a/lib/functions/utility/check_last_updated.dart +++ b/lib/functions/utility/check_last_updated.dart @@ -1,13 +1,15 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:onestop_dev/globals/database_strings.dart'; import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:onestop_dev/services/local_storage.dart'; +import 'package:shared_preferences/shared_preferences.dart'; Map> recordNames = { - "food": [DatabaseRecords.restaurant], - "travel": [DatabaseRecords.busTimings, DatabaseRecords.ferryTimings], - "menu": [DatabaseRecords.messMenu], + "foodOutlet": [DatabaseRecords.restaurant], + "timing": [DatabaseRecords.busTimings, DatabaseRecords.ferryTimings], + "messMenu": [DatabaseRecords.messMenu], "contact": [DatabaseRecords.contacts] }; @@ -15,11 +17,12 @@ Future checkLastUpdated() async { Map? lastUpdated = await DataProvider.getLastUpdated(); try { - Map last = await APIService.getLastUpdated(); + Map last = await APIService().getLastUpdated(); if (lastUpdated == null) { await LocalStorage.instance.deleteAllRecord(); - await LocalStorage.instance.storeData([last], DatabaseRecords.lastUpdated); + await LocalStorage.instance + .storeData([last], DatabaseRecords.lastUpdated); return true; } for (var key in lastUpdated.keys) { diff --git a/lib/functions/utility/pick_file.dart b/lib/functions/utility/pick_file.dart index 4c269817..fee03e94 100644 --- a/lib/functions/utility/pick_file.dart +++ b/lib/functions/utility/pick_file.dart @@ -18,7 +18,7 @@ Future uploadFile( if (result != null) { File file = File(result.files.single.path!); uploadCallback(); - String? responseFilename = await APIService.uploadFileToServer(file); + String? responseFilename = await APIService().uploadFileToServer(file); if (responseFilename == null) { showSnackBar("There was an error uploading your file"); } diff --git a/lib/functions/utility/show_snackbar.dart b/lib/functions/utility/show_snackbar.dart index b21e4505..24dd8795 100644 --- a/lib/functions/utility/show_snackbar.dart +++ b/lib/functions/utility/show_snackbar.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:dio/dio.dart'; import 'package:onestop_dev/main.dart'; void showSnackBar(String message) { @@ -9,3 +10,15 @@ void showSnackBar(String message) { ), ); } + +void showErrorSnackBar(DioException err) { + rootScaffoldMessengerKey.currentState?.showSnackBar(SnackBar( + content: Text( + (err.response != null) + ? err.response!.data['message'] + : "Some error occurred. try again", + style: MyFonts.w500, + ), + duration: const Duration(seconds: 5), + )); +} diff --git a/lib/functions/utility/validator.dart b/lib/functions/utility/validator.dart new file mode 100644 index 00000000..d10481f1 --- /dev/null +++ b/lib/functions/utility/validator.dart @@ -0,0 +1,7 @@ +String? validatefield(String? value) { + + if (value == null || value.isEmpty) { + return 'Field cannot be empty'; + } + return null; +} \ No newline at end of file diff --git a/lib/globals/database_strings.dart b/lib/globals/database_strings.dart index e7ee39c2..b7407ef5 100644 --- a/lib/globals/database_strings.dart +++ b/lib/globals/database_strings.dart @@ -7,4 +7,10 @@ abstract class DatabaseRecords { static const messMenu = "MessMenu"; static const ferryTimings = "FerryTimings"; static const busTimings = "BusTimings"; +} + +class BackendHelper { + static const refreshtoken = "refreshToken"; + static const accesstoken = "accessToken"; + static const authorization = "authorization"; } \ No newline at end of file diff --git a/lib/globals/endpoints.dart b/lib/globals/endpoints.dart new file mode 100644 index 00000000..92040a7c --- /dev/null +++ b/lib/globals/endpoints.dart @@ -0,0 +1,43 @@ +import 'package:onestop_dev/globals/database_strings.dart'; + +import '../functions/utility/auth_user_helper.dart'; + +class Endpoints { + static const baseUrl = String.fromEnvironment('SERVER-URL'); + static const String restaurantURL = "/getAllOutlets"; + static const String lastUpdatedURL = "/lastDataUpdate"; + static const String contactURL = "/getContacts"; + static const String timetableURL = "https://swc.iitg.ac.in/smartTimetable/get-my-courses"; + static const String ferryURL = '/ferryTimings'; + static const String busURL = '/busTimings'; + static const String busStops = '/busstops'; + static const String messURL = "/hostelsMessMenu"; + static const String buyURL = '/buy'; + static const String sellURL = '/sell'; + static const String buyPath = '/buyPage'; + static const String sellPath = '/sellPage'; + static const String bnsMyAdsURL = '/bns/myads'; + static const String lnfMyAdsURL = '/lnf/myads'; + static const String deleteBuyURL = "/buy/remove"; + static const String deleteSellURL = "/sell/remove"; + static const String deleteLostURL = "/lost/remove"; + static const String deleteFoundURL = "/found/remove"; + static const String lostURL = '/lost'; + static const String lostPath = '/lostPage'; + static const String foundPath = '/foundPage'; + static const String foundURL = '/found'; + static const String claimItemURL = "/found/claim"; + static const String newsURL = "/news"; + static const String githubIssueToken = String.fromEnvironment('GITHUB_ISSUE_TOKEN'); + static const apiSecurityKey = String.fromEnvironment('SECURITY-KEY'); + static const feedback = 'https://api.github.com/repos/swciitg/onestop_flutter/issues'; + static const String upspPost = '/upsp/submit-request'; + static const String uploadFileUPSP = "/upsp/file-upload"; + static const String guestLogin = "/user/guest/login"; + static const String userProfile = "/user"; + static const String userDeviceTokens = "/user/device-tokens"; + //static const String userLogout = "/user/logout"; + static getHeader() { + return {'Content-Type': 'application/json', 'security-key': Endpoints.apiSecurityKey}; + } +} diff --git a/lib/globals/my_colors.dart b/lib/globals/my_colors.dart index 2d5e6c76..1e5d6c90 100644 --- a/lib/globals/my_colors.dart +++ b/lib/globals/my_colors.dart @@ -42,3 +42,6 @@ const Color kGrey14 = Color.fromRGBO(41, 45, 53, 1); const Color kGreen = Color.fromRGBO(124, 198, 154, 1); const Color kBadgeColor = Color.fromRGBO(255, 201, 7, 1); const Color kTimetableDisabled = Color.fromRGBO(120, 120, 120, 0.16); +const Color kfocusColor = Color.fromRGBO(94, 94, 94, 1); +const Color kdatePickerSurfaceColor = Color.fromRGBO(43, 62, 92, 1); +const Color kGreenDisabled = Color.fromRGBO(124, 198, 154, 0.5); \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index e1ce8cec..c559ca29 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,24 +1,36 @@ // ignore_for_file: unused_import - +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:onestop_dev/functions/utility/check_last_updated.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/routes.dart'; +import 'package:onestop_dev/services/api.dart'; +import 'package:onestop_dev/services/notifications_provider.dart'; import 'package:onestop_dev/stores/common_store.dart'; import 'package:onestop_dev/stores/login_store.dart'; import 'package:onestop_dev/stores/mapbox_store.dart'; import 'package:onestop_dev/stores/restaurant_store.dart'; -import 'package:onestop_dev/stores/timetable_store.dart'; import 'package:provider/provider.dart'; +import './services/api.dart'; +import 'firebase_options.dart'; + +import 'firebase_options.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(options:DefaultFirebaseOptions.currentPlatform); SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top]); await checkLastUpdated(); + await checkForNotifications(); + final fcmToken = await FirebaseMessaging.instance.getToken(); // ask for notification permission + print("FCM Token is $fcmToken"); + // await APIService.createUser(fcmToken ?? ''); + FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); runApp(const MyApp()); } @@ -30,8 +42,8 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { + print("IN MY APP"); debugInvertOversizedImages = true; - return MultiProvider( providers: [ Provider( @@ -54,7 +66,7 @@ class MyApp extends StatelessWidget { scaffoldBackgroundColor: kBackground, splashColor: Colors.transparent), title: 'OneStop 2.0', - routes: routes, + routes: routes ), ); } diff --git a/lib/models/contacts/contact_model.dart b/lib/models/contacts/contact_model.dart index aa71aac7..537b665d 100644 --- a/lib/models/contacts/contact_model.dart +++ b/lib/models/contacts/contact_model.dart @@ -6,15 +6,13 @@ part 'contact_model.g.dart'; @JsonSerializable(explicitToJson: true) class ContactModel { @JsonKey(defaultValue: "Untitled") - late String name; + late String sectionName; @JsonKey(defaultValue: []) late List contacts; - @JsonKey(defaultValue: "") - late String group; //Constructor ContactModel( - {required this.name, required this.contacts, required this.group}); + {required this.sectionName, required this.contacts}); factory ContactModel.fromJson(Map json) => _$ContactModelFromJson(json); @@ -22,7 +20,7 @@ class ContactModel { Map toJson() => _$ContactModelToJson(this); //This constructor also does the work of initialising the variables // ContactModel.fromJson(Map json) { - // name = json['name']; + // sectionName = json['sectionName']; // parent = 'Campus'; // contacts = []; // List.from(json['contacts']).forEach((element) { diff --git a/lib/models/contacts/contact_model.g.dart b/lib/models/contacts/contact_model.g.dart index 5e910cba..708d4bf1 100644 --- a/lib/models/contacts/contact_model.g.dart +++ b/lib/models/contacts/contact_model.g.dart @@ -7,18 +7,16 @@ part of 'contact_model.dart'; // ************************************************************************** ContactModel _$ContactModelFromJson(Map json) => ContactModel( - name: json['name'] as String? ?? 'Untitled', + sectionName: json['sectionName'] as String? ?? 'Untitled', contacts: (json['contacts'] as List?) ?.map((e) => ContactDetailsModel.fromJson(e as Map)) .toList() ?? [], - group: json['group'] as String? ?? '', ); Map _$ContactModelToJson(ContactModel instance) => { - 'name': instance.name, + 'sectionName': instance.sectionName, 'contacts': instance.contacts.map((e) => e.toJson()).toList(), - 'group': instance.group, }; diff --git a/lib/models/food/dish_model.dart b/lib/models/food/dish_model.dart index b1d4ae82..b8cae8ca 100644 --- a/lib/models/food/dish_model.dart +++ b/lib/models/food/dish_model.dart @@ -6,28 +6,15 @@ part 'dish_model.g.dart'; @JsonSerializable() class DishModel { @JsonKey(defaultValue: "Unnamed") - late String name; - @JsonKey(defaultValue: false) - late bool veg; - @JsonKey( - defaultValue: " ", - fromJson: ingredientsFromJson, - toJson: ingredientsToJson) - late String ingredients; + late String itemName; @JsonKey(defaultValue: 2) - late int waiting_time; - @JsonKey(defaultValue: 150) late int price; - - String image; + String imageURL; DishModel( - {required this.name, - required this.veg, - required this.ingredients, - required this.waiting_time, + {required this.itemName, required this.price, - this.image = + this.imageURL = "https://d4t7t8y8xqo0t.cloudfront.net/resized/750X436/eazytrendz%2F3070%2Ftrend20210218124824.jpg"}); factory DishModel.fromJson(Map json) => @@ -42,13 +29,4 @@ class DishModel { // waiting_time = json['waiting_time'] ?? "Not Known"; // price = json['price'] ?? "Not Known"; // } -} - -String ingredientsFromJson(List ing) { - return ing.toString(); -} - -List ingredientsToJson(String ing) { - ing = ing.substring(1, ing.length - 1); - return ing.split(',').toList(); -} +} \ No newline at end of file diff --git a/lib/models/food/dish_model.g.dart b/lib/models/food/dish_model.g.dart index 252ae72d..c4047200 100644 --- a/lib/models/food/dish_model.g.dart +++ b/lib/models/food/dish_model.g.dart @@ -7,22 +7,14 @@ part of 'dish_model.dart'; // ************************************************************************** DishModel _$DishModelFromJson(Map json) => DishModel( - name: json['name'] as String? ?? 'Unnamed', - veg: json['veg'] as bool? ?? false, - ingredients: json['ingredients'] == null - ? ' ' - : ingredientsFromJson(json['ingredients'] as List), - waiting_time: json['waiting_time'] as int? ?? 2, - price: json['price'] as int? ?? 150, - image: json['image'] as String? ?? + itemName: json['itemName'] as String? ?? 'Unnamed', + price: json['price'] as int? ?? 2, + imageURL: json['imageURL'] as String? ?? "https://d4t7t8y8xqo0t.cloudfront.net/resized/750X436/eazytrendz%2F3070%2Ftrend20210218124824.jpg", ); Map _$DishModelToJson(DishModel instance) => { - 'name': instance.name, - 'veg': instance.veg, - 'ingredients': ingredientsToJson(instance.ingredients), - 'waiting_time': instance.waiting_time, + 'itemName': instance.itemName, 'price': instance.price, - 'image': instance.image, + 'imageURL': instance.imageURL, }; diff --git a/lib/models/food/mess_menu_model.dart b/lib/models/food/mess_menu_model.dart index 679e0fbb..4e9cfa29 100644 --- a/lib/models/food/mess_menu_model.dart +++ b/lib/models/food/mess_menu_model.dart @@ -1,33 +1,97 @@ import 'package:json_annotation/json_annotation.dart'; part 'mess_menu_model.g.dart'; - @JsonSerializable() -class MessMenuModel { - @JsonKey(defaultValue: "Untitled Hostel") - late String hostel; +class MessMenu { + final String id; + final String hostel; + final Day monday; + final Day tuesday; + final Day wednesday; + final Day thursday; + final Day friday; + final Day saturday; + final Day sunday; + final int v; + + MessMenu({ + required this.id, + required this.hostel, + required this.monday, + required this.tuesday, + required this.wednesday, + required this.thursday, + required this.friday, + required this.saturday, + required this.sunday, + required this.v, + }); + factory MessMenu.fromJson(Map json) => _$MessMenuFromJson(json); - @JsonKey(defaultValue: "Untitled Meal") - late String meal; + Map toJson() => _$MessMenuToJson(this); - @JsonKey(defaultValue: "Untitled Menu") - late String menu; +} +@JsonSerializable() +class Day { + final String id; + final MealType breakfast; + final MealType lunch; + final MealType dinner; - @JsonKey(defaultValue: "Untitled Timing") - late String timing; + Day({ + required this.id, + required this.breakfast, + required this.lunch, + required this.dinner, + }); + factory Day.fromJson(Map json) => _$DayFromJson(json); - @JsonKey(defaultValue: "Untitled Day") - late String day; + Map toJson() => _$DayToJson(this); +} +@JsonSerializable() +class MealType { + final String id; + final String mealDescription; + final DateTime startTiming; + final DateTime endTiming; - MessMenuModel( - {required this.hostel, - required this.meal, - required this.menu, - required this.day, - required this.timing}); + MealType({ + required this.id, + required this.mealDescription, + required this.startTiming, + required this.endTiming, + }); + factory MealType.fromJson(Map json) => _$MealTypeFromJson(json); - factory MessMenuModel.fromJson(Map json) => - _$MessMenuModelFromJson(json); + Map toJson() => _$MealTypeToJson(this); - Map toJson() => _$MessMenuModelToJson(this); } +// @JsonSerializable() +// class MessMenuModel { +// @JsonKey(defaultValue: "Untitled Hostel") +// late String hostel; +// +// @JsonKey(defaultValue: "Untitled Meal") +// late String meal; +// +// @JsonKey(defaultValue: "Untitled Menu") +// late String menu; +// +// @JsonKey(defaultValue: "Untitled Timing") +// late String timing; +// +// @JsonKey(defaultValue: "Untitled Day") +// late String day; +// +// MessMenuModel( +// {required this.hostel, +// required this.meal, +// required this.menu, +// required this.day, +// required this.timing}); +// +// factory MessMenuModel.fromJson(Map json) => +// _$MessMenuModelFromJson(json); +// +// Map toJson() => _$MessMenuModelToJson(this); +//} diff --git a/lib/models/food/mess_menu_model.g.dart b/lib/models/food/mess_menu_model.g.dart index f1177fa0..ecc92e23 100644 --- a/lib/models/food/mess_menu_model.g.dart +++ b/lib/models/food/mess_menu_model.g.dart @@ -6,20 +6,56 @@ part of 'mess_menu_model.dart'; // JsonSerializableGenerator // ************************************************************************** -MessMenuModel _$MessMenuModelFromJson(Map json) => - MessMenuModel( - hostel: json['hostel'] as String? ?? 'Untitled Hostel', - meal: json['meal'] as String? ?? 'Untitled Meal', - menu: json['menu'] as String? ?? 'Untitled Menu', - day: json['day'] as String? ?? 'Untitled Day', - timing: json['timing'] as String? ?? 'Untitled Timing', +MessMenu _$MessMenuFromJson(Map json) => MessMenu( + id: json['id'] as String, + hostel: json['hostel'] as String, + monday: Day.fromJson(json['monday'] as Map), + tuesday: Day.fromJson(json['tuesday'] as Map), + wednesday: Day.fromJson(json['wednesday'] as Map), + thursday: Day.fromJson(json['thursday'] as Map), + friday: Day.fromJson(json['friday'] as Map), + saturday: Day.fromJson(json['saturday'] as Map), + sunday: Day.fromJson(json['sunday'] as Map), + v: json['v'] as int, ); -Map _$MessMenuModelToJson(MessMenuModel instance) => - { +Map _$MessMenuToJson(MessMenu instance) => { + 'id': instance.id, 'hostel': instance.hostel, - 'meal': instance.meal, - 'menu': instance.menu, - 'timing': instance.timing, - 'day': instance.day, + 'monday': instance.monday, + 'tuesday': instance.tuesday, + 'wednesday': instance.wednesday, + 'thursday': instance.thursday, + 'friday': instance.friday, + 'saturday': instance.saturday, + 'sunday': instance.sunday, + 'v': instance.v, + }; + +Day _$DayFromJson(Map json) => Day( + id: json['id'] as String, + breakfast: MealType.fromJson(json['breakfast'] as Map), + lunch: MealType.fromJson(json['lunch'] as Map), + dinner: MealType.fromJson(json['dinner'] as Map), + ); + +Map _$DayToJson(Day instance) => { + 'id': instance.id, + 'breakfast': instance.breakfast, + 'lunch': instance.lunch, + 'dinner': instance.dinner, + }; + +MealType _$MealTypeFromJson(Map json) => MealType( + id: json['id'] as String, + mealDescription: json['mealDescription'] as String, + startTiming: DateTime.parse(json['startTiming'] as String), + endTiming: DateTime.parse(json['endTiming'] as String), + ); + +Map _$MealTypeToJson(MealType instance) => { + 'id': instance.id, + 'mealDescription': instance.mealDescription, + 'startTiming': instance.startTiming.toIso8601String(), + 'endTiming': instance.endTiming.toIso8601String(), }; diff --git a/lib/models/food/restaurant_model.dart b/lib/models/food/restaurant_model.dart index e2869697..70f53e1c 100644 --- a/lib/models/food/restaurant_model.dart +++ b/lib/models/food/restaurant_model.dart @@ -8,19 +8,19 @@ part 'restaurant_model.g.dart'; @JsonSerializable(explicitToJson: true) class RestaurantModel { @JsonKey(defaultValue: "Untitled Restaurant") - late String name; + late String outletName; @JsonKey(defaultValue: " ") late String caption; @JsonKey(defaultValue: "10:00 PM") - late String closing_time; + late String closingTime; - @JsonKey(defaultValue: "2 hrs") - late String waiting_time; + @JsonKey(defaultValue: "IIT Guwahati") + late String location; @JsonKey(defaultValue: " ", fromJson: fromJsonPhone, toJson: toJsonPhone) - late String phone_number; + late String phoneNumber; @JsonKey(defaultValue: 26.19247153449412) late double latitude; @@ -28,29 +28,25 @@ class RestaurantModel { @JsonKey(defaultValue: 91.6993500129393) late double longitude; - @JsonKey(defaultValue: " ") - late String address; - @JsonKey(defaultValue: []) late List tags; @JsonKey(defaultValue: []) late List menu; - @JsonKey(name: "imageURL") - late String image; + @JsonKey(defaultValue: "https://dw7n6pv5zdng0.cloudfront.net/modules/0001/04/thumb_3251_modules_big.jpeg") + late String imageURL; RestaurantModel( - {required this.name, + {required this.outletName, required this.caption, - required this.closing_time, - required this.waiting_time, - required this.phone_number, + required this.closingTime, + required this.phoneNumber, required this.latitude, required this.longitude, - required this.address, + required this.location, required this.tags, - required this.image}); + required this.imageURL}); // RestaurantModel.fromJson(Map json) { // name = json['name'] ?? "Unnamed";= "https://live.staticflickr.com/3281/5813689894_a558bb341f_b.jpg" diff --git a/lib/models/food/restaurant_model.g.dart b/lib/models/food/restaurant_model.g.dart index fded6ec6..51c0f233 100644 --- a/lib/models/food/restaurant_model.g.dart +++ b/lib/models/food/restaurant_model.g.dart @@ -8,20 +8,20 @@ part of 'restaurant_model.dart'; RestaurantModel _$RestaurantModelFromJson(Map json) => RestaurantModel( - name: json['name'] as String? ?? 'Untitled Restaurant', + outletName: json['outletName'] as String? ?? 'Untitled Restaurant', caption: json['caption'] as String? ?? ' ', - closing_time: json['closing_time'] as String? ?? '10:00 PM', - waiting_time: json['waiting_time'] as String? ?? '2 hrs', - phone_number: json['phone_number'] == null + closingTime: json['closingTime'] as String? ?? '10:00 PM', + phoneNumber: json['phoneNumber'] == null ? ' ' - : fromJsonPhone(json['phone_number'] as int), + : fromJsonPhone(json['phoneNumber'] as int), latitude: (json['latitude'] as num?)?.toDouble() ?? 26.19247153449412, longitude: (json['longitude'] as num?)?.toDouble() ?? 91.6993500129393, - address: json['address'] as String? ?? ' ', + location: json['location'] as String? ?? 'IIT Guwahati', tags: (json['tags'] as List?)?.map((e) => e as String).toList() ?? [], - image: json['imageURL'] as String, + imageURL: json['imageURL'] as String? ?? + 'https://dw7n6pv5zdng0.cloudfront.net/modules/0001/04/thumb_3251_modules_big.jpeg', )..menu = (json['menu'] as List?) ?.map((e) => DishModel.fromJson(e as Map)) .toList() ?? @@ -29,15 +29,14 @@ RestaurantModel _$RestaurantModelFromJson(Map json) => Map _$RestaurantModelToJson(RestaurantModel instance) => { - 'name': instance.name, + 'outletName': instance.outletName, 'caption': instance.caption, - 'closing_time': instance.closing_time, - 'waiting_time': instance.waiting_time, - 'phone_number': toJsonPhone(instance.phone_number), + 'closingTime': instance.closingTime, + 'location': instance.location, + 'phoneNumber': toJsonPhone(instance.phoneNumber), 'latitude': instance.latitude, 'longitude': instance.longitude, - 'address': instance.address, 'tags': instance.tags, 'menu': instance.menu.map((e) => e.toJson()).toList(), - 'imageURL': instance.image, + 'imageURL': instance.imageURL, }; diff --git a/lib/models/lostfound/lost_model.g.dart b/lib/models/lostfound/lost_model.g.dart index 068124b9..57159075 100644 --- a/lib/models/lostfound/lost_model.g.dart +++ b/lib/models/lostfound/lost_model.g.dart @@ -14,8 +14,8 @@ LostModel _$LostModelFromJson(Map json) => LostModel( email: json['email'] as String, compressedImageURL: json['compressedImageURL'] as String, date: DateTime.parse(json['date'] as String), - phonenumber: json['phonenumber'] as String, id: json['_id'] as String, + phonenumber: json['phonenumber'] as String, ); Map _$LostModelToJson(LostModel instance) => { diff --git a/lib/models/profile/profile_model.dart b/lib/models/profile/profile_model.dart new file mode 100644 index 00000000..47bcbc4f --- /dev/null +++ b/lib/models/profile/profile_model.dart @@ -0,0 +1,38 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'profile_model.g.dart'; + +@JsonSerializable() +class ProfileModel { + final String name; + final String rollNo; + final String outlookEmail; + final String? altEmail; + final int? phoneNumber; + final int? emergencyPhoneNumber; + final String? gender; + final String? roomNo; + final String? homeAddress; + final String? dob; + final String? hostel; + final String? linkedin; + final String? image; + ProfileModel( + {required this.name, + required this.rollNo, + required this.outlookEmail, + this.altEmail, + this.phoneNumber, + this.emergencyPhoneNumber, + this.gender, + this.roomNo, + this.homeAddress, + this.dob, + this.hostel, + this.linkedin, + this.image}); + + factory ProfileModel.fromJson(Map map) => + _$ProfileModelFromJson(map); + + Map toJson() => _$ProfileModelToJson(this); +} diff --git a/lib/models/profile/profile_model.g.dart b/lib/models/profile/profile_model.g.dart new file mode 100644 index 00000000..acd57101 --- /dev/null +++ b/lib/models/profile/profile_model.g.dart @@ -0,0 +1,40 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'profile_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ProfileModel _$ProfileModelFromJson(Map json) => ProfileModel( + name: json['name'] as String, + rollNo: json['rollNo'] as String, + outlookEmail: json['outlookEmail'] as String, + altEmail: json['altEmail'] as String?, + phoneNumber: json['phoneNumber'] as int?, + emergencyPhoneNumber: json['emergencyPhoneNumber'] as int?, + gender: json['gender'] as String?, + roomNo: json['roomNo'] as String?, + homeAddress: json['homeAddress'] as String?, + dob: json['dob'] as String?, + hostel: json['hostel'] as String?, + linkedin: json['linkedin'] as String?, + image: json['image'] as String?, + ); + +Map _$ProfileModelToJson(ProfileModel instance) => + { + 'name': instance.name, + 'rollNo': instance.rollNo, + 'outlookEmail': instance.outlookEmail, + 'altEmail': instance.altEmail, + 'phoneNumber': instance.phoneNumber, + 'emergencyPhoneNumber': instance.emergencyPhoneNumber, + 'gender': instance.gender, + 'roomNo': instance.roomNo, + 'homeAddress': instance.homeAddress, + 'dob': instance.dob, + 'hostel': instance.hostel, + 'linkedin': instance.linkedin, + 'image': instance.image, + }; diff --git a/lib/models/travel/day_type_model.dart b/lib/models/travel/day_type_model.dart new file mode 100644 index 00000000..ca40f4af --- /dev/null +++ b/lib/models/travel/day_type_model.dart @@ -0,0 +1,21 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:json_annotation/json_annotation.dart'; + +part 'day_type_model.g.dart'; + +@JsonSerializable() +class DayType { + final List fromCampus; + final List toCampus; + const DayType( + { + required this.fromCampus, + required this.toCampus, + } + ); + factory DayType.fromJson(Map json) => + _$DayTypeFromJson(json); + + Map toJson() => _$DayTypeToJson(this); +} diff --git a/lib/models/travel/day_type_model.g.dart b/lib/models/travel/day_type_model.g.dart new file mode 100644 index 00000000..35e7fc69 --- /dev/null +++ b/lib/models/travel/day_type_model.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'day_type_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +DayType _$DayTypeFromJson(Map json) => DayType( + fromCampus: (json['fromCampus'] as List) + .map((e) => DateTime.parse(e as String)) + .toList(), + toCampus: (json['toCampus'] as List) + .map((e) => DateTime.parse(e as String)) + .toList(), + ); + +Map _$DayTypeToJson(DayType instance) => { + 'fromCampus': + instance.fromCampus.map((e) => e.toIso8601String()).toList(), + 'toCampus': instance.toCampus.map((e) => e.toIso8601String()).toList(), + }; diff --git a/lib/models/travel/ferry_data_model.dart b/lib/models/travel/ferry_data_model.dart deleted file mode 100644 index 31e49b5d..00000000 --- a/lib/models/travel/ferry_data_model.dart +++ /dev/null @@ -1,26 +0,0 @@ -// ignore_for_file: non_constant_identifier_names - -import 'package:json_annotation/json_annotation.dart'; - -part 'ferry_data_model.g.dart'; - -@JsonSerializable() -class FerryTimeData { - final String name; - final List MonToFri_GuwahatiToNorthGuwahati; - final List MonToFri_NorthGuwahatiToGuwahati; - final List Sunday_GuwahatiToNorthGuwahati; - final List Sunday_NorthGuwahatiToGuwahati; - - FerryTimeData( - this.name, - this.MonToFri_GuwahatiToNorthGuwahati, - this.MonToFri_NorthGuwahatiToGuwahati, - this.Sunday_GuwahatiToNorthGuwahati, - this.Sunday_NorthGuwahatiToGuwahati); - - factory FerryTimeData.fromJson(Map json) => - _$FerryTimeDataFromJson(json); - - Map toJson() => _$FerryTimeDataToJson(this); -} diff --git a/lib/models/travel/ferry_data_model.g.dart b/lib/models/travel/ferry_data_model.g.dart deleted file mode 100644 index 83b4dfe4..00000000 --- a/lib/models/travel/ferry_data_model.g.dart +++ /dev/null @@ -1,35 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'ferry_data_model.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -FerryTimeData _$FerryTimeDataFromJson(Map json) => - FerryTimeData( - json['name'] as String, - (json['MonToFri_GuwahatiToNorthGuwahati'] as List) - .map((e) => e as String) - .toList(), - (json['MonToFri_NorthGuwahatiToGuwahati'] as List) - .map((e) => e as String) - .toList(), - (json['Sunday_GuwahatiToNorthGuwahati'] as List) - .map((e) => e as String) - .toList(), - (json['Sunday_NorthGuwahatiToGuwahati'] as List) - .map((e) => e as String) - .toList(), - ); - -Map _$FerryTimeDataToJson(FerryTimeData instance) => - { - 'name': instance.name, - 'MonToFri_GuwahatiToNorthGuwahati': - instance.MonToFri_GuwahatiToNorthGuwahati, - 'MonToFri_NorthGuwahatiToGuwahati': - instance.MonToFri_NorthGuwahatiToGuwahati, - 'Sunday_GuwahatiToNorthGuwahati': instance.Sunday_GuwahatiToNorthGuwahati, - 'Sunday_NorthGuwahatiToGuwahati': instance.Sunday_NorthGuwahatiToGuwahati, - }; diff --git a/lib/models/travel/travel_timing_model.dart b/lib/models/travel/travel_timing_model.dart new file mode 100644 index 00000000..84447297 --- /dev/null +++ b/lib/models/travel/travel_timing_model.dart @@ -0,0 +1,30 @@ +import 'package:json_annotation/json_annotation.dart'; + +import './day_type_model.dart'; + +part 'travel_timing_model.g.dart'; + +@JsonSerializable() +class TravelTiming { + @JsonKey(name: '_id') + final String id; + @JsonKey(defaultValue: '') + final String type; + @JsonKey(defaultValue: '') + final String stop; + final DayType weekend; + final DayType weekdays; + + + TravelTiming({ + required this.type, + required this.id, + required this.stop, + required this.weekend, + required this.weekdays, + }); + factory TravelTiming.fromJson(Map json) => + _$TravelTimingFromJson(json); + + Map toJson() => _$TravelTimingToJson(this); +} diff --git a/lib/models/travel/travel_timing_model.g.dart b/lib/models/travel/travel_timing_model.g.dart new file mode 100644 index 00000000..0ec3fcb3 --- /dev/null +++ b/lib/models/travel/travel_timing_model.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'travel_timing_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TravelTiming _$TravelTimingFromJson(Map json) => TravelTiming( + type: json['type'] as String? ?? '', + id: json['_id'] as String, + stop: json['stop'] as String? ?? '', + weekend: DayType.fromJson(json['weekend'] as Map), + weekdays: DayType.fromJson(json['weekdays'] as Map), + ); + +Map _$TravelTimingToJson(TravelTiming instance) => + { + '_id': instance.id, + 'type': instance.type, + 'stop': instance.stop, + 'weekend': instance.weekend, + 'weekdays': instance.weekdays, + }; diff --git a/lib/pages/buy_sell/bns_home.dart b/lib/pages/buy_sell/bns_home.dart index ced85633..10210a9e 100644 --- a/lib/pages/buy_sell/bns_home.dart +++ b/lib/pages/buy_sell/bns_home.dart @@ -14,6 +14,7 @@ import 'package:onestop_dev/widgets/buy_sell/buy_tile.dart'; import 'package:onestop_dev/widgets/buy_sell/item_type_bar.dart'; import 'package:onestop_dev/widgets/lostfound/add_item_button.dart'; import 'package:onestop_dev/widgets/lostfound/ads_tile.dart'; +import 'package:onestop_dev/widgets/ui/guest_restrict.dart'; import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; import 'package:provider/provider.dart'; @@ -35,10 +36,10 @@ class _BuySellHomeState extends State { void initState() { super.initState(); _sellController.addPageRequestListener((pageKey) async { - await listener(_sellController, APIService.getSellPage, pageKey); + await listener(_sellController, APIService().getSellPage, pageKey); }); _buyController.addPageRequestListener((pageKey) async { - await listener(_buyController, APIService.getBuyPage, pageKey); + await listener(_buyController, APIService().getBuyPage, pageKey); }); } @@ -65,6 +66,8 @@ class _BuySellHomeState extends State { @override Widget build(BuildContext context) { var commonStore = context.read(); + + return Observer( builder: (BuildContext context) { return Scaffold( @@ -166,9 +169,10 @@ class _BuySellHomeState extends State { ) else Expanded( - child: FutureBuilder( - future: APIService.getBnsMyItems( - context.read().userData['email'] ?? ""), + child: context.read().isGuestUser ? const GuestRestrictAccess() + : FutureBuilder( + future: APIService().getBnsMyItems( + LoginStore.userData['outlookEmail']!), builder: (context, snapshot) { if (snapshot.hasData) { List models = @@ -199,7 +203,7 @@ class _BuySellHomeState extends State { ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: AddItemButton( + floatingActionButton: context.read().isGuestUser ? Container() : AddItemButton( type: commonStore.bnsIndex, ), ); diff --git a/lib/pages/buy_sell/buy_form.dart b/lib/pages/buy_sell/buy_form.dart index a3da796d..9cae3b5b 100644 --- a/lib/pages/buy_sell/buy_form.dart +++ b/lib/pages/buy_sell/buy_form.dart @@ -67,7 +67,7 @@ class _BuySellFormState extends State { children: [ isLoading ? const LinearProgressIndicator() - : const ProgressBar(blue: 2, grey: 0), + : widget.category == "Found" ? const ProgressBar(blue: 3, grey: 0): const ProgressBar(blue: 2, grey: 0), Container( margin: const EdgeInsets.only( top: 40, left: 15, right: 5, bottom: 15), @@ -155,22 +155,22 @@ class _BuySellFormState extends State { data['location'] = _price.text.trim(); data['contact'] = _contactNumber.text.trim(); data['image'] = widget.imageString; - data['name'] = context.read().userData["name"]!; - data['email'] = context.read().userData["email"]!; + data['name'] = LoginStore.userData["name"]!; + data['email'] = LoginStore.userData["outlookEmail"]!; data['total_price'] = "${_price.text}-${_price2.text}"; try { if (widget.category == "Sell") { - res = await APIService.postSellData(data); + res = await APIService().postSellData(data); } if (widget.category == "Buy") { - res = await APIService.postBuyData(data); + res = await APIService().postBuyData(data); } if (widget.category == "Lost") { - res = await APIService.postLostData(data); + res = await APIService().postLostData(data); } if (widget.category == "Found") { - res = await APIService.postFoundData(data); + res = await APIService().postFoundData(data); } // ignore: empty_catches } catch (e) { diff --git a/lib/pages/contact/contact.dart b/lib/pages/contact/contact.dart index 01ea0264..5ea38e57 100644 --- a/lib/pages/contact/contact.dart +++ b/lib/pages/contact/contact.dart @@ -154,7 +154,7 @@ class _ContactPageState extends State { }); for (var e in alphabets) { people["$e ADONOTUSE"] = ContactModel( - name: "Random", contacts: [], group: ""); + sectionName: "Random", contacts: []); } return AlphabetScrollView( list: people.keys.map((e) => AlphaModel(e)).toList(), diff --git a/lib/pages/contact/contact_detail.dart b/lib/pages/contact/contact_detail.dart index 0fde93f0..2c60dc89 100644 --- a/lib/pages/contact/contact_detail.dart +++ b/lib/pages/contact/contact_detail.dart @@ -51,18 +51,18 @@ class _ContactDetailsPageState extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( - widget.contact!.name, + widget.contact!.sectionName, style: MyFonts.w600.size(16).setColor(kWhite), ), ), - const Expanded(child: SizedBox()), - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Text( - widget.contact!.group, - style: MyFonts.w400.size(14).setColor(kGrey2), - ), - ) + // const Expanded(child: SizedBox()), + // Padding( + // padding: const EdgeInsets.only(right: 8.0), + // child: Text( + // widget.contact!.group, + // style: MyFonts.w400.size(14).setColor(kGrey2), + // ), + // ) ], ), Row( diff --git a/lib/pages/home/home_tab.dart b/lib/pages/home/home_tab.dart index 1dee8775..83c55aca 100644 --- a/lib/pages/home/home_tab.dart +++ b/lib/pages/home/home_tab.dart @@ -25,8 +25,10 @@ class _HomeTabState extends State { @override void initState() { super.initState(); - context.read().setTimetable( - context.read().userData["rollno"] ?? "190101109"); + if (!LoginStore.isGuest) { + context.read().setTimetable( + LoginStore.userData["rollNo"]!, context); + } } @override @@ -45,10 +47,17 @@ class _HomeTabState extends State { const SizedBox( height: 10, ), - const DateCourse(), - const SizedBox( - height: 10, - ), + LoginStore.isGuest + ? Container() + : const Column( + mainAxisSize: MainAxisSize.min, + children: [ + const DateCourse(), + SizedBox( + height: 10, + ) + ], + ), HomeLinks(title: 'Services', links: serviceLinks), const SizedBox( height: 10, diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 1d9d3c05..45b98795 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -1,12 +1,16 @@ import 'dart:async'; import 'dart:io'; +import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; import 'package:onestop_dev/globals/size_config.dart'; import 'package:onestop_dev/pages/login/welcome.dart'; import 'package:onestop_dev/widgets/login/login_webview.dart'; import 'package:webview_flutter/webview_flutter.dart'; +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; + class LoginPage extends StatefulWidget { static String id = "/login"; @@ -16,7 +20,7 @@ class LoginPage extends StatefulWidget { } class _LoginPageState extends State { - bool loading = false; + // bool loading = false; final Completer _controller = Completer(); @@ -30,12 +34,16 @@ class _LoginPageState extends State { Widget build(BuildContext context) { SizeConfig().init(context); return Scaffold( - body: loading - ? SafeArea(child: LoginWebView(controller: _controller)) - : WelcomePage(setLoading: () { - setState(() { - loading = true; - }); - })); + body: + // loading + // ? + SafeArea(child: LoginWebView(controller: _controller)) + // : WelcomePage(setLoading: () { + // setState(() { + // loading = true; + // }); + // }) + + ); } } diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index e61e7d2e..e509fac6 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -3,35 +3,47 @@ import 'package:onestop_dev/globals/my_spaces.dart'; import 'package:onestop_dev/widgets/login/login_button.dart'; import 'package:onestop_dev/widgets/login/welcome_header.dart'; +import '../../globals/size_config.dart'; + class WelcomePage extends StatelessWidget { - final Function setLoading; - const WelcomePage({Key? key, required this.setLoading}) : super(key: key); + static String id = "/login2"; + // final Function setLoading; + const WelcomePage({Key? key, + // required this.setLoading + }) : super(key: key); @override Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - flex: 4, - child: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/bg_triangle.png'), - fit: BoxFit.fill, - )), - child: const WelcomeHeader(), - ), - ), - Expanded( - flex: 1, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: MySpaces.horizontalScreenPadding), - child: LoginButton(setLoading: setLoading), - ), + SizeConfig().init(context); + return Scaffold( + body: + SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + flex: 4, + child: Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/bg_triangle.png'), + fit: BoxFit.fill, + )), + child: const WelcomeHeader(), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: MySpaces.horizontalScreenPadding + ), + child: const LoginButton(), + ), + ), + ], ), - ], + ), ); } } diff --git a/lib/pages/lost_found/lnf_home.dart b/lib/pages/lost_found/lnf_home.dart index 718cc03f..1a7da6e5 100644 --- a/lib/pages/lost_found/lnf_home.dart +++ b/lib/pages/lost_found/lnf_home.dart @@ -13,6 +13,7 @@ import 'package:onestop_dev/widgets/lostfound/ads_tile.dart'; import 'package:onestop_dev/widgets/lostfound/lost_found_button.dart'; import 'package:onestop_dev/widgets/lostfound/add_item_button.dart'; import 'package:onestop_dev/widgets/lostfound/lost_found_tile.dart'; +import 'package:onestop_dev/widgets/ui/guest_restrict.dart'; import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; import 'package:provider/provider.dart'; @@ -34,10 +35,10 @@ class _LostFoundHomeState extends State { void initState() { super.initState(); _lostController.addPageRequestListener((pageKey) async { - await listener(_lostController, APIService.getLostPage, pageKey); + await listener(_lostController, APIService().getLostPage, pageKey); }); _foundController.addPageRequestListener((pageKey) async { - await listener(_foundController, APIService.getFoundPage, pageKey); + await listener(_foundController, APIService().getFoundPage, pageKey); }); } @@ -64,6 +65,8 @@ class _LostFoundHomeState extends State { @override Widget build(BuildContext context) { var commonStore = context.read(); + + return Observer(builder: (context) { return Scaffold( appBar: AppBar( @@ -169,9 +172,10 @@ class _LostFoundHomeState extends State { ) else Expanded( - child: FutureBuilder( - future: APIService.getLnfMyItems( - context.read().userData['email'] ?? ""), + child: context.read().isGuestUser ? const GuestRestrictAccess() + : FutureBuilder( + future: APIService().getLnfMyItems( + LoginStore.userData['outlookEmail'] ?? ""), builder: (context, snapshot) { if (snapshot.hasData) { List models = snapshot.data! as List; @@ -200,7 +204,7 @@ class _LostFoundHomeState extends State { ], ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: AddItemButton( + floatingActionButton: context.read().isGuestUser ? Container() : AddItemButton( type: commonStore.lnfIndex, ), ); diff --git a/lib/pages/notifications/notifications.dart b/lib/pages/notifications/notifications.dart new file mode 100644 index 00000000..89a98d32 --- /dev/null +++ b/lib/pages/notifications/notifications.dart @@ -0,0 +1,134 @@ +import 'dart:convert'; + +import 'package:fluentui_system_icons/fluentui_system_icons.dart'; +import 'package:flutter/material.dart'; +import 'package:onestop_dev/functions/notifications/get_notifications.dart'; +import 'package:onestop_dev/globals/my_colors.dart'; +import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; +import 'package:onestop_dev/widgets/ui/notification_tile.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class NotifsModel { + String? title; + String? body; + String category; + bool read; + DateTime time; + String messageId; + + NotifsModel( + this.title, + this.body, + this.read, + this.category, + this.time, + this.messageId + ); +} + +class NotificationPage extends StatefulWidget { + static String id = "notifications"; + const NotificationPage({Key? key}) : super(key: key); + + @override + State createState() => _NotificationPageState(); +} + +class _NotificationPageState extends State { + + IconData getIcon(bool readNotif) { + if (!readNotif) { + return FluentIcons.circle_24_filled; + } + return Icons.brightness_1_outlined; + } + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: kAppBarGrey, + actions: [ + ElevatedButton.icon( + onPressed: () async { + final SharedPreferences prefs = + await SharedPreferences.getInstance(); + await prefs.reload(); + prefs.remove('notifications'); + setState(() {}); + }, + icon: const Icon(FluentIcons.delete_12_regular), + label: Text( + 'Clear All', + style: MyFonts.w300, + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, elevation: 0), + ) + ], + leading: IconButton( + onPressed: () { + Navigator.of(context).pop(); + }, + icon: const Icon(FluentIcons.arrow_left_24_regular)), + title: Text( + 'Notifications', + style: MyFonts.w500, + ), + ), + body: FutureBuilder>( + future: getSavedNotifications(true), + builder: (context, snapshot) { + if (snapshot.hasData) { + if (snapshot.data!.isEmpty) { + return Center( + child: Text( + 'No notifications found', + style: MyFonts.w300.setColor(kWhite), + ), + ); + } + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: ListView.builder( + itemCount: snapshot.data!.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: NotificationTile( + notifModel: snapshot.data![index], + ), + ); + }, + ), + ); + } + if (snapshot.connectionState == ConnectionState.waiting) { + return Column( + children: [ + const SizedBox( + height: 10, + ), + Expanded( + child: ListShimmer( + count: 5, + )), + ], + ); + } + return Center( + child: Text( + 'No notifications found', + style: MyFonts.w300.setColor(kWhite), + ), + ); + }), + ); + } +} diff --git a/lib/pages/profile.dart b/lib/pages/profile.dart index bbf3d8fb..3abdfb38 100644 --- a/lib/pages/profile.dart +++ b/lib/pages/profile.dart @@ -42,12 +42,12 @@ class _ProfilePageState extends State { width: MediaQuery.of(context).size.width, ), Text( - "${context.read().userData['name']}", + "${LoginStore.userData['name']}", textAlign: TextAlign.center, style: MyFonts.w800.setColor(kWhite).size(20), ), Text( - '${context.read().userData['rollno']}', + '${LoginStore.userData['rollNo']}', textAlign: TextAlign.center, style: MyFonts.w500.setColor(kWhite).size(20), ), @@ -69,7 +69,7 @@ class _ProfilePageState extends State { // padding: const EdgeInsets.symmetric(horizontal: 16), // child: BarcodeWidget( // barcode: Barcode.code128(), - // data: "${context.read().userData['rollno']}", + // data: "${context.read().userData['rollNo']}", // height: 150, // color: kBlack, // backgroundColor: kWhite, @@ -99,7 +99,9 @@ class _ProfilePageState extends State { '/', (Route route) => false)); }, style: ElevatedButton.styleFrom( - elevation: 0, backgroundColor: kAppBarGrey), + elevation: 0, + backgroundColor: kAppBarGrey, + ), child: Text( 'Log Out', style: MyFonts.w500.setColor(kBlue), diff --git a/lib/pages/profile/edit_profile.dart b/lib/pages/profile/edit_profile.dart new file mode 100644 index 00000000..b0a33360 --- /dev/null +++ b/lib/pages/profile/edit_profile.dart @@ -0,0 +1,515 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:intl/intl.dart'; +import 'package:onestop_dev/globals/database_strings.dart'; +import 'package:onestop_dev/services/api.dart'; +import 'package:onestop_dev/services/local_storage.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../functions/utility/show_snackbar.dart'; +import '../../functions/utility/validator.dart'; +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; +import '../../models/profile/profile_model.dart'; +import '../../stores/login_store.dart'; +import '../../widgets/profile/custom_date_picker.dart'; +import '../../widgets/profile/custom_dropdown.dart'; +import '../../widgets/profile/custom_text_field.dart'; +import 'profile_page.dart'; + +class EditProfile extends StatefulWidget { + final ProfileModel profileModel; + const EditProfile({Key? key, required this.profileModel}) : super(key: key); + + @override + State createState() => _EditProfileState(); +} + +class _EditProfileState extends State { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _outlookEmailController = TextEditingController(); + final TextEditingController _rollController = TextEditingController(); + final TextEditingController _altEmailController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(); + final TextEditingController _emergencyController = TextEditingController(); + final TextEditingController _roomNoController = TextEditingController(); + final TextEditingController _homeAddressController = TextEditingController(); + final TextEditingController _dobController = TextEditingController(); + final TextEditingController _linkedinController = TextEditingController(); + String? hostel; + String? gender; + DateTime? selectedDob; + // String? imageString; + final List genders = ["Male", "Female", "Others"]; + final List hostels = [ + "Kameng", + "Barak", + "Lohit", + "Brahma", + "Disang", + "Manas", + "Dihing", + "Umiam", + "Siang", + "Kapili", + "Dhansiri", + "Subhansiri" + ]; + final _formKey = GlobalKey(); + + @override + void initState() { + super.initState(); + ProfileModel p = widget.profileModel!; + _nameController.text = p.name; + _rollController.text = p.rollNo; + _outlookEmailController.text = p.outlookEmail; + _altEmailController.text = p.altEmail ?? ""; + _phoneController.text = + p.phoneNumber == null ? "" : p.phoneNumber.toString(); + _emergencyController.text = + p.emergencyPhoneNumber == null ? "" : p.emergencyPhoneNumber.toString(); + _roomNoController.text = p.roomNo ?? ""; + _homeAddressController.text = p.homeAddress ?? ""; + _dobController.text = DateFormat('dd-MMM-yyyy') + .format(DateTime.parse(p.dob ?? DateTime.now().toIso8601String())); + _linkedinController.text = p.linkedin ?? ""; + hostel = p.hostel; + gender = p.gender; + selectedDob = p.dob != null ? DateTime.parse(p.dob!) : DateTime.now(); + // imageString = p.image; + } + + @override + Widget build(BuildContext context) { + Widget? counterBuilder(context, + {required currentLength, required isFocused, required maxLength}) { + if (currentLength == 0) { + return null; + } + return Text("$currentLength/$maxLength", + style: MyFonts.w500.size(12).setColor(kWhite)); + } + + Future onFormSubmit() async { + if (!_formKey.currentState!.validate()) { + showSnackBar('Please give all the inputs correctly'); + return; + } else { + DateTime date = + DateTime(selectedDob!.year, selectedDob!.month, selectedDob!.day); + var data = { + 'name': _nameController.text, + 'rollNo': _rollController.text, + 'outlookEmail': _outlookEmailController.text, + 'altEmail': _altEmailController.text, + 'dob': date.toIso8601String(), + 'gender': gender, + 'phoneNumber': _phoneController.text, + 'emergencyPhoneNumber': _emergencyController.text, + 'hostel': hostel, + 'roomNo': _roomNoController.text, + 'homeAddress': _homeAddressController.text, + 'linkedin': _linkedinController.text + }; + print(data); + try { + await APIService().updateUserProfile(data, null); + } catch (e) { + showSnackBar(e.toString()); + return; + } + Map userInfo = await APIService().getUserProfile(); + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('hostel', hostel ?? ""); + await prefs.setString("userInfo", jsonEncode(userInfo)); + await context.read().saveToUserInfo( + prefs); // automatically updates token & other user info + await prefs.setBool("isProfileComplete", true); // profile is complete + await LocalStorage.instance.deleteRecord(DatabaseRecords.timetable); + print("PROFILE COMPLETED"); + Navigator.of(context) + .pushNamedAndRemoveUntil('/', (Route route) => false); + + // Navigator.of(context).pushAndRemoveUntil( + // MaterialPageRoute( + // builder: (context) => Profile( + // profileModel: ProfileModel.fromJson(data), + // )), + // ((route) => false)); + } + } + + return GestureDetector( + onTap: () { + FocusScope.of(context).requestFocus(new FocusNode()); + }, + child: Scaffold( + backgroundColor: kBackground, + appBar: AppBar( + backgroundColor: kAppBarGrey, + iconTheme: const IconThemeData(color: kAppBarGrey), + automaticallyImplyLeading: false, + centerTitle: false, + title: Text( + "Profile Setup", + textAlign: TextAlign.left, + style: MyFonts.w500.size(23).setColor(kWhite), + ), + ), + body: SafeArea( + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'Fields marked with', + style: MyFonts.w500.setColor(kWhite3).size(12)), + TextSpan( + text: ' * ', + style: MyFonts.w500.setColor(kRed).size(12)), + TextSpan( + text: 'are compulsory', + style: MyFonts.w500.setColor(kWhite3).size(12)), + ], + ), + ), + const SizedBox( + height: 24, + ), + // For now image will not be stored + // Center( + // child: Stack(alignment: Alignment.bottomRight, children: [ + // + // ClipRRect( + // borderRadius: BorderRadius.circular(75.0), + // + // child: Image( + // image: imageString==null?const ResizeImage(AssetImage('assets/images/profile_placeholder.png'),width: 150,height: 150): ResizeImage( + // MemoryImage(base64Decode(imageString!)) + // ,width: 150, + // height: 150,), + // fit: BoxFit.fill, + // ) + // ), + // Padding( + // padding: const EdgeInsets.all(8.0), + // child: GestureDetector( + // onTap: () async { + // XFile? xFile; + // await showDialog( + // context: context, + // builder: (BuildContext context) { + // return AlertDialog( + // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(28)), + // backgroundColor: kBlueGrey, + // title: Text( + // "Do you want to change your profile photo?",style: MyFonts.w500.size(16).setColor(kWhite2),), + // content: SingleChildScrollView( + // child: ListBody( + // children: [ + // GestureDetector( + // child: Text("Take Photo",style: MyFonts.w500.size(14).setColor(kWhite),), + // onTap: () async { + // xFile = await ImagePicker().pickImage( + // source: ImageSource.camera); + // if (!mounted) return; + // Navigator.of(context).pop(); + // }, + // ), + // const Padding( + // padding: EdgeInsets.all(8.0)), + // GestureDetector( + // child: Text("Choose Photo",style: MyFonts.w500.size(14).setColor(kWhite),), + // onTap: () async { + // xFile = await ImagePicker().pickImage( + // source: ImageSource.gallery); + // if (!mounted) return; + // Navigator.of(context).pop(); + // }, + // ), + // const Padding( + // padding: EdgeInsets.all(8.0)), + // + // GestureDetector( + // child: Text("Remove Photo",style: MyFonts.w500.size(14).setColor(kRed),), + // onTap: () async { + // setState(() { + // imageString=null; + // }); + // return + // Navigator.of(context).pop(); + // }, + // ), + // ], + // ), + // )); + // }); + // + // if (!mounted) return; + // if (xFile != null) { + // var bytes = File(xFile!.path).readAsBytesSync(); + // var imageSize = (bytes.lengthInBytes / + // (1048576)); // dividing by 1024*1024 + // if (imageSize > 2.5) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text( + // "Maximum image size can be 2.5 MB", + // style: MyFonts.w500, + // ))); + // return; + // } + // setState(() { + // imageString = base64Encode(bytes); + // }); + // return; + // } + // }, + // child: Container( + // height: 30, + // width: 30, + // decoration: const BoxDecoration( + // borderRadius: BorderRadius.all(Radius.circular(75)), + // color: kWhite), + // child: const Icon(Icons.edit_outlined), + // ), + // ), + // ), + // ])), + // const SizedBox( + // height: 24, + // ), + Text('Basic Information', + style: MyFonts.w600.size(16).setColor(kWhite)), + const SizedBox( + height: 18, + ), + Form( + key: _formKey, + child: Column( + children: [ + CustomTextField( + hintText: 'name', + // validator: validatefield, + isNecessary: false, + controller: _nameController, + isEnabled: false, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Roll Number', + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Field cannot be empty'; + } else if (value.length != 9) { + return 'Enter valid roll number'; + } + return null; + }, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + isNecessary: true, + controller: _rollController, + maxLength: 9, + maxLines: 1, + counter: true, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + isEnabled: false, + hintText: 'outlookEmail ID', + // validator: validatefield, + isNecessary: false, + controller: _outlookEmailController, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Alt Email', + validator: validatefield, + isNecessary: true, + controller: _altEmailController, + maxLength: 50, + maxLines: 1, + counter: true, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Phone Number', + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Field cannot be empty'; + } else if (value.length != 10) { + return 'Enter valid 10 digit phone number'; + } + return null; + }, + isNecessary: true, + controller: _phoneController, + inputType: TextInputType.phone, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + maxLength: 10, + maxLines: 1, + counter: true, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Emergency Contact Number', + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Field cannot be empty'; + } else if (value.length != 10) { + return 'Enter valid 10 digit phone number'; + } + return null; + }, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + isNecessary: true, + controller: _emergencyController, + inputType: TextInputType.phone, + maxLength: 10, + maxLines: 1, + counter: true, + ), + const SizedBox( + height: 12, + ), + CustomDropDown( + value: gender, + items: genders, + hintText: 'Your Gender', + onChanged: (g) => gender = g, + validator: validatefield), + const SizedBox( + height: 12, + ), + CustomDropDown( + value: hostel, + items: hostels, + hintText: 'Hostel', + onChanged: (h) => hostel = h, + validator: validatefield, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Date of Birth', + validator: validatefield, + controller: _dobController, + onTap: () async { + FocusScope.of(context).requestFocus(FocusNode()); + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: selectedDob ?? DateTime.now(), + firstDate: DateTime(1990), + //DateTime.now() - not to allow to choose before today. + lastDate: DateTime(2101), + builder: (context, child) => CustomDatePicker( + child: child, + )); + if (pickedDate != null) { + if (!mounted) return; + selectedDob = pickedDate; + String formattedDate = + DateFormat('dd-MMM-yyyy').format(pickedDate); + setState(() { + _dobController.text = + formattedDate; //set output date to TextField value. + }); + } + }, + isNecessary: true, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Hostel room no', + validator: validatefield, + isNecessary: true, + controller: _roomNoController, + maxLength: 5, + maxLines: 1, + counter: true, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'Home Address', + validator: validatefield, + isNecessary: true, + controller: _homeAddressController, + maxLength: 400, + // maxLines: 1, + counter: true, + ), + const SizedBox( + height: 12, + ), + CustomTextField( + hintText: 'LinkedIn Profile', + // validator: validatefield, + isNecessary: false, + controller: _linkedinController, + maxLength: 50, + maxLines: 1, + counter: true, + ), + const SizedBox( + height: 24, + ), + ], + )), + GestureDetector( + onTap: onFormSubmit, + child: Container( + width: double.infinity, + height: 48, + alignment: Alignment.center, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4)), + color: lBlue2), + child: const Text( + 'Submit', + textAlign: TextAlign.center, + ), + ), + ), + const SizedBox( + height: 24, + ), + ], + ), + )), + ), + ), + ); + } +} diff --git a/lib/pages/profile/profile_page.dart b/lib/pages/profile/profile_page.dart new file mode 100644 index 00000000..2ab56a4c --- /dev/null +++ b/lib/pages/profile/profile_page.dart @@ -0,0 +1,176 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; +import '../../models/profile/profile_model.dart'; +import '../../stores/login_store.dart'; +import '../../widgets/profile/data_tile.dart'; +import '../../widgets/profile/feedback.dart'; +import 'edit_profile.dart'; + +class Profile extends StatefulWidget { + final ProfileModel profileModel; + const Profile({super.key, required this.profileModel}); + + @override + State createState() => _ProfileState(); +} + +class _ProfileState extends State { + @override + Widget build(BuildContext context) { + print(widget.profileModel!.toJson()); + return Scaffold( + backgroundColor: kBackground, + appBar: AppBar( + backgroundColor: kAppBarGrey, + iconTheme: const IconThemeData(color: kAppBarGrey), + automaticallyImplyLeading: false, + centerTitle: false, + title: Text( + "Profile", + textAlign: TextAlign.left, + style: MyFonts.w500.size(23).setColor(kWhite), + ), + actions: [ + if (!context.read().isGuestUser) + IconButton( + onPressed: (() { + showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(20), + ), + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + isScrollControlled: true, + builder: (BuildContext context) { + return const FeedBack(); + }); + }), + icon: const Icon( + Icons.bug_report_outlined, + color: kWhite, + )), + IconButton( + onPressed: (() { + context.read().logOut(() => Navigator.of(context) + .pushNamedAndRemoveUntil( + '/', (Route route) => false)); + }), + icon: const Icon( + Icons.logout_outlined, + color: kWhite, + )) + ], + ), + body: SafeArea( + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 12, + ), + // Center( + // child: Stack(alignment: Alignment.bottomRight, children: [ + // ClipRRect( + // borderRadius: BorderRadius.circular(75.0), + // child: Image( + // image: widget.profileModel?.image == null + // ? const ResizeImage( + // AssetImage( + // 'assets/images/profile_placeholder.png'), + // width: 150, + // height: 150) + // : ResizeImage( + // MemoryImage( + // base64Decode(widget.profileModel!.image!)), + // width: 150, + // height: 150, + // ), + // fit: BoxFit.fill, + // )), + // ])), + // const SizedBox( + // height: 24, + // ), + Text('Basic Information', + style: MyFonts.w600.size(16).setColor(kWhite)), + const SizedBox( + height: 6, + ), + DataTile( + title: 'Username', + semiTitle: widget.profileModel.name, + ), + DataTile( + title: 'Roll Number', + semiTitle: widget.profileModel.rollNo, + ), + DataTile( + title: 'Outlook ID', + semiTitle: widget.profileModel.outlookEmail, + ), + DataTile( + title: 'Alt Email', + semiTitle: widget.profileModel.altEmail, + ), + DataTile( + title: 'Contact Number', + semiTitle: widget.profileModel.phoneNumber!=null ? widget.profileModel.phoneNumber.toString() : null, + ), + DataTile( + title: 'Emergency Contact Number', + semiTitle: widget.profileModel.emergencyPhoneNumber!=null ? widget.profileModel.emergencyPhoneNumber.toString() : null, + ), + DataTile( + title: 'Hostel', + semiTitle: widget.profileModel.hostel, + ), + widget.profileModel.dob==null + ? Container() + : DataTile( + title: 'Date of Birth', + semiTitle: DateFormat('dd-MMM-yyyy') + .format(DateTime.parse(widget.profileModel.dob!)), + ), + DataTile( + title: 'LinkedIn Profile', + semiTitle: widget.profileModel.linkedin, + ), + const SizedBox( + height: 24, + ), + ], + ), + )), + ), + floatingActionButton: LoginStore.isGuest ? Container() : GestureDetector( + onTap: (() { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => EditProfile( + profileModel: widget.profileModel, + ))); + }), + child: Container( + width: 48, + height: 48, + alignment: Alignment.center, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(16)), + color: lBlue2), + child: const Icon(Icons.edit_outlined), + ), + ), + ); + } +} diff --git a/lib/pages/quick_links/cab_share.dart b/lib/pages/quick_links/cab_share.dart index 33733419..0ac2437b 100644 --- a/lib/pages/quick_links/cab_share.dart +++ b/lib/pages/quick_links/cab_share.dart @@ -9,10 +9,7 @@ class CabShare extends StatelessWidget { @override Widget build(BuildContext context) { - return CabSharingScreen(userData: { - 'name': context.read().userData["name"]!, - 'email': context.read().userData["email"]!, - 'security-key': const String.fromEnvironment('SECURITY-KEY') - }); + print(LoginStore.userData); + return CabSharingSplashScreen(); } } diff --git a/lib/pages/quick_links/gc_scoreboard.dart b/lib/pages/quick_links/gc_scoreboard.dart index 9d2785c6..27e7aa9c 100644 --- a/lib/pages/quick_links/gc_scoreboard.dart +++ b/lib/pages/quick_links/gc_scoreboard.dart @@ -9,6 +9,6 @@ class Scoreboard extends StatelessWidget { @override Widget build(BuildContext context) { - return GCScoreBoard(userInfo: context.read().userData); + return GCScoreBoard(userInfo: {"name": LoginStore.userData["name"],"rollno": LoginStore.userData["rollNo"],"email" : LoginStore.userData["outlookEmail"]}); } } diff --git a/lib/pages/splash.dart b/lib/pages/splash.dart index 82bcd613..048d075d 100644 --- a/lib/pages/splash.dart +++ b/lib/pages/splash.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:onestop_dev/functions/utility/show_snackbar.dart'; +import 'package:onestop_dev/models/profile/profile_model.dart'; +import 'package:onestop_dev/pages/profile/edit_profile.dart'; import 'package:onestop_dev/stores/login_store.dart'; import 'package:provider/provider.dart'; @@ -18,12 +21,12 @@ class _SplashPageState extends State { Provider.of(context, listen: false) .isAlreadyAuthenticated() .then((result) { - if (result) { + if (result && LoginStore.isProfileComplete){ Navigator.of(context) .pushNamedAndRemoveUntil('/home2', (Route route) => false); } else { Navigator.of(context) - .pushNamedAndRemoveUntil('/login', (Route route) => false); + .pushNamedAndRemoveUntil('/login2', (Route route) => false); } }); } diff --git a/lib/pages/timetable/timetable.dart b/lib/pages/timetable/timetable.dart index 88ffbad3..e9c0c98b 100644 --- a/lib/pages/timetable/timetable.dart +++ b/lib/pages/timetable/timetable.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:onestop_dev/pages/lost_found/lnf_home.dart'; +import 'package:onestop_dev/stores/login_store.dart'; import 'package:onestop_dev/stores/timetable_store.dart'; import 'package:onestop_dev/widgets/timetable/date_slider.dart'; import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; import 'package:provider/provider.dart'; +import 'package:onestop_dev/widgets/ui/guest_restrict.dart'; class TimeTableTab extends StatefulWidget { - static const String id = 'time'; + static const String id = '/time'; const TimeTableTab({Key? key}) : super(key: key); @override State createState() => _TimeTableTabState(); @@ -16,7 +19,7 @@ class _TimeTableTabState extends State { List>>> data1 = []; @override Widget build(BuildContext context) { - return SingleChildScrollView( + return LoginStore.isGuest ? const GuestRestrictAccess() : SingleChildScrollView( child: Column( children: [ const SizedBox( diff --git a/lib/pages/upsp/details_upsp.dart b/lib/pages/upsp/details_upsp.dart index b4d692ee..c754b8c7 100644 --- a/lib/pages/upsp/details_upsp.dart +++ b/lib/pages/upsp/details_upsp.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fluentui_system_icons/fluentui_system_icons.dart'; +import 'package:flutter/services.dart'; import 'package:onestop_dev/functions/utility/show_snackbar.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; @@ -19,9 +20,9 @@ class DetailsUpsp extends StatefulWidget { } class _DetailsUpspState extends State { - String selectedDropdown = 'Kameng'; bool submitted = false; TextEditingController contact = TextEditingController(); + TextEditingController rollNo = TextEditingController(); List hostels = [ "Kameng", "Barak", @@ -41,11 +42,13 @@ class _DetailsUpspState extends State { @override Widget build(BuildContext context) { - var userStore = context.read(); - var userData = userStore.userData; - String email = userData['email']!; + var userData = LoginStore.userData; + String email = userData['outlookEmail']!; String name = userData['name']!; - String roll = userData['rollno']!; + rollNo.text = userData['rollNo']!.toString(); + String selectedDropdown = userData['hostel']!; + contact.text=userData['phoneNumber']!.toString(); + return Scaffold( backgroundColor: kBackground, appBar: AppBar( @@ -89,13 +92,14 @@ class _DetailsUpspState extends State { padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 10), child: TextFormField( - initialValue: roll, + controller: rollNo, validator: (val) { if (val == null || val.isEmpty) { return "Please fill your roll number"; } return null; }, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.number, style: MyFonts.w500.size(16).setColor(kWhite), decoration: InputDecoration( @@ -105,7 +109,6 @@ class _DetailsUpspState extends State { hintText: 'Your Answer', hintStyle: const TextStyle(color: kGrey8), ), - onChanged: (r) => roll = r, ))), ), Padding( @@ -138,6 +141,7 @@ class _DetailsUpspState extends State { return null; }, keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], controller: contact, maxLength: 10, style: MyFonts.w500.size(16).setColor(kWhite), @@ -164,6 +168,7 @@ class _DetailsUpspState extends State { padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 5), child: DropdownButtonFormField( + value: selectedDropdown, validator: (val) { if (val == null) { return "Hostel can not be empty"; @@ -237,26 +242,23 @@ class _DetailsUpspState extends State { data['phone'] = contact.text; data['hostel'] = selectedDropdown; data['name'] = name; - data['roll_number'] = roll; + data['roll_number'] = rollNo.text; data['email'] = email; try { - var response = await APIService.postUPSP(data); + var response = await APIService().postUPSP(data); if (!mounted) return; if (response['success']) { - showSnackBar( - "Your problem has been successfully sent to respective authorities."); + showSnackBar("Your problem has been successfully sent to respective au1thorities."); Navigator.popUntil( context, ModalRoute.withName(HomePage.id)); } else { - showSnackBar( - "Some error occurred. Try again later"); + showSnackBar("Some error occurred. Try again later"); setState(() { submitted = false; }); } } catch (err) { - showSnackBar( - "Please check you internet connection and try again"); + showSnackBar("Please check you internet connection and try again"); setState(() { submitted = false; }); diff --git a/lib/pages/upsp/upsp.dart b/lib/pages/upsp/upsp.dart index ef080a9f..96aefbe1 100644 --- a/lib/pages/upsp/upsp.dart +++ b/lib/pages/upsp/upsp.dart @@ -49,9 +49,8 @@ class _UpspState extends State { @override Widget build(BuildContext context) { - var userStore = context.read(); - var userData = userStore.userData; - String email = userData['email']!; + var userData = LoginStore.userData; + String email = userData['outlookEmail']!; return Theme( data: Theme.of(context).copyWith( @@ -68,7 +67,7 @@ class _UpspState extends State { style: MyFonts.w600.size(16).setColor(kWhite), ), ), - body: userStore.isGuestUser + body: LoginStore.isGuest ? Center( child: Text( 'Please sign in to use this feature', @@ -196,8 +195,7 @@ class _UpspState extends State { GestureDetector( onTap: () { if (problem.value.text.isEmpty) { - showSnackBar( - "Problem description cannot be empty"); + showSnackBar("Problem description cannot be empty"); } else { Map data = { 'problem': problem.text, diff --git a/lib/routes.dart b/lib/routes.dart index ba1f63bd..e5fbf284 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,3 +1,5 @@ +import 'package:onestop_dev/pages/login/welcome.dart'; +import 'package:onestop_dev/pages/notifications/notifications.dart'; import 'package:onestop_dev/pages/quick_links/academic_calendar.dart'; import 'package:onestop_dev/pages/quick_links/academic_sso.dart'; import 'package:onestop_dev/pages/quick_links/cab_share.dart'; @@ -16,6 +18,7 @@ import 'package:onestop_dev/pages/profile.dart'; import 'package:onestop_dev/pages/splash.dart'; import 'package:onestop_dev/pages/upsp/upsp.dart'; + final routes = { SplashPage.id: (context) => const SplashPage(), ProfilePage.id: (context) => const ProfilePage(), @@ -31,7 +34,9 @@ final routes = { AcademicCalendar.id: (context) => const AcademicCalendar(), Complaints.id: (context) => const Complaints(), CabShare.id: (context) => const CabShare(), + NotificationPage.id: (context) => const NotificationPage(), Scoreboard.id: (context) => const Scoreboard(), Upsp.id: (context) => const Upsp(), GuestHouse.id: (context) => const GuestHouse(), + WelcomePage.id:(context)=> const WelcomePage(), }; diff --git a/lib/services/api.dart b/lib/services/api.dart index a66d3494..ce75762d 100644 --- a/lib/services/api.dart +++ b/lib/services/api.dart @@ -1,87 +1,184 @@ import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:http/http.dart' as http; +import 'package:onestop_dev/globals/database_strings.dart'; +import 'package:onestop_dev/globals/endpoints.dart'; +import 'package:onestop_dev/main.dart'; import 'package:onestop_dev/models/buy_sell/buy_model.dart'; import 'package:onestop_dev/models/lostfound/found_model.dart'; import 'package:onestop_dev/models/lostfound/lost_model.dart'; import 'package:onestop_dev/models/timetable/registered_courses.dart'; - import 'package:onestop_dev/models/buy_sell/sell_model.dart'; +import 'package:onestop_dev/pages/login/login.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../functions/utility/show_snackbar.dart'; +import '../models/food/mess_menu_model.dart'; +import '../models/travel/travel_timing_model.dart'; +import '../functions/utility/auth_user_helper.dart'; class APIService { - static const String _restaurantURL = - "https://swc.iitg.ac.in/onestopapi/v2/getAllOutlets"; - static const String _lastUpdatedURL = - "https://swc.iitg.ac.in/onestopapi/v2/lastDataUpdate"; - static const String _contactURL = - "https://swc.iitg.ac.in/onestopapi/v2/getContacts"; - static const String _timetableURL = - "https://swc.iitg.ac.in/smartTimetable/get-my-courses"; - static const String _ferryURL = - 'https://swc.iitg.ac.in/onestopapi/v2/ferryTimings'; - static const String _busURL = - 'https://swc.iitg.ac.in/onestopapi/v2/busTimings'; - static const String _messURL = - "https://swc.iitg.ac.in/onestopapi/v2/hostelsMessMenu"; - static const String _buyURL = 'https://swc.iitg.ac.in/onestopapi/v2/buy'; - static const String _sellURL = 'https://swc.iitg.ac.in/onestopapi/v2/sell'; - static const String _sellPath = '/onestopapi/v2/sellPage'; - static const String _buyPath = '/onestopapi/v2/buyPage'; - static const String _bnsMyAdsURL = - 'https://swc.iitg.ac.in/onestopapi/v2/bns/myads'; - static const String _lnfMyAdsURL = - 'https://swc.iitg.ac.in/onestopapi/v2/lnf/myads'; - static const String _deleteBuyURL = - "https://swc.iitg.ac.in/onestopapi/v2/buy/remove"; - static const String _deleteSellURL = - "https://swc.iitg.ac.in/onestopapi/v2/sell/remove"; - static const String _deleteLostURL = - "https://swc.iitg.ac.in/onestopapi/v2/lost/remove"; - static const String _deleteFoundURL = - "https://swc.iitg.ac.in/onestopapi/v2/found/remove"; - static const String _lostURL = 'https://swc.iitg.ac.in/onestopapi/v2/lost'; - static const String _lostPath = '/onestopapi/v2/lostPage'; - static const String _foundPath = '/onestopapi/v2/foundPage'; - static const String _foundURL = 'https://swc.iitg.ac.in/onestopapi/v2/found'; - static const String _claimItemURL = - "https://swc.iitg.ac.in/onestopapi/v2/found/claim"; - static const String _newsURL = "https://swc.iitg.ac.in/onestopapi/v2/news"; - static const String githubIssueToken = - String.fromEnvironment('GITHUB_ISSUE_TOKEN'); - static const apiSecurityKey = String.fromEnvironment('SECURITY-KEY'); - static const _feedback = - 'https://api.github.com/repos/vrrao01/onestop_dev/issues'; - static const String _upspPost = - 'https://swc.iitg.ac.in/onestopapi/v2/upsp/submit-request'; - static const String _uploadFileUPSP = - "https://swc.iitg.ac.in/onestopapi/v2/upsp/file-upload"; - - static Future postFeedbackData(Map data) async { + + final dio = Dio(BaseOptions( + baseUrl: Endpoints.baseUrl, + connectTimeout: const Duration(seconds: 15), + receiveTimeout: const Duration(seconds: 15), + headers: Endpoints.getHeader())); + +final dio2 = Dio(BaseOptions( + connectTimeout: const Duration(seconds: 15), + receiveTimeout: const Duration(seconds: 15), + headers: Endpoints.getHeader())); + + + APIService() { + dio.interceptors + .add(InterceptorsWrapper(onRequest: (options, handler) async { + print("THIS IS TOKEN"); + print(await AuthUserHelpers.getAccessToken()); + print(options.path); + options.headers["Authorization"] = + "Bearer ${await AuthUserHelpers.getAccessToken()}"; + handler.next(options); + }, onError: (error, handler) async { + var response = error.response; + if (response != null && response.statusCode == 401) { + if((await AuthUserHelpers.getAccessToken()).isEmpty){ + showSnackBar("Login to continue!!"); + } + else{ + print(response.requestOptions.path); + bool couldRegenerate = await regenerateAccessToken(); + // ignore: use_build_context_synchronously + if (couldRegenerate) { + print("COULD REGENRATE TOKEN"); + // retry + return handler.resolve(await retryRequest(response)); + } else { + showSnackBar("Your session has expired!! Login again."); + } + } + } + else if(response != null && response.statusCode == 403){ + showSnackBar("Access not allowed in guest mode"); + } + else if(response != null && response.statusCode == 400){ + showSnackBar(response.data["message"]); + } + // admin user with expired tokens + return handler.next(error); + })); + } + + Future> retryRequest(Response response) async { + RequestOptions requestOptions = response.requestOptions; + response.requestOptions.headers[BackendHelper.authorization] = + "Bearer ${await AuthUserHelpers.getAccessToken()}"; + final options = Options(method: requestOptions.method, headers: requestOptions.headers); + Dio retryDio = Dio(BaseOptions( + baseUrl: Endpoints.baseUrl, + connectTimeout: const Duration(seconds: 5), + receiveTimeout: const Duration(seconds: 5), + headers: { + 'Security-Key': Endpoints.apiSecurityKey + })); + if (requestOptions.method == "GET") { + return retryDio.request(requestOptions.path, + queryParameters: requestOptions.queryParameters, options: options); + } else { + return retryDio.request(requestOptions.path, + queryParameters: requestOptions.queryParameters, + data: requestOptions.data, + options: options); + } + } + + Future regenerateAccessToken() async { + String refreshToken = await AuthUserHelpers.getRefreshToken(); + try { + Dio regenDio = Dio(BaseOptions( + baseUrl: Endpoints.baseUrl, + connectTimeout: const Duration(seconds: 5), + receiveTimeout: const Duration(seconds: 5))); + Response> resp = await regenDio.post( + "/user/accesstoken", + options: Options(headers: {'Security-Key': Endpoints.apiSecurityKey,"authorization": "Bearer $refreshToken"})); + var data = resp.data!; + print("REGENRATED ACCESS TOKEN"); + await AuthUserHelpers.setAccessToken(data[BackendHelper.accesstoken]); + return true; + } catch (err) { + return false; + } + } + + + Future postFeedbackData(Map data) async { String tag = data['type'] == 'Issue Report' ? 'bug' : 'enhancement'; String newBody = "### Description :\n${data['body']}\n### Posted By :\n${data['user']}"; - var res = await http.post(Uri.parse(_feedback), - body: jsonEncode({ + print(Endpoints.githubIssueToken); + + var res = await dio2.post(Endpoints.feedback, + data: { 'title': data['title'], 'body': newBody, 'labels': [tag] - }), - headers: { + }, + options: Options(headers: { 'Accept': 'application/vnd.github+json', - 'Authorization': 'Bearer $githubIssueToken' - }); + 'Authorization': 'Bearer ${Endpoints.githubIssueToken}' + })); if (res.statusCode == 201) { return true; } return false; } - static Future>> getRestaurantData() async { - http.Response response = await http.get(Uri.parse(_restaurantURL)); + Future guestUserLogin() async { + var response = await dio.post(Endpoints.guestLogin); + return response; + } + + Future getUserProfile() async { + print("Inside GET USER PROFILE"); + var response = await dio.get(Endpoints.userProfile); + print(response.data); + return response.data; + } + + Future updateUserProfile(Map data,String? deviceToken) async { + print(data); + Map queryParameters={}; + if(deviceToken!=null) queryParameters["deviceToken"]=deviceToken; + var response = await dio.patch(Endpoints.userProfile,data: data,queryParameters: queryParameters); + print(response); + } + + Future postUserDeviceToken(String deviceToken) async { + var response = await dio.post(Endpoints.userDeviceTokens,data: {"deviceToken" : deviceToken}); + print(response); + } + + Future updateUserDeviceToken(Map data) async { + print(data); + var response = await dio.patch(Endpoints.userDeviceTokens,data: data); + print(response); + } + + // Future logoutUser(String deviceToken) async { + // print(deviceToken); + // var response = await dio.delete(Endpoints.userLogout,data: {"deviceToken" : deviceToken}); + // print(response); + // } + + Future>> getRestaurantData() async { + var response = await dio.get(Endpoints.restaurantURL); var status = response.statusCode; - var body = jsonDecode(response.body); + var body = response.data; if (status == 200) { List> data = []; for (var json in body) { @@ -93,10 +190,10 @@ class APIService { } } - static Future>> getNewsData() async { - http.Response response = await http.get(Uri.parse(_newsURL)); + Future>> getNewsData() async { + var response = await dio.get(Endpoints.newsURL); var status = response.statusCode; - var body = jsonDecode(response.body); + var body = response.data; if (status == 200) { List> data = []; for (var json in body) { @@ -108,69 +205,45 @@ class APIService { } } - static Future claimFoundItem( + Future claimFoundItem( {required String name, required String email, required String id}) async { - var res = await http.post(Uri.parse(_claimItemURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: - jsonEncode({"id": id, "claimerEmail": email, "claimerName": name})); - return jsonDecode(res.body); + var res = await dio.post(Endpoints.claimItemURL,data: {"id": id, "claimerEmail": email, "claimerName": name}); + return res.data; } - static Future deleteBnsMyAd(String id, String email) async { - await http.post(Uri.parse(_deleteBuyURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({'id': id, 'email': email})); - await http.post(Uri.parse(_deleteSellURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({'id': id, 'email': email})); + Future deleteBnsMyAd(String id, String email) async { + await dio.post(Endpoints.deleteBuyURL, + data: {'id': id, 'email': email}); + await dio.post(Endpoints.deleteSellURL, + data: {'id': id, 'email': email}); } - static Future deleteLnfMyAd(String id, String email) async { - await http.post(Uri.parse(_deleteLostURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({'id': id, 'email': email})); - await http.post(Uri.parse(_deleteFoundURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({'id': id, 'email': email})); + Future deleteLnfMyAd(String id, String email) async { + await dio.post(Endpoints.deleteLostURL, + data: {'id': id, 'email': email}); + await dio.post(Endpoints.deleteFoundURL, + data: {'id': id, 'email': email}); } - static Future getBuyItems() async { - var res = await http.get(Uri.parse(_buyURL)); - var lostItemsDetails = jsonDecode(res.body); - return lostItemsDetails["details"]; + Future getBuyItems() async { + //var res = await http.get(Uri.parse(Endpoints.buyURL)); + var response = await dio.get(Endpoints.buyURL); + // var lostItemsDetails = jsonDecode(res.body); + // return lostItemsDetails["details"]; + print(response.data); + return response.data.details; } - static Future getSellItems() async { - var res = await http.get(Uri.parse(_sellURL)); - var foundItemsDetails = jsonDecode(res.body); - return foundItemsDetails["details"]; + Future getSellItems() async { + var res = await dio.get(Endpoints.sellURL); + return res.data.details; } - static Future> getBnsMyItems(String mail) async { - var res = await http.post(Uri.parse(_bnsMyAdsURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({'email': mail})); - - var myItemsDetails = jsonDecode(res.body); + Future> getBnsMyItems(String mail) async { + print("here in function"); + var res = await dio.post(Endpoints.bnsMyAdsURL,data: {'email': mail}); + print(res.data); + var myItemsDetails = res.data; var sellList = (myItemsDetails["details"]["sellList"] as List) .map((e) => BuyModel.fromJson(e)) .toList(); @@ -181,15 +254,11 @@ class APIService { return [...sellList, ...buyList]; } - static Future> getLnfMyItems(String mail) async { - var res = await http.post(Uri.parse(_lnfMyAdsURL), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({'email': mail})); - - var myItemsDetails = jsonDecode(res.body); + Future> getLnfMyItems(String mail) async { + print("here"); + var res = await dio.post(Endpoints.lnfMyAdsURL,data: {'email': mail}); + print(res); + var myItemsDetails = res.data; var foundList = (myItemsDetails["details"]["foundList"] as List) .map((e) => FoundModel.fromJson(e)) .toList(); @@ -200,19 +269,23 @@ class APIService { return [...foundList, ...lostList]; } - static Future getLostItems() async { - var res = await http.get(Uri.parse(_lostURL)); - var lostItemsDetails = jsonDecode(res.body); + Future getLostItems() async { + var res = await dio.get(Endpoints.lostURL); + var lostItemsDetails = res.data; return lostItemsDetails["details"]; } - static Future> getLostPage(int pageNumber) async { + Future> getLostPage(int pageNumber) async { + print("hre"); final queryParameters = { 'page': pageNumber.toString(), }; - final uri = Uri.https('swc.iitg.ac.in', _lostPath, queryParameters); - var response = await http.get(uri); - var json = jsonDecode(response.body); + // final uri = + // Uri.https('swc.iitg.ac.in', Endpoints.lostPath, queryParameters); + var response = await dio.get(Endpoints.lostPath,queryParameters: queryParameters); + print(response); + var json = response.data; + print(json); List lostPage = (json['details'] as List) .map((e) => LostModel.fromJson(e)) .toList(); @@ -220,13 +293,14 @@ class APIService { return lostPage; } - static Future> getFoundPage(int pageNumber) async { + Future> getFoundPage(int pageNumber) async { final queryParameters = { 'page': pageNumber.toString(), }; - final uri = Uri.https('swc.iitg.ac.in', _foundPath, queryParameters); - var response = await http.get(uri); - var json = jsonDecode(response.body); + // final uri = + // Uri.https('swc.iitg.ac.in', Endpoints.foundPath, queryParameters); + var response = await dio.get(Endpoints.foundPath,queryParameters: queryParameters); + var json = response.data; List lostPage = (json['details'] as List) .map((e) => FoundModel.fromJson(e)) .toList(); @@ -234,13 +308,14 @@ class APIService { return lostPage; } - static Future> getSellPage(int pageNumber) async { + Future> getSellPage(int pageNumber) async { final queryParameters = { 'page': pageNumber.toString(), }; - final uri = Uri.https('swc.iitg.ac.in', _sellPath, queryParameters); - var response = await http.get(uri); - var json = jsonDecode(response.body); + // final uri = + // Uri.https('swc.iitg.ac.in', Endpoints.sellPath, queryParameters); + var response = await dio.get(Endpoints.sellPath,queryParameters: queryParameters); + var json = response.data; List sellPage = (json['details'] as List) .map((e) => BuyModel.fromJson(e)) .toList(); @@ -248,13 +323,15 @@ class APIService { return sellPage; } - static Future> getBuyPage(int pageNumber) async { + Future> getBuyPage(int pageNumber) async { + print(pageNumber); final queryParameters = { 'page': pageNumber.toString(), }; - final uri = Uri.https('swc.iitg.ac.in', _buyPath, queryParameters); - var response = await http.get(uri); - var json = jsonDecode(response.body); + //final uri = Uri.https('swc.iitg.ac.in', Endpoints.buyPath, queryParameters); + var response = await dio.get(Endpoints.buyPath,queryParameters: queryParameters); + print(response); + var json = response.data; List buyPage = (json['details'] as List) .map((e) => SellModel.fromJson(e)) .toList(); @@ -262,54 +339,50 @@ class APIService { return buyPage; } - static Future getFoundItems() async { - var res = await http.get(Uri.parse(_foundURL)); - var foundItemsDetails = jsonDecode(res.body); + Future getFoundItems() async { + var res = await dio.get(Endpoints.foundURL); + var foundItemsDetails = res.data; return foundItemsDetails["details"]; } - static Future> postSellData( + Future> postSellData( Map data) async { - var res = await http.post(Uri.parse(_sellURL), - body: jsonEncode({ - 'title': data['title'], - 'description': data['description'], - 'price': data['price'], - 'imageString': data['image'], - 'phonenumber': data['contact'], - 'email': data['email'], - 'username': data['name'] - }), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }); - return jsonDecode(res.body); + var res = await dio.post( + Endpoints.sellURL, + data: { + 'title': data['title'], + 'description': data['description'], + 'price': data['price'], + 'imageString': data['image'], + 'phonenumber': data['contact'], + 'email': data['email'], + 'username': data['name'] + } + ); + return res.data; } - static Future> postBuyData( + Future> postBuyData( Map data) async { - var res = await http.post(Uri.parse(_buyURL), - body: jsonEncode({ - 'title': data['title'], - 'description': data['description'], - 'price': data['total_price'], - 'imageString': data['image'], - 'phonenumber': data['contact'], - 'email': data['email'], - 'username': data['name'] - }), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }); - return jsonDecode(res.body); + var res = await dio.post( + Endpoints.buyURL, + data: { + 'title': data['title'], + 'description': data['description'], + 'price': data['total_price'], + 'imageString': data['image'], + 'phonenumber': data['contact'], + 'email': data['email'], + 'username': data['name'] + } + ); + return res.data; } - static Future> postLostData( + Future> postLostData( Map data) async { - var res = await http.post(Uri.parse(_lostURL), - body: jsonEncode({ + var res = await dio.post(Endpoints.lostURL, + data: { 'title': data['title'], 'description': data['description'], 'location': data['location'], @@ -317,18 +390,14 @@ class APIService { 'phonenumber': data['contact'], 'email': data['email'], 'username': data['name'] - }), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey }); - return jsonDecode(res.body); + return res.data; } - static Future> postFoundData( + Future> postFoundData( Map data) async { - var res = await http.post(Uri.parse(_foundURL), - body: jsonEncode({ + var res = await dio.post(Endpoints.foundURL, + data: { 'title': data['title'], 'description': data['description'], 'location': data['location'], @@ -336,18 +405,16 @@ class APIService { 'submittedat': data['submittedAt'], 'email': data['email'], 'username': data['name'] - }), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey }); - return jsonDecode(res.body); + return res.data; } - static Future> getLastUpdated() async { - http.Response response = await http.get(Uri.parse(_lastUpdatedURL)); + Future> getLastUpdated() async { + var response = + await dio.get(Endpoints.lastUpdatedURL); var status = response.statusCode; - var body = jsonDecode(response.body); + var body = response.data; + print(body); if (status == 200) { Map data = body; return data; @@ -356,10 +423,10 @@ class APIService { } } - static Future>> getContactData() async { - http.Response response = await http.get(Uri.parse(_contactURL)); + Future>> getContactData() async { + var response = await dio.get(Endpoints.contactURL); var status = response.statusCode; - var body = jsonDecode(response.body); + var body = response.data; if (status == 200) { List> data = []; for (var json in body) { @@ -371,10 +438,12 @@ class APIService { } } - static Future>>> getBusData() async { - http.Response response = await http.get(Uri.parse(_busURL)); + Future>>> getBusData() async { + print("INSIDE BUS DATA"); + var response = await dio.get(Endpoints.busURL); var status = response.statusCode; - var json = jsonDecode(response.body); + var json = response.data; + print(json); if (status == 200) { Map>> answer = {}; for (String stop in json.keys) { @@ -400,10 +469,10 @@ class APIService { } } - static Future>> getFerryData() async { - http.Response response = await http.get(Uri.parse(_ferryURL)); + Future>> getFerryData() async { + var response = await dio.get(Endpoints.ferryURL); var status = response.statusCode; - var json = jsonDecode(response.body); + var json = response.data; if (status == 200) { List> answer = []; for (var temp in json) { @@ -415,28 +484,25 @@ class APIService { } } - static Future getTimeTable({required String roll}) async { - final response = await http.post( - Uri.parse(_timetableURL), - headers: { - HttpHeaders.contentTypeHeader: 'application/json', - 'security-key': apiSecurityKey - }, - body: jsonEncode({ + Future getTimeTable({required String roll}) async { + print(roll); + final response = await dio2.post(Endpoints.timetableURL, + data: { "roll_number": roll, - }), + }, ); + print(response); if (response.statusCode == 200) { - return RegisteredCourses.fromJson(jsonDecode(response.body)); + return RegisteredCourses.fromJson(response.data); } else { throw Exception(response.statusCode); } } - static Future>> getMessMenu() async { - http.Response response = await http.get(Uri.parse(_messURL)); + Future>> getMessMenu() async { + var response = await dio.get(Endpoints.messURL); var status = response.statusCode; - var body = jsonDecode(response.body); + var body = response.data; if (status == 200) { List> data = []; for (var json in body) { @@ -448,49 +514,41 @@ class APIService { } } - static Future> getPolyline( + Future> getPolyline( {required LatLng source, required LatLng dest}) async { - final response = await http.get( - Uri.parse( - 'https://api.openrouteservice.org/v2/directions/driving-car?api_key=5b3ce3597851110001cf6248b144cc92443247b7b9e0bd5df85012f2&start=8.681495,49.41461&end=8.687872,49.420318'), - headers: { - HttpHeaders.contentTypeHeader: 'application/json', - }, + final response = await dio.get( + 'https://api.openrouteservice.org/v2/directions/driving-car?api_key=5b3ce3597851110001cf6248b144cc92443247b7b9e0bd5df85012f2&start=8.681495,49.41461&end=8.687872,49.420318', ); if (response.statusCode == 200) { - var body = jsonDecode(response.body); + var body = response.data; List res = []; for (var r in body['features'][0]['geometry']['coordinates']) { res.add(LatLng(r[0], r[1])); } return res; } else { - throw Exception(response.body); + throw Exception(response.data); } } - static Future> postUPSP( + Future> postUPSP( Map data) async { - var res = await http.post(Uri.parse(_upspPost), - body: jsonEncode(data), - headers: { - 'Content-Type': 'application/json', - 'security-key': apiSecurityKey - }); - return jsonDecode(res.body); + var res = await dio.post(Endpoints.upspPost, + data: data); + return res.data; } - static Future uploadFileToServer(File file) async { + Future uploadFileToServer(File file) async { var fileName = file.path.split('/').last; var formData = FormData.fromMap({ 'file': await MultipartFile.fromFile(file.path, filename: fileName), }); try { - var response = await Dio().post( - _uploadFileUPSP, + var response = await dio.post( + Endpoints.uploadFileUPSP, options: Options( - contentType: 'multipart/form-data', - headers: {'security-key': apiSecurityKey}), + contentType: 'multipart/form-data' + ), data: formData, onSendProgress: (int send, int total) { // TODO: Show send/total percent as progress indicator @@ -500,8 +558,57 @@ class APIService { return response.data['filename']; } return null; - } on DioError { + } on DioException { return null; } } + + static Future createUser(String token) async { + final prefs = await SharedPreferences.getInstance(); + final res = await http.post( + Uri.parse('https://swc.iitg.ac.in/onestopapi/v2/onestop-user'), + body: jsonEncode( + { + "name": prefs.getString('name'), + "email": prefs.getString('email'), + "deviceToken": token + }, + ), + headers: { + 'Content-Type': 'application/json', + 'security-key': Endpoints.apiSecurityKey + }, + ); + + } + + Future> getFerryTiming() async { + try { + Response res = await dio.get(Endpoints.ferryURL); + return res.data; + } catch (e) { + rethrow; + } + } + + Future> getMealData() async { + try{ + final res = await dio.get(Endpoints.messURL); + return res.data; + }catch(e){ + print(Endpoints.messURL); + print(e); + rethrow; + } + } + Future> getBusTiming() async { + try { + final res = await dio.get(Endpoints.busStops); + return res.data; + } catch (e) { + print("____________________________________________"); + print(e); + rethrow; + } + } } diff --git a/lib/services/data_provider.dart b/lib/services/data_provider.dart index e311a2d2..34b0d47d 100644 --- a/lib/services/data_provider.dart +++ b/lib/services/data_provider.dart @@ -1,136 +1,186 @@ import 'dart:async'; import 'dart:collection'; +import 'package:flutter/material.dart'; import 'package:onestop_dev/globals/database_strings.dart'; import 'package:onestop_dev/models/contacts/contact_model.dart'; import 'package:onestop_dev/models/food/mess_menu_model.dart'; import 'package:onestop_dev/models/food/restaurant_model.dart'; import 'package:onestop_dev/models/news/news_model.dart'; import 'package:onestop_dev/models/timetable/registered_courses.dart'; -import 'package:onestop_dev/models/travel/ferry_data_model.dart'; import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/local_storage.dart'; +import '../models/travel/travel_timing_model.dart'; + class DataProvider { static Future?> getLastUpdated() async { - var cachedData = await LocalStorage.instance.getRecord(DatabaseRecords.lastUpdated); + var cachedData = + await LocalStorage.instance.getRecord(DatabaseRecords.lastUpdated); if (cachedData == null) { return null; } return cachedData[0] as Map; } - static Future>>> getBusTimings() async { - var cachedData = await LocalStorage.instance.getBusRecord(DatabaseRecords.busTimings); - if (cachedData == null) { - Map>> busTime = await APIService.getBusData(); - await LocalStorage.instance.storeBusData(busTime, DatabaseRecords.busTimings); - return busTime; - } - Map>> timings = {}; - for (String key in cachedData.keys) { - timings[key] = (cachedData[key] as List) - .map((e) => - (e as List).map((e) => (e as String).trim()).toList()) - .toList(); - } - return timings; + static Future> getBusTiming() async { + var cachedData = await LocalStorage.instance.getRecord(DatabaseRecords.busTimings); + print("BUS TIMINGS"); + Map jsonData; + if (cachedData == null) { + jsonData = await APIService().getBusTiming(); + await LocalStorage.instance.storeData([jsonData], DatabaseRecords.busTimings); + } else { + jsonData = cachedData[0] as Map; + } + List busData = jsonData['data']; + print(busData); + List busTimings = []; + print("here before length"); + for (var element in busData) { + busTimings.add(TravelTiming.fromJson(element)); + } + print("here at length"); + print(busTimings.length); + return busTimings; + } static Future> getRestaurants() async { - var cachedData = await LocalStorage.instance.getRecord(DatabaseRecords.restaurant); + var cachedData = + await LocalStorage.instance.getRecord(DatabaseRecords.restaurant); if (cachedData == null) { + print("INSIDE RESTRAURENTS GET"); List> restaurantData = - await APIService.getRestaurantData(); - + await APIService().getRestaurantData(); + print(restaurantData); List restaurants = restaurantData.map((e) => RestaurantModel.fromJson(e)).toList(); - await LocalStorage.instance.storeData(restaurantData, DatabaseRecords.restaurant); + await LocalStorage.instance + .storeData(restaurantData, DatabaseRecords.restaurant); return restaurants; } - return cachedData .map((e) => RestaurantModel.fromJson(e as Map)) .toList(); } static Future> getNews() async { - List> newsData = await APIService.getNewsData(); + List> newsData = await APIService().getNewsData(); List news = newsData.map((e) => NewsModel.fromJson(e)).toList(); return news; } static Future getTimeTable({required String roll}) async { - var cachedData = (await LocalStorage.instance.getRecord(DatabaseRecords.timetable))?[0]; + var cachedData = + (await LocalStorage.instance.getRecord(DatabaseRecords.timetable))?[0]; if (cachedData == null) { + print(roll); RegisteredCourses timetableData = - await APIService.getTimeTable(roll: roll); + await APIService().getTimeTable(roll: roll); await LocalStorage.instance .storeData([timetableData.toJson()], DatabaseRecords.timetable); return timetableData; } // TODO: Change this later, for now cache till the end of Monsoon sem - DateTime semEnd = DateTime.parse("2022-12-23"); + DateTime semEnd = DateTime.parse("2023-12-23"); if (DateTime.now().isBefore(semEnd)) { return RegisteredCourses.fromJson(cachedData as Map); } - return (await APIService.getTimeTable(roll: roll)); + return (await APIService().getTimeTable(roll: roll)); } - static Future> getContacts() async { - var cachedData = await LocalStorage.instance.getRecord(DatabaseRecords.contacts); - SplayTreeMap people = SplayTreeMap(); + static Future getMealData({ + required String hostel, + required String day, + required String mealType, + }) async { + var cachedData = + (await LocalStorage.instance.getRecord(DatabaseRecords.messMenu))?[0]; + Map? jsonData; if (cachedData == null) { - List> contactData = - await APIService.getContactData(); - for (var element in contactData) { - people[element['name']] = ContactModel.fromJson(element); - } - await LocalStorage.instance.storeData(contactData, DatabaseRecords.contacts); - return people; + jsonData = await APIService().getMealData(); + LocalStorage.instance.storeData([jsonData], DatabaseRecords.messMenu); + } else { + jsonData = cachedData as Map; } - for (var element in cachedData) { - var x = element as Map; - people[x['name']] = ContactModel.fromJson(x); + + List answer = jsonData['details']!; + var meal = answer.firstWhere( + (m) => + m['hostel'].toString().trim().toLowerCase() == + hostel.toString().toLowerCase(), + orElse: () => 'no data'); + if (meal == 'no data') { + return MealType( + id: '', + mealDescription: + "Not updated by ${hostel}'s HMC. Kindly Contact ask them to update", + startTiming: DateTime.now(), + endTiming: DateTime.now()); } - return people; + return MealType( + id: meal[day.trim().toLowerCase()][mealType.trim().toLowerCase()]['_id'], + mealDescription: meal[day.trim().toLowerCase()] + [mealType.trim().toLowerCase()]['mealDescription'], + startTiming: DateTime.parse(meal[day.trim().toLowerCase()] + [mealType.trim().toLowerCase()]['startTiming']) + .add(const Duration(hours: 5, minutes: 30)), + endTiming: DateTime.parse(meal[day.trim().toLowerCase()] + [mealType.trim().toLowerCase()]['endTiming']) + .add(const Duration(hours: 5, minutes: 30)), + ); } - static Future> getMessMenu() async { - // return Future.delayed(Duration(seconds: 10),() => throw Exception("hello")); - var cachedData = await LocalStorage.instance.getRecord(DatabaseRecords.messMenu); + static Future> getContacts() async { + var cachedData = + await LocalStorage.instance.getRecord(DatabaseRecords.contacts); + SplayTreeMap people = SplayTreeMap(); if (cachedData == null) { - List> messMenuData = await APIService.getMessMenu(); - List answer = - messMenuData.map((e) => MessMenuModel.fromJson(e)).toList(); - await LocalStorage.instance.storeData(messMenuData, DatabaseRecords.messMenu); - return answer; + List> contactData = + await APIService().getContactData(); + print("GET CONTACT DATA"); + print(contactData); + for (var element in contactData) { + people[element['sectionName']] = ContactModel.fromJson(element); + print("HERE NFJ"); + } + await LocalStorage.instance + .storeData(contactData, DatabaseRecords.contacts); + return people; + } else { + for (var element in cachedData) { + var x = element as Map; + people[x['sectionName']] = ContactModel.fromJson(x); + } + return people; } - List answer = cachedData - .map((e) => MessMenuModel.fromJson(e as Map)) - .toList(); - return answer; } - static Future> getFerryTimings() async { + static Future> getFerryTiming() async { var cachedData = await LocalStorage.instance.getRecord(DatabaseRecords.ferryTimings); - if (cachedData == null) { - List> ferryData = await APIService.getFerryData(); - await LocalStorage.instance.storeData(ferryData, DatabaseRecords.ferryTimings); - List answer = - ferryData.map((e) => FerryTimeData.fromJson(e)).toList(); - return answer; - } - List answer = []; + print("FERRY TIMINGS"); + Map jsonData; + if (cachedData == null) { + jsonData = await APIService().getFerryTiming(); + await LocalStorage.instance.storeData([jsonData], DatabaseRecords.ferryTimings); + } else { + jsonData = cachedData[0] as Map; + } + + List ferryTimings = []; + List ferryData = jsonData['data']; + print(ferryData); + for (var element in ferryData) { + ferryTimings.add(TravelTiming.fromJson(element)); + print(TravelTiming.fromJson(element).toJson()); + } + print(ferryTimings.length); + return ferryTimings; - for (var element in cachedData) { - var x = element as Map; - answer.add(FerryTimeData.fromJson(x)); - } - return answer; } } diff --git a/lib/services/notifications_provider.dart b/lib/services/notifications_provider.dart new file mode 100644 index 00000000..a9630851 --- /dev/null +++ b/lib/services/notifications_provider.dart @@ -0,0 +1,174 @@ +import 'dart:convert'; +import 'dart:io' show Platform; +import 'package:firebase_core/firebase_core.dart'; +import "package:firebase_messaging/firebase_messaging.dart"; +import "package:flutter_local_notifications/flutter_local_notifications.dart"; +import 'package:shared_preferences/shared_preferences.dart'; + +Future firebaseMessagingBackgroundHandler(RemoteMessage message) async { + await Firebase.initializeApp(); + print('A bg message just showed up : ${message.messageId}'); + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + const AndroidNotificationChannel channel = AndroidNotificationChannel( + 'high_importance_channel', // id + 'High Importance Notifications', // title + description: + 'This channel is used for important notifications.', // description + importance: Importance.high, + playSound: true); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(channel); + AndroidNotificationDetails androidNotificationDetails = + AndroidNotificationDetails(channel.id, channel.name, + channelDescription: channel.description, + importance: Importance.high, + playSound: true, + icon: 'notification_icon'); + DarwinNotificationDetails iosNotificationDetails = + const DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + NotificationDetails notificationDetails = NotificationDetails( + android: androidNotificationDetails, + iOS: iosNotificationDetails, + ); + RemoteNotification? notification = message.notification; + + print("Notification : $notification"); + if (checkNotificationCategory(message.data['category'])) { + await flutterLocalNotificationsPlugin.show( + message.hashCode, + message.data['header'], + message.data['body'], + notificationDetails, + ); + } + saveNotification(message); +} + +@pragma('vm:entry-point') +void onDidReceiveNotificationResponse( + NotificationResponse notificationResponse) async { + final String? payload = notificationResponse.payload; + if (notificationResponse.payload != null) { + print('notification payload: $payload'); + } + // await Navigator.pushNamed(context, HomePage.id); +} + +bool checkNotificationCategory(String type) { + switch (type.toLowerCase()) { + case "lost": + case "found": + case "buy": + case "sell": + case "travel": + case "cab sharing": + return true; + } + return false; +} + +Future checkForNotifications() async { + await FirebaseMessaging.instance.subscribeToTopic('all'); + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + + if (Platform.isAndroid) { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.requestPermission(); + } + + const AndroidNotificationChannel channel = AndroidNotificationChannel( + 'high_importance_channel', // id + 'High Importance Notifications', // title + description: + 'This channel is used for important notifications.', // description + importance: Importance.high, + playSound: true); + + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(channel); + + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('@mipmap/ic_launcher'); + const DarwinInitializationSettings initializationSettingsDarwin = + DarwinInitializationSettings( + requestSoundPermission: true, + requestBadgePermission: true, + requestAlertPermission: true, + ); + const InitializationSettings initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsDarwin, + ); + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + // onDidReceiveNotificationResponse: onDidReceiveNotificationResponse, + // onDidReceiveBackgroundNotificationResponse: + // onDidReceiveNotificationResponse, + ); + + FirebaseMessaging.onMessage.listen((RemoteMessage message) async { + print("Here me"); + AndroidNotificationDetails androidNotificationDetails = + AndroidNotificationDetails(channel.id, channel.name, + channelDescription: channel.description, + importance: Importance.high, + playSound: true, + icon: 'notification_icon'); + DarwinNotificationDetails iosNotificationDetails = + const DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + ); + NotificationDetails notificationDetails = NotificationDetails( + android: androidNotificationDetails, + iOS: iosNotificationDetails, + ); + print("Message is ${message.data}"); + if (checkNotificationCategory(message.data['category'])) { + await flutterLocalNotificationsPlugin.show( + message.hashCode, + message.data['header'], + message.data['body'], + notificationDetails, + ); + } + saveNotification(message); + }); + + // Resave list of notifications in case it's initialized to null + final SharedPreferences preferences = await SharedPreferences.getInstance(); + await preferences.reload(); + List notifications = preferences.getStringList('notifications') ?? []; + preferences.setStringList('notifications', notifications); + return true; +} + +void saveNotification(RemoteMessage message) async { + Map notificationData = message.data; + DateTime sentTime = message.sentTime ?? DateTime.now(); + final SharedPreferences preferences = await SharedPreferences.getInstance(); + notificationData['time'] = sentTime?.toString() ?? DateTime.now().toString(); + notificationData['read'] = false; + notificationData['messageId'] = message.messageId; + String notifJson = jsonEncode(notificationData); + print("data = $notificationData"); + List notifications = preferences.getStringList('notifications') ?? []; + if (notifications.length > 15) { + notifications.removeAt(0); + } + notifications.add(notifJson); + preferences.setStringList('notifications', notifications); +} diff --git a/lib/stores/login_store.dart b/lib/stores/login_store.dart index 3b14bbb3..ab550787 100644 --- a/lib/stores/login_store.dart +++ b/lib/stores/login_store.dart @@ -1,13 +1,23 @@ // import 'package:aad_oauth/aad_oauth.dart'; // import 'package:aad_oauth/model/config.dart'; +import 'dart:convert'; + +import 'package:onestop_dev/globals/database_strings.dart'; +import 'package:onestop_dev/globals/endpoints.dart'; +import 'package:onestop_dev/models/profile/profile_model.dart'; +import 'package:onestop_dev/pages/profile/profile_page.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/local_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:webview_cookie_manager/webview_cookie_manager.dart'; +import 'package:dio/dio.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; class LoginStore { - Map userData = {}; + static Map userData = {}; final cookieManager = WebviewCookieManager(); - final String guestEmail = 'guest_user'; + static bool isGuest = false; + static bool isProfileComplete=false; // static final Config config = Config( // tenant: '850aa78d-94e1-4bc6-9cf3-8c11b530701c', // clientId: '81f3e9f0-b0fd-48e0-9d36-e6058e5c6d4f', @@ -45,49 +55,95 @@ class LoginStore { Future isAlreadyAuthenticated() async { SharedPreferences user = await SharedPreferences.getInstance(); - if (user.containsKey("name")) { - saveToUserData(user); + print("inside authentication check"); + if (user.containsKey("userInfo")) { + print("here"); + if(user.containsKey("isProfileComplete")){ + print("PROFILE IS COMPLETE"); + isProfileComplete=true; + } + else{ + print("PROFILE IS INCOMPLETE"); + } + print(await user.containsKey("userInfo")); + await saveToUserInfo(user); return true; } return false; } bool get isGuestUser { - if (userData['email'] == guestEmail) { - return true; - } - return false; + return isGuest; } Future signInAsGuest() async { + print("GUEST SIGN IN"); + isGuest = true; var sharedPrefs = await SharedPreferences.getInstance(); - saveToPreferences(sharedPrefs, { - 'displayName': 'Guest User', - 'mail': guestEmail, - 'surname': ' ', - 'id': '' - }); + print(Endpoints.guestLogin); + print(Endpoints.getHeader()); + final response = await APIService().guestUserLogin(); + print(response.data); + await saveToPreferences(sharedPrefs, response.data); + await saveToUserInfo(sharedPrefs); + await sharedPrefs.setBool("isProfileComplete", true); // profile is complete for guest } - void saveToPreferences(SharedPreferences instance, dynamic data) { - instance.setString("name", data["displayName"]); - instance.setString("email", data["mail"]); - instance.setString("rollno", data["surname"]); - instance.setString("id", data["id"]); + Future saveToPreferences( + SharedPreferences instance, dynamic data) async { + print(data); + print(data.runtimeType); + print(data[BackendHelper.accesstoken]); + await instance.setString( + BackendHelper.accesstoken, data[BackendHelper.accesstoken]); + await instance.setString( + BackendHelper.refreshtoken, data[BackendHelper.refreshtoken]); + await instance.setBool("isGuest", isGuest); // handle guest or user + Map userInfo = await APIService().getUserProfile(); + print(userInfo); + print(jsonEncode(userInfo)); + await instance.setString("userInfo", jsonEncode(userInfo)); // save user profile } - void saveToUserData(SharedPreferences instance) { - userData["name"] = instance.getString("name") ?? " "; - userData["email"] = instance.getString("email") ?? " "; - userData["rollno"] = instance.getString("rollno") ?? " "; - userData["id"] = instance.getString("id") ?? " "; + Future saveToUserInfo(SharedPreferences instance) async { // only called after saving jwt tokens in local storage + print("here"); + userData = jsonDecode(instance.getString("userInfo")!); + print(userData); + var fcmToken = await FirebaseMessaging.instance.getToken(); + print("fcm token: ${fcmToken}"); + print(isGuest); + if(instance.getBool("isGuest")==false){ + print(instance.getString("deviceToken")); + if (instance.getString("deviceToken") != null && instance.getString("deviceToken")!=fcmToken) { // already some token was stored + print("inside if"); + await APIService().updateUserDeviceToken({ + "oldToken": instance.getString("deviceToken"), // stored token + "newToken": fcmToken + }); + } + else if(instance.getString("deviceToken")==null){ + print("inside else"); + instance.setString("deviceToken", fcmToken!); // set the returned fcToken + await APIService().postUserDeviceToken(fcmToken!); + } + } + else{ + isGuest=true; + } } void logOut(Function navigationPopCallBack) async { + print("INSIDE LOGOUT"); await cookieManager.clearCookies(); SharedPreferences user = await SharedPreferences.getInstance(); - user.clear(); + // if(!isGuest){ + // print(user.getString("deviceToken")!); + // await APIService().logoutUser(user.getString("deviceToken")!); // remove token on logout if not guest + // } + await user.clear(); userData.clear(); + isGuest = false; + isProfileComplete=false; await LocalStorage.instance.deleteRecordsLogOut(); navigationPopCallBack(); } diff --git a/lib/stores/mapbox_store.dart b/lib/stores/mapbox_store.dart index 72f27ce9..9f42c6d3 100644 --- a/lib/stores/mapbox_store.dart +++ b/lib/stores/mapbox_store.dart @@ -137,8 +137,8 @@ abstract class _MapBoxStore with Store { } @action - Future getPolylines(int i) async { - loadOperation = APIService.getPolyline( + Future getPolylines(int i,BuildContext context) async { + loadOperation = APIService().getPolyline( source: LatLng(userlat, userlong), dest: const LatLng(26.2027, 91.7004)) .asObservable(); diff --git a/lib/stores/mapbox_store.g.dart b/lib/stores/mapbox_store.g.dart index cb948698..6e21b216 100644 --- a/lib/stores/mapbox_store.g.dart +++ b/lib/stores/mapbox_store.g.dart @@ -194,8 +194,8 @@ mixin _$MapBoxStore on _MapBoxStore, Store { AsyncAction('_MapBoxStore.getPolylines', context: context); @override - Future getPolylines(int i) { - return _$getPolylinesAsyncAction.run(() => super.getPolylines(i)); + Future getPolylines(int i, BuildContext context) { + return _$getPolylinesAsyncAction.run(() => super.getPolylines(i, context)); } late final _$_MapBoxStoreActionController = diff --git a/lib/stores/mess_store.dart b/lib/stores/mess_store.dart index 40ef0b99..2e131c65 100644 --- a/lib/stores/mess_store.dart +++ b/lib/stores/mess_store.dart @@ -1,23 +1,18 @@ // ignore_for_file: library_private_types_in_public_api - import 'package:mobx/mobx.dart'; import 'package:onestop_dev/functions/food/get_day.dart'; import 'package:onestop_dev/models/food/mess_menu_model.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; - part 'mess_store.g.dart'; - class MessStore = _MessStore with _$MessStore; - abstract class _MessStore with Store { _MessStore() { setupReactions(); } - @observable - String selectedDay = getFormattedDay(); - + String selectedDay = getFormattedDayForMess(); @observable String selectedMeal = getMeal(); @@ -32,68 +27,57 @@ abstract class _MessStore with Store { } return "Dinner"; } - @observable - ObservableFuture selectedHostel = ObservableFuture(getSavedHostel()); - + ObservableFuture selectedHostel = ObservableFuture(getSavedHostel()) ; + @observable + MealType mealData= MealType(id: 'id', mealDescription: 'mealDescription', startTiming: DateTime.now(), endTiming: DateTime.now()); @computed bool get hostelLoaded => selectedHostel.status == FutureStatus.fulfilled; - - @observable - MessMenuModel? selectedMessModel; - - static Future getSavedHostel() async { - var prefs = await SharedPreferences.getInstance(); - if (prefs.containsKey('hostel')) { - return prefs.getString('hostel') ?? "Kameng"; - } - return "Kameng"; - } - - @observable - ObservableFuture> allMessData = - ObservableFuture(DataProvider.getMessMenu()); - @action void setDay(String s) { selectedDay = s; } - @action void setMeal(String s) { selectedMeal = s; } - @action - void setHostel(String s) { + void setHostel(String s) { selectedHostel = ObservableFuture.value(s); + print(selectedHostel.value); + print("___________________________________"); } - @action - void setSelectedMessModel(MessMenuModel m) { - selectedMessModel = m; + void setmealData(MealType m) { + mealData = m; } - - void setupReactions() { - autorun((_) { - if (allMessData.status == FutureStatus.fulfilled && - selectedHostel.status == FutureStatus.fulfilled) { - var requiredModel = allMessData.value!.firstWhere( - (element) => (element.day - .toLowerCase() - .contains(selectedDay.toLowerCase()) && - element.hostel - .toLowerCase() - .contains(selectedHostel.value!.toLowerCase()) && - element.meal.toLowerCase() == selectedMeal.toLowerCase()), - orElse: () => MessMenuModel( - hostel: "", - meal: "", - menu: "Not updated by HMC.", - day: "", - timing: "Oh no!")); - setSelectedMessModel(requiredModel); + void setupReactions() async { + autorun((_) async{ + if(selectedHostel.status == FutureStatus.fulfilled){ + print("selected hostel"); + print(selectedHostel.value); + // MealType requiredModel = await APIService().getMealData(selectedHostel.value! , selectedDay, selectedMeal); + MealType requiredModel = await DataProvider.getMealData(hostel:selectedHostel.value!, day: selectedDay,mealType: selectedMeal ); + print(requiredModel.toJson()); + setmealData(requiredModel); + }else{ + print("else selected hostel"); + // MealType requiredModel = await APIService().getMealData('kameng' , 'Monday', 'Breakfast'); + MealType requiredModel = await DataProvider.getMealData(hostel:'kameng', day: 'monday',mealType: 'breakfast' ); + print(requiredModel.toJson()); + setmealData(requiredModel); } }); } -} + + static Future getSavedHostel() async{ + var prefs = await SharedPreferences.getInstance(); + if (prefs.containsKey('hostel')) { + if(prefs.getString('hostel')=="Brahma"){ + return 'Brahmaputra'; + } + return prefs.getString('hostel') ?? "Kameng"; + } + return "Kameng"; + } +} \ No newline at end of file diff --git a/lib/stores/mess_store.g.dart b/lib/stores/mess_store.g.dart index bb7fa502..a42f81fe 100644 --- a/lib/stores/mess_store.g.dart +++ b/lib/stores/mess_store.g.dart @@ -65,35 +65,19 @@ mixin _$MessStore on _MessStore, Store { }); } - late final _$selectedMessModelAtom = - Atom(name: '_MessStore.selectedMessModel', context: context); + late final _$mealDataAtom = + Atom(name: '_MessStore.mealData', context: context); @override - MessMenuModel? get selectedMessModel { - _$selectedMessModelAtom.reportRead(); - return super.selectedMessModel; + MealType get mealData { + _$mealDataAtom.reportRead(); + return super.mealData; } @override - set selectedMessModel(MessMenuModel? value) { - _$selectedMessModelAtom.reportWrite(value, super.selectedMessModel, () { - super.selectedMessModel = value; - }); - } - - late final _$allMessDataAtom = - Atom(name: '_MessStore.allMessData', context: context); - - @override - ObservableFuture> get allMessData { - _$allMessDataAtom.reportRead(); - return super.allMessData; - } - - @override - set allMessData(ObservableFuture> value) { - _$allMessDataAtom.reportWrite(value, super.allMessData, () { - super.allMessData = value; + set mealData(MealType value) { + _$mealDataAtom.reportWrite(value, super.mealData, () { + super.mealData = value; }); } @@ -134,11 +118,11 @@ mixin _$MessStore on _MessStore, Store { } @override - void setSelectedMessModel(MessMenuModel m) { + void setmealData(MealType m) { final _$actionInfo = _$_MessStoreActionController.startAction( - name: '_MessStore.setSelectedMessModel'); + name: '_MessStore.setmealData'); try { - return super.setSelectedMessModel(m); + return super.setmealData(m); } finally { _$_MessStoreActionController.endAction(_$actionInfo); } @@ -150,8 +134,7 @@ mixin _$MessStore on _MessStore, Store { selectedDay: ${selectedDay}, selectedMeal: ${selectedMeal}, selectedHostel: ${selectedHostel}, -selectedMessModel: ${selectedMessModel}, -allMessData: ${allMessData}, +mealData: ${mealData}, hostelLoaded: ${hostelLoaded} '''; } diff --git a/lib/stores/restaurant_store.dart b/lib/stores/restaurant_store.dart index d66e94ec..e4bc6e30 100644 --- a/lib/stores/restaurant_store.dart +++ b/lib/stores/restaurant_store.dart @@ -1,6 +1,4 @@ // ignore_for_file: library_private_types_in_public_api - -import 'package:fuzzy/fuzzy.dart'; import 'package:mobx/mobx.dart'; import 'package:onestop_dev/models/food/restaurant_model.dart'; import 'package:onestop_dev/services/data_provider.dart'; @@ -11,16 +9,15 @@ class RestaurantStore = _RestaurantStore with _$RestaurantStore; abstract class _RestaurantStore with Store { RestaurantModel _selectedRestaurant = RestaurantModel( - name: "NA", + outletName: "NA", caption: "NA", - closing_time: "NA", - waiting_time: "NA", - phone_number: "NA", + closingTime: "NA", + phoneNumber: "NA", latitude: 0, longitude: 0, - address: "NA", + location: "NA", tags: [], - image: ""); + imageURL: ""); @observable String _searchString = ""; @@ -45,7 +42,7 @@ abstract class _RestaurantStore with Store { @action void setSearchString(String str) { _searchString = str; - searchResults = ObservableFuture(executeFuzzySearch()); + searchResults = ObservableFuture(executeSearch()); _searchPageHeader = "Showing results for $str"; } @@ -54,26 +51,18 @@ abstract class _RestaurantStore with Store { _searchPageHeader = str; } - Future> executeFuzzySearch() async { + Future> executeSearch() async { List allRestaurants = await DataProvider.getRestaurants(); List searchResults = []; - for (var element in allRestaurants) { - List searchFields = element.tags; - for (var dish in element.menu) { - searchFields.add(dish.name); - } - final fuse = Fuzzy( - searchFields, - options: FuzzyOptions( - findAllMatches: false, - tokenize: false, - threshold: 0.4, - ), - ); - - final result = fuse.search(_searchString); - if (result.isNotEmpty) { - searchResults.add(element); + for (var restaurant in allRestaurants) { + if (restaurant.outletName.toLowerCase().contains(_searchString.toLowerCase())) { + searchResults.add(restaurant); + } else { + for (var dish in restaurant.menu) { + if (dish.itemName.toLowerCase().contains(_searchString.toLowerCase())) { + searchResults.add(restaurant); + } + } } } return searchResults; diff --git a/lib/stores/timetable_store.dart b/lib/stores/timetable_store.dart index 2df05264..5cddf623 100644 --- a/lib/stores/timetable_store.dart +++ b/lib/stores/timetable_store.dart @@ -22,6 +22,18 @@ abstract class _TimetableStore with Store { initialiseDates(); } + void setupReactions() { + autorun((_) { + if (loadOperation.value != null) { + processTimetable(); + } + }); + } + + //List of dates to show in the date slider + List dates = List.filled(5, DateTime.now()); + + //Initialising the dates void initialiseDates() { dates = List.filled(5, DateTime.now()); if (dates[0].weekday == 6 || dates[0].weekday == 7) { @@ -37,15 +49,7 @@ abstract class _TimetableStore with Store { } } - List dates = List.filled(5, DateTime.now()); - - List allTimetableCourses = - List.generate(5, (index) => TimetableDay()); - - @observable - ObservableFuture loadOperation = - ObservableFuture.value(null); - + //index of date slider item @observable int selectedDate = 0; @@ -54,17 +58,10 @@ abstract class _TimetableStore with Store { selectedDate = i; } + //Dropdown state of tt on home @observable bool showDropDown = false; - @action - Future setTimetable(String rollNumber) async { - if (loadOperation.value == null) { - loadOperation = - DataProvider.getTimeTable(roll: rollNumber).asObservable(); - } - } - @action void toggleDropDown() { showDropDown = !showDropDown; @@ -75,6 +72,64 @@ abstract class _TimetableStore with Store { showDropDown = b; } + List get homeTimeTable { + DateTime current = DateTime.now(); + if (current.weekday == 6 || current.weekday == 7) { + CourseModel noClass = CourseModel(); + noClass.instructor = ''; + noClass.course = 'Happy Weekend !'; + noClass.timing = ''; + return List.filled(1, TimetableTile(course: noClass)); + } + current = dates[0]; + DateFormat dateFormat = DateFormat("hh:00 - hh:55 a"); + List l = [ + ...allTimetableCourses[current.weekday - 1] + .morning + .where((e) => dateFormat.parse(e.timing).hour >= DateTime.now().hour) + .toList() + .map((e) => TimetableTile( + course: e, + inHomePage: true, + )) + .toList(), + ...allTimetableCourses[current.weekday - 1] + .afternoon + .where((e) => dateFormat.parse(e.timing).hour >= DateTime.now().hour) + .toList() + .map((e) => TimetableTile( + course: e, + inHomePage: true, + )) + .toList() + ]; + if (l.isEmpty) { + CourseModel noClass = CourseModel(); + noClass.instructor = ''; + noClass.course = 'No upcoming classes'; + noClass.timing = ''; + l.add(TimetableTile(course: noClass)); + } + return l; + } + + //List of time table of each day of the week + List allTimetableCourses = List.generate(5, (index) => TimetableDay()); + + + + @observable + ObservableFuture loadOperation = ObservableFuture.value(null); + + @action + Future setTimetable(String rollNumber,BuildContext context) async { + if (loadOperation.value == null) { + loadOperation = + DataProvider.getTimeTable(roll: rollNumber).asObservable(); + } + } + + @computed bool get coursesLoaded => loadOperation.value != null; @@ -115,58 +170,13 @@ abstract class _TimetableStore with Store { return l; } - List get homeTimeTable { - DateTime current = DateTime.now(); - if (current.weekday == 6 || current.weekday == 7) { - CourseModel noClass = CourseModel(); - noClass.instructor = ''; - noClass.course = 'Happy Weekend !'; - noClass.timing = ''; - return List.filled(1, TimetableTile(course: noClass)); - } - current = dates[0]; - DateFormat dateFormat = DateFormat("hh:00 - hh:55 a"); - List l = [ - ...allTimetableCourses[current.weekday - 1] - .morning - .where((e) => dateFormat.parse(e.timing).hour >= DateTime.now().hour) - .toList() - .map((e) => TimetableTile( - course: e, - inHomePage: true, - )) - .toList(), - ...allTimetableCourses[current.weekday - 1] - .afternoon - .where((e) => dateFormat.parse(e.timing).hour >= DateTime.now().hour) - .toList() - .map((e) => TimetableTile( - course: e, - inHomePage: true, - )) - .toList() - ]; - if (l.isEmpty) { - CourseModel noClass = CourseModel(); - noClass.instructor = ''; - noClass.course = 'No upcoming classes'; - noClass.timing = ''; - l.add(TimetableTile(course: noClass)); - } - return l; - } + void processTimetable() { - void setupReactions() { - autorun((_) { - if (loadOperation.value != null) { - processTimetable(); - } - }); - } + //A list of timetable of each day, with index 0 to 4 signifying mon to fri + List timetableCourses = List.generate(5, (index) => TimetableDay()); + + //Lets fill the above now - void processTimetable() { - List timetableCourses = - List.generate(5, (index) => TimetableDay()); var courseList = loadOperation.value!; for (int i = 0; i <= 4; i++) { for (var v in courseList.courses!) { @@ -175,53 +185,95 @@ abstract class _TimetableStore with Store { if (slot == 'A') { switch (i) { case 0: + copyCourse.timing = '08:00 - 08:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; case 1: - case 2: copyCourse.timing = '09:00 - 09:55 AM'; timetableCourses[i].addMorning(copyCourse); break; + case 2: + copyCourse.timing = '10:00 - 10:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; + case 3: + copyCourse.timing = '11:00 - 11:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; } } if (slot == 'B') { switch (i) { - case 3: - case 4: + case 0: copyCourse.timing = '09:00 - 09:55 AM'; timetableCourses[i].addMorning(copyCourse); break; - case 0: + case 1: copyCourse.timing = '10:00 - 10:55 AM'; timetableCourses[i].addMorning(copyCourse); break; + case 2: + copyCourse.timing = '11:00 - 11:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; + case 4: + copyCourse.timing = '08:00 - 08:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; } } if (slot == 'C') { switch (i) { + case 4: + copyCourse.timing = '09:00 - 09:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; + case 0: + copyCourse.timing = '10:00 - 10:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; case 1: - case 2: + copyCourse.timing = '11:00 - 11:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; case 3: - copyCourse.timing = '10:00 - 10:55 AM'; + copyCourse.timing = '08:00 - 08:55 AM'; timetableCourses[i].addMorning(copyCourse); break; } } if (slot == 'D') { switch (i) { + case 3: + copyCourse.timing = '09:00 - 09:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; case 4: copyCourse.timing = '10:00 - 10:55 AM'; timetableCourses[i].addMorning(copyCourse); break; case 0: - case 1: copyCourse.timing = '11:00 - 11:55 AM'; timetableCourses[i].addMorning(copyCourse); + break; + case 2: + copyCourse.timing = '08:00 - 08:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; } } if (slot == 'E') { switch (i) { case 2: + copyCourse.timing = '09:00 - 09:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; case 3: - copyCourse.timing = '11:00 - 11:55 AM'; + copyCourse.timing = '10:00 - 10:55 AM'; + timetableCourses[i].addMorning(copyCourse); + break; + case 1: + copyCourse.timing = '08:00 - 08:55 AM'; timetableCourses[i].addMorning(copyCourse); break; } @@ -237,11 +289,12 @@ abstract class _TimetableStore with Store { copyCourse.timing = '11:00 - 11:55 AM'; timetableCourses[i].addMorning(copyCourse); break; + } } if (slot == 'G') { switch (i) { - case 2: + case 5: case 3: case 4: copyCourse.timing = '12:00 - 12:55 PM'; @@ -252,8 +305,18 @@ abstract class _TimetableStore with Store { if (slot == 'A1') { switch (i) { case 0: + copyCourse.timing = '05:00 - 05:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; case 1: + copyCourse.timing = '04:00 - 04:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; case 2: + copyCourse.timing = '03:00 - 03:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; + case 3: copyCourse.timing = '02:00 - 02:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; @@ -261,58 +324,89 @@ abstract class _TimetableStore with Store { } if (slot == 'B1') { switch (i) { - case 3: case 4: - copyCourse.timing = '02:00 - 02:55 PM'; + copyCourse.timing = '05:00 - 05:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; case 0: + copyCourse.timing = '04:00 - 04:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; + case 1: copyCourse.timing = '03:00 - 03:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; + case 2: + copyCourse.timing = '02:00 - 02:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; } } if (slot == 'C1') { switch (i) { - case 1: - case 2: case 3: + copyCourse.timing = '05:00 - 05:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; + case 4: + copyCourse.timing = '04:00 - 04:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; + case 0: copyCourse.timing = '03:00 - 03:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; + case 1: + copyCourse.timing = '02:00 - 02:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; } } if (slot == 'D1') { switch (i) { + case 2: + copyCourse.timing = '05:00 - 05:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; + case 3: + copyCourse.timing = '04:00 - 04:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; case 4: copyCourse.timing = '03:00 - 03:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; case 0: - case 1: - copyCourse.timing = '04:00 - 04:55 PM'; + copyCourse.timing = '02:00 - 02:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; } } if (slot == 'E1') { switch (i) { + case 1: + copyCourse.timing = '05:00 - 05:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; case 2: - case 3: copyCourse.timing = '04:00 - 04:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; + case 3: + copyCourse.timing = '03:00 - 03:55 PM'; + timetableCourses[i].addAfternoon(copyCourse); + break; } } if (slot == 'F1') { switch (i) { case 0: case 1: - copyCourse.timing = '05:00 - 05:55 PM'; + copyCourse.timing = '01:00 - 01:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; case 4: - copyCourse.timing = '04:00 - 04:55 PM'; + copyCourse.timing = '02:00 - 02:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; } @@ -322,14 +416,14 @@ abstract class _TimetableStore with Store { case 2: case 3: case 4: - copyCourse.timing = '05:00 - 05:55 PM'; + copyCourse.timing = '01:00 - 01:55 PM'; timetableCourses[i].addAfternoon(copyCourse); break; } } if (slot == 'c') { switch (i) { - case 0: + case 3: copyCourse.timing = '08:00 - 08:55 AM'; timetableCourses[i].addMorning(copyCourse); break; @@ -345,7 +439,7 @@ abstract class _TimetableStore with Store { } if (slot == 'b') { switch (i) { - case 2: + case 4: copyCourse.timing = '08:00 - 08:55 AM'; timetableCourses[i].addMorning(copyCourse); break; @@ -353,7 +447,7 @@ abstract class _TimetableStore with Store { } if (slot == 'd') { switch (i) { - case 3: + case 2: copyCourse.timing = '08:00 - 08:55 AM'; timetableCourses[i].addMorning(copyCourse); break; @@ -361,7 +455,7 @@ abstract class _TimetableStore with Store { } if (slot == 'a') { switch (i) { - case 4: + case 0: copyCourse.timing = '08:00 - 08:55 AM'; timetableCourses[i].addMorning(copyCourse); break; @@ -391,7 +485,6 @@ abstract class _TimetableStore with Store { break; } } - if (slot == 'ML4') { switch (i) { case 3: @@ -449,8 +542,8 @@ abstract class _TimetableStore with Store { } } } - timetableCourses[i].morning.sort(); - timetableCourses[i].afternoon.sort(); + timetableCourses[i].morning.sort(((a, b) => a.timing.compareTo(b.timing))); + timetableCourses[i].afternoon.sort((a,b)=> a.timing.compareTo(b.timing)); } allTimetableCourses = timetableCourses; } diff --git a/lib/stores/timetable_store.g.dart b/lib/stores/timetable_store.g.dart index 4d469d14..8aaf0d68 100644 --- a/lib/stores/timetable_store.g.dart +++ b/lib/stores/timetable_store.g.dart @@ -38,22 +38,6 @@ mixin _$TimetableStore on _TimetableStore, Store { name: '_TimetableStore.todayTimeTable')) .value; - late final _$loadOperationAtom = - Atom(name: '_TimetableStore.loadOperation', context: context); - - @override - ObservableFuture get loadOperation { - _$loadOperationAtom.reportRead(); - return super.loadOperation; - } - - @override - set loadOperation(ObservableFuture value) { - _$loadOperationAtom.reportWrite(value, super.loadOperation, () { - super.loadOperation = value; - }); - } - late final _$selectedDateAtom = Atom(name: '_TimetableStore.selectedDate', context: context); @@ -86,12 +70,29 @@ mixin _$TimetableStore on _TimetableStore, Store { }); } + late final _$loadOperationAtom = + Atom(name: '_TimetableStore.loadOperation', context: context); + + @override + ObservableFuture get loadOperation { + _$loadOperationAtom.reportRead(); + return super.loadOperation; + } + + @override + set loadOperation(ObservableFuture value) { + _$loadOperationAtom.reportWrite(value, super.loadOperation, () { + super.loadOperation = value; + }); + } + late final _$setTimetableAsyncAction = AsyncAction('_TimetableStore.setTimetable', context: context); @override - Future setTimetable(String rollNumber) { - return _$setTimetableAsyncAction.run(() => super.setTimetable(rollNumber)); + Future setTimetable(String rollNumber, BuildContext context) { + return _$setTimetableAsyncAction + .run(() => super.setTimetable(rollNumber, context)); } late final _$_TimetableStoreActionController = @@ -133,9 +134,9 @@ mixin _$TimetableStore on _TimetableStore, Store { @override String toString() { return ''' -loadOperation: ${loadOperation}, selectedDate: ${selectedDate}, showDropDown: ${showDropDown}, +loadOperation: ${loadOperation}, coursesLoaded: ${coursesLoaded}, coursesLoading: ${coursesLoading}, coursesError: ${coursesError}, diff --git a/lib/stores/travel_store.dart b/lib/stores/travel_store.dart index 797fb50b..870731d6 100644 --- a/lib/stores/travel_store.dart +++ b/lib/stores/travel_store.dart @@ -2,7 +2,8 @@ import 'package:flutter/material.dart'; import 'package:mobx/mobx.dart'; -import 'package:onestop_dev/models/travel/ferry_data_model.dart'; +import 'package:onestop_dev/models/travel/travel_timing_model.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:onestop_dev/widgets/travel/bus_details.dart'; import 'package:onestop_dev/widgets/travel/stops_list.dart'; @@ -28,8 +29,11 @@ abstract class _TravelStore with Store { String selectedFerryGhat = "Mazgaon"; @observable - ObservableFuture> ferryTimings = - ObservableFuture(DataProvider.getFerryTimings()); + ObservableFuture> ferryTimings = + // ObservableFuture(APIService().getFerryTiming()); + ObservableFuture(DataProvider.getFerryTiming()); + + @action void setFerryDayType(String s) { @@ -101,4 +105,4 @@ abstract class _TravelStore with Store { void setFerryGhat(String s) { selectedFerryGhat = s; } -} +} \ No newline at end of file diff --git a/lib/stores/travel_store.g.dart b/lib/stores/travel_store.g.dart index 5c606896..e93f4fdd 100644 --- a/lib/stores/travel_store.g.dart +++ b/lib/stores/travel_store.g.dart @@ -121,13 +121,13 @@ mixin _$TravelStore on _TravelStore, Store { Atom(name: '_TravelStore.ferryTimings', context: context); @override - ObservableFuture> get ferryTimings { + ObservableFuture> get ferryTimings { _$ferryTimingsAtom.reportRead(); return super.ferryTimings; } @override - set ferryTimings(ObservableFuture> value) { + set ferryTimings(ObservableFuture> value) { _$ferryTimingsAtom.reportWrite(value, super.ferryTimings, () { super.ferryTimings = value; }); diff --git a/lib/widgets/contact/contact_page_button.dart b/lib/widgets/contact/contact_page_button.dart index 832bea10..3614e8ca 100644 --- a/lib/widgets/contact/contact_page_button.dart +++ b/lib/widgets/contact/contact_page_button.dart @@ -47,11 +47,14 @@ class _ContactPageButtonState extends State { flex: 106, child: GestureDetector( onTap: () { - var contact = people['Gymkhana']; - if (widget.label == "Emergency") { - contact = people['Emergency']; - } else if (widget.label == 'Transport') { - contact = people['Transport']; + ContactModel contact = ContactModel(sectionName: widget.label, contacts: []); //case when section is not in db + if(widget.label=="Gymkhana" && people['Gymkhana']!=null){ + contact=people['Gymkhana']!; + } + else if (widget.label == "Emergency" && people['Emergency']!=null) { + contact = people['Emergency']!; + } else if (widget.label == 'Transport' && people['Transport']!=null) { + contact = people['Transport']!; } Navigator.push(context, MaterialPageRoute(builder: (context) { return Provider.value( diff --git a/lib/widgets/food/mess/mess_meal.dart b/lib/widgets/food/mess/mess_meal.dart index dcd2f477..1ddb14ab 100644 --- a/lib/widgets/food/mess/mess_meal.dart +++ b/lib/widgets/food/mess/mess_meal.dart @@ -4,15 +4,12 @@ import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; import 'package:onestop_dev/stores/mess_store.dart'; import 'package:provider/provider.dart'; - class MessMeal extends StatelessWidget { const MessMeal({ Key? key, required this.mealName, }) : super(key: key); - final String mealName; - @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; @@ -36,11 +33,11 @@ class MessMeal extends StatelessWidget { mealName, style: selected ? MyFonts.w500 - .size(screenWidth <= 380 ? 13 : 14) - .setColor(kBlueGrey) + .size(screenWidth <= 380 ? 13 : 14) + .setColor(kBlueGrey) : MyFonts.w500 - .size(screenWidth <= 380 ? 13 : 14) - .setColor(const Color.fromRGBO(91, 146, 227, 1)), + .size(screenWidth <= 380 ? 13 : 14) + .setColor(const Color.fromRGBO(91, 146, 227, 1)), ), ); }), @@ -48,4 +45,4 @@ class MessMeal extends StatelessWidget { ), ); } -} +} \ No newline at end of file diff --git a/lib/widgets/food/mess/mess_menu.dart b/lib/widgets/food/mess/mess_menu.dart index 632b60a5..2acf8987 100644 --- a/lib/widgets/food/mess/mess_menu.dart +++ b/lib/widgets/food/mess/mess_menu.dart @@ -1,6 +1,7 @@ import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:intl/intl.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; import 'package:onestop_dev/stores/mess_store.dart'; @@ -12,12 +13,12 @@ class MessMenu extends StatelessWidget { Key? key, }) : super(key: key); - final List days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + final List days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; final List hostels = [ "Kameng", "Barak", "Lohit", - "Brahma", + "Brahmaputra", "Disang", "Manas", "Dihing", @@ -49,12 +50,13 @@ class MessMenu extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: const [ + children: [ MessMeal(mealName: "Breakfast"), MessMeal(mealName: "Lunch"), MessMeal(mealName: "Dinner") ], - )), + ) + ), const SizedBox( width: 16, ), @@ -73,7 +75,7 @@ class MessMenu extends StatelessWidget { Expanded( flex: 1, child: Text( - messStore.selectedMessModel?.timing ?? "", + messStore.mealData.id.isEmpty ? "Not Specified" : "${DateFormat.jm().format(messStore.mealData.startTiming)} - ${DateFormat.jm().format(messStore.mealData.endTiming)}", // id empty means not updated by HMC style: MyFonts.w500.size(12).setColor(kGrey12), ), ), @@ -81,7 +83,7 @@ class MessMenu extends StatelessWidget { flex: 4, child: SingleChildScrollView( child: Text( - messStore.selectedMessModel?.menu ?? "", + messStore.mealData.mealDescription, style: MyFonts.w400 .size(14) .setColor(kWhite)))), @@ -98,15 +100,15 @@ class MessMenu extends StatelessWidget { return days .map( (value) => PopupMenuItem( - onTap: () { - messStore.setDay(value); - }, - value: value, - child: Text(value, - style: MyFonts.w500 - .setColor(kWhite)), - ), - ) + onTap: () { + messStore.setDay(value); + }, + value: value, + child: Text(value.substring(0,3), + style: MyFonts.w500 + .setColor(kWhite)), + ), + ) .toList(); }, offset: const Offset(1, 40), @@ -119,19 +121,19 @@ class MessMenu extends StatelessWidget { Radius.circular(20))), child: Row( mainAxisAlignment: - MainAxisAlignment.spaceAround, + MainAxisAlignment.spaceAround, mainAxisSize: MainAxisSize.min, children: [ - Text(messStore.selectedDay, + Text(messStore.selectedDay.substring(0,3), style: MyFonts.w500 .setColor(lBlue) - .size(screenWidth <= 380 - ? 10 - : 13)), + .size(screenWidth <= 390 + ? 10 + : 13)), Icon( FluentIcons.chevron_down_24_regular, color: lBlue, - size: screenWidth <= 380 ? 15 : 20, + size: screenWidth <= 390 ? 15 : 20, ), ], ), @@ -143,22 +145,23 @@ class MessMenu extends StatelessWidget { .copyWith(cardColor: kBlueGrey), child: PopupMenuButton( constraints: - const BoxConstraints(maxHeight: 320), + const BoxConstraints(maxHeight: 320), itemBuilder: (context) { return hostels .map( (value) => PopupMenuItem( - onTap: () { - messStore.setHostel(value); - }, - value: value, - child: Text( - value, - style: MyFonts.w500 - .setColor(kWhite), - ), - ), - ) + onTap: () { + messStore.setHostel(value); + + }, + value: value, + child: Text( + value, + style: MyFonts.w500 + .setColor(kWhite), + ), + ), + ) .toList(); }, offset: const Offset(1, 40), @@ -171,19 +174,20 @@ class MessMenu extends StatelessWidget { Radius.circular(20))), child: Row( mainAxisAlignment: - MainAxisAlignment.spaceAround, + MainAxisAlignment.spaceAround, mainAxisSize: MainAxisSize.min, children: [ Text(messStore.selectedHostel.value!, + overflow: TextOverflow.fade, style: MyFonts.w500 .setColor(lBlue) - .size(screenWidth <= 380 - ? 10 - : 13)), + .size(screenWidth <= 390 + ? 10 + : 13)), Icon( FluentIcons.chevron_down_24_regular, color: lBlue, - size: screenWidth <= 380 ? 15 : 20, + size: screenWidth <= 390 ? 15 : 20, ), ], ), diff --git a/lib/widgets/food/restaurant/food_tile.dart b/lib/widgets/food/restaurant/food_tile.dart index 6594d925..09580af3 100644 --- a/lib/widgets/food/restaurant/food_tile.dart +++ b/lib/widgets/food/restaurant/food_tile.dart @@ -47,42 +47,42 @@ class FoodTile extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - Row( - children: [ - Expanded( - flex: 4, - child: Text( - dish.name, - style: MyFonts.w600.size(16).setColor(kWhite), - ), - ), - Expanded( - flex: 1, - child: Stack( - alignment: Alignment.center, - children: [ - Icon( - Icons.crop_square_sharp, - color: getIconColor(dish.veg), - size: 14, - ), - Icon( - Icons.circle, - color: getIconColor(dish.veg), - size: 5, - ), - ], - ), - ), - ], + Text( + dish.itemName, + style: MyFonts.w600.size(16).setColor(kWhite), ), + // Row( + // children: [ + // Expanded( + // flex: 4, + // child: Text( + // dish.itemName, + // style: MyFonts.w600.size(16).setColor(kWhite), + // ), + // ), + // Expanded( + // flex: 1, + // child: Stack( + // alignment: Alignment.center, + // children: [ + // Icon( + // Icons.crop_square_sharp, + // color: getIconColor(dish.veg), + // size: 14, + // ), + // Icon( + // Icons.circle, + // color: getIconColor(dish.veg), + // size: 5, + // ), + // ], + // ), + // ), + // ], + // ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - getIngredients(dish.ingredients), - style: MyFonts.w400.size(14).setColor(kGrey6), - ), const SizedBox( height: 8, ), @@ -106,7 +106,7 @@ class FoodTile extends StatelessWidget { aspectRatio: 1, child: CachedNetworkImage( maxHeightDiskCache: 200, - imageUrl: dish.image, + imageUrl: dish.imageURL, imageBuilder: (context, imageProvider) => Image( image: imageProvider, fit: BoxFit.cover, diff --git a/lib/widgets/food/restaurant/restaurant_header.dart b/lib/widgets/food/restaurant/restaurant_header.dart index 2ab4fecf..d314c789 100644 --- a/lib/widgets/food/restaurant/restaurant_header.dart +++ b/lib/widgets/food/restaurant/restaurant_header.dart @@ -29,7 +29,7 @@ class RestaurantHeader extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - restaurant.name, + restaurant.outletName, style: MyFonts.w600.size(22).setColor(kWhite), ), Text( @@ -40,7 +40,7 @@ class RestaurantHeader extends StatelessWidget { padding: const EdgeInsets.only(top: 10.0, bottom: 8.0), child: RichText( text: TextSpan( - text: restaurant.address, + text: restaurant.location, style: MyFonts.w500.size(13).setColor(kGrey), children: [ TextSpan( @@ -68,10 +68,6 @@ class RestaurantHeader extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - Text( - 'Waiting time: ${restaurant.waiting_time}', - style: MyFonts.w300.size(12).setColor(kWhite), - ), const Padding( padding: EdgeInsets.symmetric(horizontal: 5.0), child: Icon(FluentIcons.circle_12_filled, @@ -86,7 +82,7 @@ class RestaurantHeader extends StatelessWidget { width: 4, ), Text( - 'Closing time: ${restaurant.closing_time}', + 'Closing time: ${restaurant.closingTime}', style: MyFonts.w300.size(12).setColor(lRed2), ), ], @@ -112,7 +108,7 @@ class RestaurantHeader extends StatelessWidget { callMap: 'Call', icon: FluentIcons.call_24_regular, callback: () { - launchPhoneURL(restaurant.phone_number); + launchPhoneURL(restaurant.phoneNumber); }, ), ), @@ -126,7 +122,7 @@ class RestaurantHeader extends StatelessWidget { icon: FluentIcons.location_24_regular, callback: () { openMap(restaurant.latitude, restaurant.longitude, - context, restaurant.name); + context, restaurant.outletName); }, ), ), diff --git a/lib/widgets/food/restaurant/restaurant_tile.dart b/lib/widgets/food/restaurant/restaurant_tile.dart index 6d9289c9..76638b19 100644 --- a/lib/widgets/food/restaurant/restaurant_tile.dart +++ b/lib/widgets/food/restaurant/restaurant_tile.dart @@ -7,6 +7,7 @@ import 'package:onestop_dev/functions/utility/open_map.dart'; import 'package:onestop_dev/functions/utility/phone_email.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/globals/size_config.dart'; import 'package:onestop_dev/models/food/restaurant_model.dart'; import 'package:onestop_dev/pages/food/restaurant_page.dart'; import 'package:onestop_dev/stores/restaurant_store.dart'; @@ -22,6 +23,7 @@ class RestaurantTile extends StatelessWidget { @override Widget build(BuildContext context) { + print(restaurantModel.imageURL); return TextButton( onPressed: () { context.read().setSelectedRestaurant(restaurantModel); @@ -50,7 +52,7 @@ class RestaurantTile extends StatelessWidget { aspectRatio: 1, child: CachedNetworkImage( maxHeightDiskCache: 200, - imageUrl: restaurantModel.image, + imageUrl: restaurantModel.imageURL, imageBuilder: (context, imageProvider) => Image( image: imageProvider, fit: BoxFit.cover, @@ -71,7 +73,7 @@ class RestaurantTile extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - restaurantModel.name, + restaurantModel.outletName, textAlign: TextAlign.left, style: MyFonts.w600.size(16).setColor(kWhite), ), @@ -83,14 +85,7 @@ class RestaurantTile extends StatelessWidget { height: 8, ), Text( - 'Waiting time: ${restaurantModel.waiting_time}', - style: MyFonts.w500.size(11).setColor(kTabText), - ), - const SizedBox( - height: 1, - ), - Text( - 'Closes at ${restaurantModel.closing_time}', + 'Closes at ${restaurantModel.closingTime}', style: MyFonts.w500.size(11).setColor(lRed2), ), const SizedBox( @@ -102,7 +97,7 @@ class RestaurantTile extends StatelessWidget { callMap: 'Call', icon: FluentIcons.call_20_regular, callback: () { - launchPhoneURL(restaurantModel.phone_number); + launchPhoneURL(restaurantModel.phoneNumber); }, ), const SizedBox( @@ -116,13 +111,17 @@ class RestaurantTile extends StatelessWidget { restaurantModel.latitude, restaurantModel.longitude, context, - restaurantModel.name); + restaurantModel.outletName); }, ), Expanded(child: Container()), - Text( - getRestaurantDistance(context, restaurantModel), - style: MyFonts.w500.size(11).setColor(kWhite), + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 55), + child: Text( + getRestaurantDistance(context, restaurantModel), + textAlign: TextAlign.center, + style: MyFonts.w500.size(11).setColor(kWhite) + ), ), Expanded(child: Container()), ], diff --git a/lib/widgets/home/date_course.dart b/lib/widgets/home/date_course.dart index f602b170..d952fdd1 100644 --- a/lib/widgets/home/date_course.dart +++ b/lib/widgets/home/date_course.dart @@ -3,6 +3,7 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:onestop_dev/globals/days.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/stores/login_store.dart'; import 'package:onestop_dev/stores/timetable_store.dart'; import 'package:onestop_dev/widgets/timetable/dropdown_arrow.dart'; import 'package:onestop_dev/widgets/timetable/home_shimmer.dart'; diff --git a/lib/widgets/home/service_links.dart b/lib/widgets/home/service_links.dart index da1f0976..8f6d09ca 100644 --- a/lib/widgets/home/service_links.dart +++ b/lib/widgets/home/service_links.dart @@ -33,11 +33,11 @@ List serviceLinks = [ label: "Cab Sharing", icon: FluentIcons.vehicle_bus_24_regular, routeId: CabShare.id), - const HomeTabTile( - label: "GC Score Board", - icon: FluentIcons.trophy_20_regular, - routeId: Scoreboard.id, - ), + // const HomeTabTile( + // label: "GC Score Board", + // icon: FluentIcons.trophy_20_regular, + // routeId: Scoreboard.id, + // ), const HomeTabTile( label: "UPSP", icon: FluentIcons.chat_warning_16_regular, diff --git a/lib/widgets/login/login_button.dart b/lib/widgets/login/login_button.dart index 1aa1a203..86e55702 100644 --- a/lib/widgets/login/login_button.dart +++ b/lib/widgets/login/login_button.dart @@ -9,10 +9,10 @@ import 'package:provider/provider.dart'; class LoginButton extends StatelessWidget { const LoginButton({ Key? key, - required this.setLoading, + // required this.setLoading, }) : super(key: key); - final Function setLoading; + // final Function setLoading; @override Widget build(BuildContext context) { @@ -32,7 +32,10 @@ class LoginButton extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(18))), onPressed: () { - setLoading(); + // setLoading(); + Navigator.of(context).pushNamed( + '/login', + ); }, child: FittedBox( fit: BoxFit.fitWidth, @@ -59,6 +62,7 @@ class LoginButton extends StatelessWidget { ..onTap = () async { await context.read().signInAsGuest(); // TODO: Next version of Flutter will have context.mounted. Use that instead to escape the lint + print("completed sign in"); Navigator.of(context).pushNamedAndRemoveUntil( '/', (Route route) => false); }, diff --git a/lib/widgets/login/login_webview.dart b/lib/widgets/login/login_webview.dart index 0c19a8f5..7fa7f25e 100644 --- a/lib/widgets/login/login_webview.dart +++ b/lib/widgets/login/login_webview.dart @@ -1,5 +1,11 @@ import 'dart:async'; +import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:onestop_dev/globals/database_strings.dart'; +import 'package:onestop_dev/globals/endpoints.dart'; +import 'package:onestop_dev/models/profile/profile_model.dart'; +import 'package:onestop_dev/pages/profile/edit_profile.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/stores/login_store.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -23,7 +29,7 @@ class _LoginWebViewState extends State { @override Widget build(BuildContext context) { return WebView( - initialUrl: "https://swc.iitg.ac.in/onestopapi/v2/auth/microsoft", + initialUrl: "${Endpoints.baseUrl}/auth/microsoft", javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (controller) { widget._controller.complete(controller); @@ -31,24 +37,25 @@ class _LoginWebViewState extends State { onWebResourceError: (context) {}, onPageFinished: (url) async { if (url.startsWith( - "https://swc.iitg.ac.in/onestopapi/v2/auth/microsoft/redirect?code")) { + "${Endpoints.baseUrl}/auth/microsoft/redirect?code")) { WebViewController controller = await widget._controller.future; - var userInfoString = await controller.runJavascriptReturningResult("document.querySelector('#userInfo').innerText"); - var userInfo = {}; - List values = userInfoString.replaceAll('"', '').split("/"); - if (!values[0].toLowerCase().contains("error")) { - userInfo["displayName"] = values[0]; - userInfo["mail"] = values[1]; - userInfo["surname"] = values[2]; - userInfo["id"] = values[3]; + var userTokensString = await controller.runJavascriptReturningResult("document.querySelector('#userTokens').innerText"); + print("TOKENS STRING"); + userTokensString=userTokensString.replaceAll('"', ''); + print(userTokensString); + if (userTokensString!="ERROR OCCURED") { SharedPreferences user = await SharedPreferences.getInstance(); if (!mounted) return; - context.read().saveToPreferences(user, userInfo); - context.read().saveToUserData(user); + Map userTokens = {BackendHelper.accesstoken: userTokensString.split('/')[0],BackendHelper.refreshtoken: userTokensString.split('/')[1]}; + print(userTokens); + await context.read().saveToPreferences(user, userTokens); + await context.read().saveToUserInfo(user); await WebviewCookieManager().clearCookies(); - Navigator.of(context) - .pushNamedAndRemoveUntil('/', (Route route) => false); + print("its here"); + Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) => EditProfile(profileModel: ProfileModel.fromJson(LoginStore.userData),)), (route) => false); + // Navigator.of(context) + // .pushNamedAndRemoveUntil('/', (Route route) => false); } } }, diff --git a/lib/widgets/lostfound/ads_tile.dart b/lib/widgets/lostfound/ads_tile.dart index cd60b37e..856340f9 100644 --- a/lib/widgets/lostfound/ads_tile.dart +++ b/lib/widgets/lostfound/ads_tile.dart @@ -1,6 +1,7 @@ import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; import 'package:onestop_dev/functions/food/rest_frame_builder.dart'; +import 'package:onestop_dev/functions/utility/show_snackbar.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; import 'package:onestop_dev/models/lostfound/found_model.dart'; @@ -169,20 +170,16 @@ class _MyAdsTileState extends State { ), onPressed: () async { if (isLnf) { - await APIService.deleteLnfMyAd( + await APIService().deleteLnfMyAd( widget.model.id, widget.model.email); } else { - await APIService.deleteBnsMyAd( + await APIService().deleteBnsMyAd( widget.model.id, widget.model.email); } if (!mounted) return; Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text( - "Deleted your post successfully", - style: MyFonts.w500, - ))); + showSnackBar("Deleted your post successfully"); }, ), ), diff --git a/lib/widgets/lostfound/claim_call_button.dart b/lib/widgets/lostfound/claim_call_button.dart index decd5ca2..67585c4a 100644 --- a/lib/widgets/lostfound/claim_call_button.dart +++ b/lib/widgets/lostfound/claim_call_button.dart @@ -48,10 +48,10 @@ class _ClaimCallButtonState extends State { } buttonPressed = true; var name = - context.read().userData['name']; + LoginStore.userData['name']; var email = - context.read().userData['email']; - var body = await APIService.claimFoundItem( + LoginStore.userData['outlookEmail']; + var body = await APIService().claimFoundItem( name: name!, email: email!, id: widget.model.id); @@ -69,9 +69,7 @@ class _ClaimCallButtonState extends State { ModalRoute.withName(LostFoundHome.id)); } else { widget.model.claimed = true; - widget.model.claimerEmail = context - .read() - .userData["email"]!; + widget.model.claimerEmail = LoginStore.userData["outlookEmail"]!; Navigator.popUntil(context, ModalRoute.withName(LostFoundHome.id)); ScaffoldMessenger.of(widget.parentContext) @@ -142,7 +140,7 @@ class _ClaimCallButtonState extends State { ) : Text( widget.model.claimerEmail == - context.read().userData["email"] + LoginStore.userData["outlookEmail"] ? " You claimed" : " Already Claimed", style: MyFonts.w500.size(11).setColor(lBlue2), diff --git a/lib/widgets/mapbox/carousel_card.dart b/lib/widgets/mapbox/carousel_card.dart index 71af3353..656a9310 100644 --- a/lib/widgets/mapbox/carousel_card.dart +++ b/lib/widgets/mapbox/carousel_card.dart @@ -5,6 +5,8 @@ import 'package:onestop_dev/functions/food/get_day.dart'; import 'package:onestop_dev/functions/travel/next_time.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/models/travel/travel_timing_model.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:onestop_dev/stores/mapbox_store.dart'; import 'package:provider/provider.dart'; @@ -18,39 +20,60 @@ class CarouselCard extends StatelessWidget { @override Widget build(BuildContext context) { - Future getNextTime() async { + Future getNextTime() async { String today = getFormattedDay(); if (context.read().indexBusesorFerry == 0) { - var allBusTimes = await DataProvider.getBusTimings(); - List> busTimes = [[], []]; - allBusTimes.forEach((key, list) { - for (String time in list[0]) { - busTimes[0].add(time); + // List allBusTimes = await APIService().getBusTiming(); + List allBusTimes = await DataProvider.getBusTiming(); + List weekdaysTimes= []; + List weekendTimes=[]; + for(var xyz in allBusTimes){ + int n=xyz.weekdays.fromCampus.length; + for(int i=0;i a.compareTo(b)); + for(var xyz in allBusTimes){ + int n=xyz.weekend.fromCampus.length; + for(int i=0;i parseTime(a).compareTo(parseTime(b))); - busTimes[1].sort((a, b) => parseTime(a).compareTo(parseTime(b))); + } + weekendTimes.sort((a, b) => a.compareTo(b)); + if (today == 'Fri') { - return 'Next Bus at: ${nextTime(busTimes[1], firstTime: busTimes[0][0])}'; + return 'Next Bus at: ${nextTime(weekdaysTimes, firstTime: weekendTimes[0].toString())}'; } else if (today == 'Sun') { - return 'Next Bus at: ${nextTime(busTimes[0], firstTime: busTimes[1][0])}'; + return 'Next Bus at: ${nextTime(weekendTimes, firstTime: weekdaysTimes[0].toString())}'; } else if (today == 'Sat') { - return 'Next Bus at: ${nextTime(busTimes[0])}'; + return 'Next Bus at: ${nextTime(weekendTimes)}'; } - return 'Next Bus at: ${nextTime(busTimes[1])}'; + return 'Next Bus at: ${nextTime(weekdaysTimes)}'; } else { - var ferryTimes = await DataProvider.getFerryTimings(); - var requiredModel = - ferryTimes.firstWhere((element) => element.name == name); + // List ferryTimings = await APIService().getFerryTiming(); + List ferryTimings = await DataProvider.getFerryTiming(); + List weekdaysTimes= []; + List weekendTimes=[]; + TravelTiming requiredModel = + ferryTimings.firstWhere((element) => element.stop == name); + + int n=requiredModel.weekdays.fromCampus.length; + for(int i=0;i a.compareTo(b)); + int p=requiredModel.weekend.fromCampus.length; + for(int i=0;i a.compareTo(b)); if (today == 'Sat') { - return 'Next Ferry at: ${nextTime(requiredModel.MonToFri_NorthGuwahatiToGuwahati, firstTime: requiredModel.Sunday_NorthGuwahatiToGuwahati[0])}'; + return 'Next Ferry at: ${nextTime(weekdaysTimes, firstTime: weekendTimes[0].toString())}'; } else if (today == 'Sun') { - return 'Next Ferry at: ${nextTime(requiredModel.Sunday_NorthGuwahatiToGuwahati, firstTime: requiredModel.MonToFri_NorthGuwahatiToGuwahati[0])}'; + return 'Next Ferry at: ${nextTime(weekendTimes, firstTime: weekdaysTimes[0].toString())}'; } - return 'Next Ferry at: ${nextTime(requiredModel.MonToFri_NorthGuwahatiToGuwahati)}'; + return 'Next Ferry at: ${nextTime(weekdaysTimes)}'; } } @@ -63,9 +86,9 @@ class CarouselCard extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(20)), border: Border.all( color: - (context.read().selectedCarouselIndex == index) - ? lBlue5 - : kTileBackground), + (context.read().selectedCarouselIndex == index) + ? lBlue5 + : kTileBackground), ), child: Padding( padding: const EdgeInsets.all(10.0), diff --git a/lib/widgets/mapbox/map_box.dart b/lib/widgets/mapbox/map_box.dart index 86cad3b2..bd6c837e 100644 --- a/lib/widgets/mapbox/map_box.dart +++ b/lib/widgets/mapbox/map_box.dart @@ -26,7 +26,6 @@ class MapBox extends StatefulWidget { DateTime now = DateTime.now(); String formattedTime = DateFormat.jm().format(now); - class _MapBoxState extends State { String mapString = ''; late GoogleMapController controller; @@ -58,9 +57,9 @@ class _MapBoxState extends State { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - "Could not fetch your current location", - style: MyFonts.w500, - ))); + "Could not fetch your current location", + style: MyFonts.w500, + ))); return const LatLng(26.192613073419974, 91.69907177061708); } return coordinates; @@ -92,7 +91,7 @@ class _MapBoxState extends State { gestureRecognizers: < Factory>{ Factory( - () => EagerGestureRecognizer()) + () => EagerGestureRecognizer()) }, onMapCreated: (mapcontroller) { controller = mapcontroller; @@ -272,7 +271,7 @@ class _MapBoxState extends State { await availableMap.showDirections( originTitle: 'User Location', destinationTitle: - mapStore.selectedCarouselName, + mapStore.selectedCarouselName, directionsMode: DirectionsMode.walking, destination: Coords( mapStore @@ -285,10 +284,10 @@ class _MapBoxState extends State { if (!mounted) return; ScaffoldMessenger.of(context) .showSnackBar(SnackBar( - content: Text( - "Could not open map.", - style: MyFonts.w500, - ))); + content: Text( + "Could not open map.", + style: MyFonts.w500, + ))); } }, mini: true, @@ -319,37 +318,37 @@ class _MapBoxState extends State { ), (!mapStore.isTravelPage) ? Observer(builder: (context) { - return CarouselSlider( - items: mapStore.carouselCards - .map((e) => GestureDetector( - child: mapStore.selectedCarouselIndex == - (e as CarouselCard).index - ? e - : ColorFiltered( - colorFilter: ColorFilter.mode( - Colors.grey.shade600, - BlendMode.modulate), - child: e, - ), - onTap: () { - mapStore.selectedCarousel(e.index); - mapStore.zoomTwoMarkers( - mapStore.selectedCarouselLatLng, - LatLng(mapStore.userlat, - mapStore.userlong), - 120.0); - }, - )) - .toList(), - options: CarouselOptions( - height: 100, - viewportFraction: 0.7, - initialPage: 0, - enableInfiniteScroll: false, - scrollDirection: Axis.horizontal, - ), - ); - }) + return CarouselSlider( + items: mapStore.carouselCards + .map((e) => GestureDetector( + child: mapStore.selectedCarouselIndex == + (e as CarouselCard).index + ? e + : ColorFiltered( + colorFilter: ColorFilter.mode( + Colors.grey.shade600, + BlendMode.modulate), + child: e, + ), + onTap: () { + mapStore.selectedCarousel(e.index); + mapStore.zoomTwoMarkers( + mapStore.selectedCarouselLatLng, + LatLng(mapStore.userlat, + mapStore.userlong), + 120.0); + }, + )) + .toList(), + options: CarouselOptions( + height: 100, + viewportFraction: 0.7, + initialPage: 0, + enableInfiniteScroll: false, + scrollDirection: Axis.horizontal, + ), + ); + }) : const SizedBox(), ], ), diff --git a/lib/widgets/profile/custom_date_picker.dart b/lib/widgets/profile/custom_date_picker.dart new file mode 100644 index 00000000..fc3ec247 --- /dev/null +++ b/lib/widgets/profile/custom_date_picker.dart @@ -0,0 +1,47 @@ + +import 'package:flutter/material.dart'; + +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; + + +class CustomDatePicker extends StatefulWidget { + final Widget? child; + const CustomDatePicker({super.key, this.child}); + + @override + State createState() => _CustomDatePickerState(); +} + +class _CustomDatePickerState extends State { + @override + Widget build(BuildContext context) { + return Theme( + data: Theme.of(context).copyWith( + textTheme: TextTheme( + headline4: MyFonts.w500, + headline5: MyFonts.w500, // Selected Date landscape + headline6: MyFonts.w500, // Selected Date portrait + overline: MyFonts.w500, // Title - SELECT DATE + bodyText1: MyFonts.w500, // year gridbview picker + subtitle1: MyFonts.w500, // input + subtitle2: MyFonts.w500, // month/year picker + caption: MyFonts.w500, // days + ), + colorScheme: const ColorScheme.dark( + primary: lBlue4, + surface: kdatePickerSurfaceColor, + ), + dialogBackgroundColor: kdatePickerSurfaceColor, + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + backgroundColor: kdatePickerSurfaceColor, // button + foregroundColor: lBlue2, + elevation: 0, + textStyle: MyFonts.w500), + ), + ), + child: widget.child!, + ); + } +} diff --git a/lib/widgets/profile/custom_dropdown.dart b/lib/widgets/profile/custom_dropdown.dart new file mode 100644 index 00000000..fa99659b --- /dev/null +++ b/lib/widgets/profile/custom_dropdown.dart @@ -0,0 +1,99 @@ + +import 'package:flutter/material.dart'; + + +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; + +class CustomDropDown extends StatelessWidget { + final List items; + final String hintText; + final Function? onChanged; + final String? Function(String?)? validator; + final int? index; + final String? value; + + const CustomDropDown( + {super.key, + required this.items, + required this.hintText, + required this.onChanged, + this.index, + this.value, + required this.validator}); + + @override + Widget build(BuildContext context) { + return DropdownButtonFormField( + validator: validator, + menuMaxHeight: 400, + value: value, + isExpanded: true, + decoration: InputDecoration( + label: RichText( + text: TextSpan( + children: [ + TextSpan( + text: hintText, + style: MyFonts.w500.size(14).setColor(kTabText), + ), + TextSpan( + text: ' * ', + style: MyFonts.w500.size(16).setColor(kRed), + ), + ], + ), + ), + labelStyle: MyFonts.w500.size(14).setColor(kTabText), + errorStyle: MyFonts.w500, + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 16), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: kfocusColor, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: kfocusColor, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + errorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + focusedErrorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + ), + dropdownColor: kBackground, + isDense: true, + icon: const Icon( + Icons.arrow_drop_down, + size: 28, + ), + elevation: 16, + style: MyFonts.w500.size(14).setColor(kWhite), + onChanged: (String? value) { + if (index != null) { + onChanged!(value, index); + } else { + onChanged!(value); + } + }, + items: items.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ); + } +} diff --git a/lib/widgets/profile/custom_text_field.dart b/lib/widgets/profile/custom_text_field.dart new file mode 100644 index 00000000..a5620073 --- /dev/null +++ b/lib/widgets/profile/custom_text_field.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; + + +class CustomTextField extends StatefulWidget { + final List? inputFormatters; + final String hintText; + final TextInputType? inputType; + final String? Function(String?)? validator; + final String? value; + final void Function(String)? onChanged; + final bool isNecessary; + final TextEditingController? controller; + final void Function()? onTap; + final FocusNode? focusNode; + final bool? isEnabled; + final int? maxLength; + final int? maxLines; + final bool? counter; + + + const CustomTextField( + {super.key, + required this.hintText, + this.validator, + this.value, + this.onChanged, + required this.isNecessary, + this.inputType, + this.controller, + this.onTap, + this.isEnabled, + this.focusNode, this.maxLength, this.maxLines, this.counter, this.inputFormatters, }); + + @override + State createState() => _CustomTextFieldState(); +} + +class _CustomTextFieldState extends State { + @override + Widget build(BuildContext context) { + Widget? counterBuilder(context, + {required currentLength, required isFocused, required maxLength}) { + if (currentLength == 0) { + return null; + } + return Text("$currentLength/$maxLength", + style: MyFonts.w500.size(12).setColor(kWhite)); + } + return TextFormField( + inputFormatters:widget.inputFormatters, + enabled: widget.isEnabled ?? true, + readOnly: widget.onTap != null, + style: MyFonts.w500.size(14).copyWith(color: Colors.white), + validator: widget.validator, + controller: widget.controller, + focusNode: widget.focusNode, + cursorColor: lBlue2, + onTap: widget.onTap, + onChanged: widget.onChanged, + buildCounter:widget.counter==true?counterBuilder:null, + initialValue: widget.value == 'null' ? '' : widget.value, + keyboardType: widget.inputType, + maxLength: widget.maxLength, + maxLines: widget.maxLines, + decoration: InputDecoration( + errorStyle: MyFonts.w500, + label: RichText( + text: TextSpan( + children: [ + TextSpan( + text: widget.hintText, + style: MyFonts.w500.size(14).setColor(kTabText), + ), + if (widget.isNecessary) + TextSpan( + text: ' * ', + style: MyFonts.w500.size(16).setColor(kRed), + ), + ], + ), + ), + labelStyle: MyFonts.w500.size(14).setColor(kTabText), + hintStyle: MyFonts.w500.size(14).setColor(kTabText), + contentPadding: + const EdgeInsets.symmetric(vertical: 20, horizontal: 16), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: kfocusColor, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: kfocusColor, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + disabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: kfocusColor, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + errorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + focusedErrorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 1), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/profile/data_tile.dart b/lib/widgets/profile/data_tile.dart new file mode 100644 index 00000000..67864b51 --- /dev/null +++ b/lib/widgets/profile/data_tile.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:onestop_dev/stores/login_store.dart'; + +import '../../globals/my_colors.dart'; +import '../../globals/my_fonts.dart'; + + +class DataTile extends StatelessWidget { + final String title; + final String? semiTitle; + const DataTile({Key? key, required this.title, required this.semiTitle}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 12, + ), + Text( + title, + style: MyFonts.w600.size(12).setColor(kTabText), + ), + const SizedBox( + height: 10, + ), + Text( + semiTitle!=null && semiTitle!.isNotEmpty ? semiTitle! : (LoginStore.isGuest ? "Not set for guest user" : "Not set by you"), + style: MyFonts.w500.size(14).setColor(kWhite), + ), + const SizedBox( + height: 12, + ) + ], + ); + } +} diff --git a/lib/widgets/profile/feedback.dart b/lib/widgets/profile/feedback.dart index 7d92bc75..a147a79a 100644 --- a/lib/widgets/profile/feedback.dart +++ b/lib/widgets/profile/feedback.dart @@ -185,6 +185,7 @@ class _FeedBackState extends State { onTap: !enableSubmitButton ? null : () async { + print("inside feedback submit"); bool isValid = formKey.currentState!.validate(); if (!isValid) { return; @@ -193,14 +194,12 @@ class _FeedBackState extends State { 'title': title.text, 'body': body.text, 'type': selected, - 'user': context - .read() - .userData['email'] ?? + 'user': LoginStore.userData['outlookEmail'] ?? "Unknown" }; setState(() => enableSubmitButton = false); bool success = - await APIService.postFeedbackData(data); + await APIService().postFeedbackData(data); String snackBar = "There was an error while sending your feedback.\nPlease try again later or reach out to any member using the Contacts section."; if (success) { diff --git a/lib/widgets/timetable/date_slider.dart b/lib/widgets/timetable/date_slider.dart index 7ea1cd46..20318fb2 100644 --- a/lib/widgets/timetable/date_slider.dart +++ b/lib/widgets/timetable/date_slider.dart @@ -36,7 +36,6 @@ class _DateSliderState extends State { tStyle = MyFonts.w500.size(14).setColor(kGrey7); } return Container( - // height: 125, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: selected ? kTimetableGreen : Colors.transparent, diff --git a/lib/widgets/travel/bus_details.dart b/lib/widgets/travel/bus_details.dart index a4bcfb44..761e6786 100644 --- a/lib/widgets/travel/bus_details.dart +++ b/lib/widgets/travel/bus_details.dart @@ -3,8 +3,13 @@ import 'package:flutter/material.dart'; import 'package:onestop_dev/functions/travel/has_left.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/models/travel/travel_timing_model.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; +import 'package:provider/provider.dart'; +import '../../functions/travel/next_time.dart'; +import '../../stores/travel_store.dart'; import 'timing_tile.dart'; class BusDetails extends StatefulWidget { @@ -19,8 +24,7 @@ class BusDetails extends StatefulWidget { class _BusDetailsState extends State { bool isCity = false; bool isCampus = false; - Map>> busTime = {}; - + List? busTime = []; @override void initState() { super.initState(); @@ -28,11 +32,13 @@ class _BusDetailsState extends State { @override Widget build(BuildContext context) { - return FutureBuilder( - future: DataProvider.getBusTimings(), + var daytype = context.read().busDayType; + return FutureBuilder>( + // future: APIService().getBusTiming(), + future: DataProvider.getBusTiming(), builder: (context, snapshot) { if (snapshot.hasData) { - busTime = snapshot.data as Map>>; + busTime = snapshot.data; return Column( children: [ GestureDetector( @@ -60,36 +66,34 @@ class _BusDetailsState extends State { ), ), isCity - ? Column( - children: busTime.entries.map((entry) { - if ((busTime[entry.key]![widget.index].isEmpty)) { - return Container(); - } - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Text( - "To ${entry.key}", - style: MyFonts.w500.setColor(kWhite), - ), + ?Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 5), + child: Text( + "To ${busTime![0].stop}", + style: MyFonts.w500.setColor(kWhite), + ), + ), + ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount:daytype == 'Weekdays' ?busTime![0].weekdays.fromCampus.length:busTime![0].weekend.fromCampus.length, + itemBuilder:(BuildContext context, int index){ + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: TimingTile( + time: daytype == 'Weekdays' ? formatTime(busTime![0].weekdays.fromCampus[index]):formatTime(busTime![0].weekend.fromCampus[index]), + isLeft: daytype=='Weekdays'? hasLeft(busTime![0].weekdays.fromCampus[index]):hasLeft(busTime![0].weekend.fromCampus[index]), + icon: FluentIcons.vehicle_bus_24_filled, + ), - Column( - children: - busTime[entry.key]![widget.index].map((e) { - return Padding( - padding: - const EdgeInsets.symmetric(vertical: 5), - child: TimingTile( - time: e, - isLeft: hasLeft(e.toString()), - icon: FluentIcons.vehicle_bus_24_filled, - ), - ); - }).toList()), - ], - ); - }).toList()) + ); + } + ), + ], + ) : Container(), GestureDetector( onTap: () { @@ -117,35 +121,33 @@ class _BusDetailsState extends State { ), isCampus ? Column( - children: busTime.entries.map((entry) { - if ((busTime[entry.key]![widget.index + 2].isEmpty)) { - return Container(); - } - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Text( - "From ${entry.key}", - style: MyFonts.w500.setColor(kWhite), - ), + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 5), + child: Text( + "From ${busTime![0].stop}", + style: MyFonts.w500.setColor(kWhite), + ), + ), + ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount:daytype == 'Weekdays' ?busTime![0].weekdays.toCampus.length : busTime![0].weekend.toCampus.length, + itemBuilder:(BuildContext context, int index){ + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: TimingTile( + time: daytype == 'Weekdays' ? formatTime(busTime![0].weekdays.toCampus[index]):formatTime(busTime![0].weekend.toCampus[index]), + isLeft: daytype=='Weekdays'?hasLeft(busTime![0].weekdays.toCampus[index]):hasLeft(busTime![0].weekend.toCampus[index]), + icon: FluentIcons.vehicle_bus_24_filled, + ), - Column( - children: busTime[entry.key]![widget.index + 2] - .map((e) { - return Padding( - padding: - const EdgeInsets.symmetric(vertical: 5), - child: TimingTile( - time: e, - isLeft: hasLeft(e.toString()), - icon: FluentIcons.vehicle_bus_24_filled, - ), - ); - }).toList()), - ], - ); - }).toList()) + ); + } + ), + ], + ) : Container(), ], ); diff --git a/lib/widgets/travel/ferry_details.dart b/lib/widgets/travel/ferry_details.dart index d5b9bca6..ad532d76 100644 --- a/lib/widgets/travel/ferry_details.dart +++ b/lib/widgets/travel/ferry_details.dart @@ -6,6 +6,7 @@ import 'package:mobx/mobx.dart'; import 'package:onestop_dev/functions/travel/has_left.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/models/travel/travel_timing_model.dart'; import 'package:onestop_dev/pages/travel/data.dart'; import 'package:onestop_dev/stores/mapbox_store.dart'; import 'package:onestop_dev/stores/travel_store.dart'; @@ -13,22 +14,38 @@ import 'package:onestop_dev/widgets/travel/timing_tile.dart'; import 'package:onestop_dev/widgets/travel/travel_drop_down.dart'; import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; import 'package:provider/provider.dart'; +import '../../functions/travel/next_time.dart'; -class FerryDetails extends StatelessWidget { +class FerryDetails extends StatefulWidget { const FerryDetails({Key? key}) : super(key: key); + @override + State createState() => _FerryDetailsState(); +} + +class _FerryDetailsState extends State { + @override + void initState() { + super.initState(); + if (DateTime.now().weekday == DateTime.sunday) { + context.read().setFerryDayType("Sunday"); + } + } + @override Widget build(BuildContext context) { return Observer(builder: (context) { + var direction = context.read().ferryDirection; + var daytype = context.read().ferryDayType; if (context.read().ferryTimings.status == FutureStatus.fulfilled) { - var ferryModel = context + TravelTiming ferryModel = context .read() .ferryTimings .value! .firstWhere((element) => - element.name == context.read().selectedFerryGhat); - var ferryMap = ferryModel.toJson(); + element.stop == context.read().selectedFerryGhat); + // var ferryMap = ferryModel.toJson(); return Column(children: [ SizedBox( height: 50, @@ -94,23 +111,51 @@ class FerryDetails extends StatelessWidget { ], ), ), - Column( - children: (ferryMap[context.read().ferryDataIndex] - as List) - .map((e) { - return Padding( - padding: const EdgeInsets.fromLTRB(0, 5, 0, 5), - child: TimingTile( - time: e, - isLeft: hasLeft(e.toString()), - icon: FluentIcons.vehicle_ship_24_filled, - ), - ); - }).toList(), - ) + if (daytype == "Sunday") ...[ + ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: direction == "Campus to City" + ? ferryModel.weekend.fromCampus.length + : ferryModel.weekend.toCampus.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: TimingTile( + time: direction == "Campus to City" + ? formatTime(ferryModel.weekend.fromCampus[index]) + : formatTime(ferryModel.weekend.toCampus[index]), + isLeft: direction == "Campus to City" + ? hasLeft(ferryModel.weekend.fromCampus[index]) + : hasLeft(ferryModel.weekend.toCampus[index]), + icon: FluentIcons.vehicle_bus_24_filled, + ), + ); + }), + ] else ...[ + ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + itemCount: direction == "Campus to City" + ? ferryModel.weekdays.fromCampus.length + : ferryModel.weekdays.toCampus.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: TimingTile( + time: direction == "Campus to City" + ? formatTime(ferryModel.weekdays.fromCampus[index]) + : formatTime(ferryModel.weekdays.toCampus[index]), + isLeft: direction == "Campus to City" + ? hasLeft(ferryModel.weekdays.fromCampus[index]) + : hasLeft(ferryModel.weekdays.toCampus[index]), + icon: FluentIcons.vehicle_bus_24_filled, + ), + ); + }), + ] ]); } - return ListShimmer( count: 3, height: 50, diff --git a/lib/widgets/travel/next_time_card.dart b/lib/widgets/travel/next_time_card.dart index 38d1c887..cd364883 100644 --- a/lib/widgets/travel/next_time_card.dart +++ b/lib/widgets/travel/next_time_card.dart @@ -7,10 +7,13 @@ import 'package:onestop_dev/functions/travel/duration_left.dart'; import 'package:onestop_dev/functions/travel/next_time.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:onestop_dev/stores/mapbox_store.dart'; import 'package:provider/provider.dart'; +import '../../models/travel/travel_timing_model.dart'; + class NextTimeCard extends StatefulWidget { const NextTimeCard({Key? key}) : super(key: key); @@ -23,41 +26,71 @@ class _NextTimeCardState extends State { Widget build(BuildContext context) { var mapStore = context.read(); Future getNextTime() async { + print("INSIDE NEXT TIME CARD"); String today = getFormattedDay(); + print(mapStore.indexBusesorFerry); if (mapStore.indexBusesorFerry == 0) { - var allBusTimes = await DataProvider.getBusTimings(); - List> busTimes = [[], []]; - allBusTimes.forEach((key, list) { - for (String time in list[0]) { - busTimes[0].add(time); + print("hererereferf"); + // List allBusTimes = await APIService().getBusTiming(); + List allBusTimes = await DataProvider.getBusTiming(); + //print(allBusTimes.toString()); + print("AFTER ALL BUS TIMES"); + List weekdaysTimes= []; + List weekendTimes=[]; + for(var xyz in allBusTimes){ + int n=xyz.weekdays.fromCampus.length; + print("n is : ${n}"); + for(int i=0;i a.compareTo(b)); + for(var xyz in allBusTimes){ + int n=xyz.weekend.fromCampus.length; + for(int i=0;i parseTime(a).compareTo(parseTime(b))); - busTimes[1].sort((a, b) => parseTime(a).compareTo(parseTime(b))); + } + weekendTimes.sort((a, b) => a.compareTo(b)); + //List> busTimes = [[], []]; if (today == 'Fri') { - return nextTime(busTimes[1], firstTime: busTimes[0][0]); + return nextTime(weekdaysTimes, firstTime: weekendTimes[0].toString()); } else if (today == 'Sun') { - return nextTime(busTimes[0], firstTime: busTimes[1][0]); + return nextTime(weekendTimes, firstTime:weekdaysTimes[0].toString()); } else if (today == 'Sat') { - return nextTime(busTimes[0]); + return nextTime(weekendTimes); } - return nextTime(busTimes[1]); + return nextTime(weekdaysTimes); } else { - var ferryTimes = await DataProvider.getFerryTimings(); - var requiredModel = ferryTimes.firstWhere((element) => - element.name == - mapStore.allLocationData[mapStore.selectedCarouselIndex]['name']); + // List ferryTimings = await APIService().getFerryTiming(); + List ferryTimings = await DataProvider.getFerryTiming(); + List weekdaysTimes= []; + List weekendTimes=[]; + TravelTiming requiredModel = + ferryTimings.firstWhere((element) => element.stop == mapStore.allLocationData[mapStore.selectedCarouselIndex]['name']); + print(requiredModel.toJson()); + int n=requiredModel.weekdays.fromCampus.length; + for(int i=0;i a.compareTo(b)); + int p=requiredModel.weekend.fromCampus.length; + for(int i=0;i a.compareTo(b)); + // var ferryTimes = await DataProvider.getFerryTimings(); + // var requiredModel = ferryTimes.firstWhere((element) => + // element.name == + // mapStore.allLocationData[mapStore.selectedCarouselIndex]['name']); if (today == 'Sat') { - return nextTime(requiredModel.MonToFri_NorthGuwahatiToGuwahati, - firstTime: requiredModel.Sunday_NorthGuwahatiToGuwahati[0]); + return nextTime(weekdaysTimes, + firstTime: weekendTimes[0].toString()); } else if (today == 'Sun') { - return nextTime(requiredModel.Sunday_NorthGuwahatiToGuwahati, - firstTime: requiredModel.MonToFri_NorthGuwahatiToGuwahati[0]); + return nextTime(weekendTimes, + firstTime: weekdaysTimes[0].toString()); } - return nextTime(requiredModel.MonToFri_NorthGuwahatiToGuwahati); + return nextTime(weekdaysTimes); } } @@ -78,13 +111,13 @@ class _NextTimeCardState extends State { radius: 20, child: (context.read().indexBusesorFerry == 1) ? const Icon( - FluentIcons.vehicle_ship_24_filled, - color: kBlueGrey, - ) + FluentIcons.vehicle_ship_24_filled, + color: kBlueGrey, + ) : const Icon( - FluentIcons.vehicle_bus_24_filled, - color: kBlueGrey, - ), + FluentIcons.vehicle_bus_24_filled, + color: kBlueGrey, + ), ), title: Text( mapStore.allLocationData[mapStore.selectedCarouselIndex]['name'], @@ -101,13 +134,13 @@ class _NextTimeCardState extends State { width: 80, child: (mapStore.indexBusesorFerry == 0) ? Text( - 'Next Bus in ${durationLeft(snapshot.data.toString())}', - style: MyFonts.w500.setColor(lBlue2).size(14), - ) + 'Next Bus in ${durationLeft(snapshot.data.toString())}', + style: MyFonts.w500.setColor(lBlue2).size(14), + ) : Text( - 'Next Ferry in ${durationLeft(snapshot.data.toString())}', - style: MyFonts.w500.setColor(lBlue2).size(14), - )); + 'Next Ferry in ${durationLeft(snapshot.data.toString())}', + style: MyFonts.w500.setColor(lBlue2).size(14), + )); } return const CircularProgressIndicator(); }), diff --git a/lib/widgets/travel/stops_bus_details.dart b/lib/widgets/travel/stops_bus_details.dart index 818c8b2d..a5702014 100644 --- a/lib/widgets/travel/stops_bus_details.dart +++ b/lib/widgets/travel/stops_bus_details.dart @@ -7,9 +7,23 @@ import 'package:onestop_dev/widgets/travel/tracking_dailog.dart'; import 'package:onestop_dev/widgets/travel/travel_drop_down.dart'; import 'package:provider/provider.dart'; -class StopsBusDetails extends StatelessWidget { +class StopsBusDetails extends StatefulWidget { const StopsBusDetails({Key? key}) : super(key: key); + @override + State createState() => _StopsBusDetailsState(); +} + +class _StopsBusDetailsState extends State { + @override + void initState() { + super.initState(); + if (DateTime.now().weekday == DateTime.sunday || + DateTime.now().weekday == DateTime.saturday) { + context.read().setBusDayString("Weekends"); + } + } + @override Widget build(BuildContext context) { return Observer(builder: (context) { @@ -68,7 +82,6 @@ class StopsBusDetails extends StatelessWidget { Expanded( child: Container(), ), - context.read().isBusSelected ? TravelDropDown( value: context.read().busDayType, @@ -76,11 +89,16 @@ class StopsBusDetails extends StatelessWidget { items: const ['Weekdays', 'Weekends'], ) : GestureDetector( - onTap: (){ - showDialog(context: context, builder: (_) => const TrackingDailog()); - }, - child: Text("Track Bus", style: MyFonts.w500.setColor(kWhite),), - ) + onTap: () { + showDialog( + context: context, + builder: (_) => const TrackingDailog()); + }, + child: Text( + "Track Bus", + style: MyFonts.w500.setColor(kWhite), + ), + ) ], ), context.read().busPage diff --git a/lib/widgets/travel/stops_list.dart b/lib/widgets/travel/stops_list.dart index d9ec2013..c840ec81 100644 --- a/lib/widgets/travel/stops_list.dart +++ b/lib/widgets/travel/stops_list.dart @@ -7,6 +7,8 @@ import 'package:onestop_dev/functions/travel/distance.dart'; import 'package:onestop_dev/functions/travel/next_time.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/models/travel/travel_timing_model.dart'; +import 'package:onestop_dev/services/api.dart'; import 'package:onestop_dev/services/data_provider.dart'; import 'package:onestop_dev/stores/mapbox_store.dart'; import 'package:onestop_dev/widgets/ui/list_shimmer.dart'; @@ -23,23 +25,45 @@ class BusStopList extends StatelessWidget { itemCount: context.read().allLocationData.length, itemBuilder: (BuildContext context, int index) { var mapStore = context.read(); - return FutureBuilder( - future: DataProvider.getBusTimings(), + return FutureBuilder>( + // future: APIService().getBusTiming(), + future: DataProvider.getBusTiming(), builder: (context, snapshot) { if (snapshot.hasData) { - var allBusTimes = - (snapshot.data as Map>>); - List> busTime = [[], []]; - allBusTimes.forEach((key, list) { - for (String time in list[0]) { - busTime[0].add(time); + List? busTime = snapshot.data ; + List weekdaysTimes=[]; + List weekendTimes=[]; + for(var xyz in busTime!){ + int n=xyz.weekdays.fromCampus.length; + for(int i=0;i a.compareTo(b)); + for(var xyz in busTime){ + int n=xyz.weekend.fromCampus.length; + for(int i=0;i parseTime(a).compareTo(parseTime(b))); - busTime[1].sort((a, b) => parseTime(a).compareTo(parseTime(b))); + } + weekendTimes.sort((a, b) => a.compareTo(b)); + // List allBusTimes = + // (snapshot.data as List); + // List> busTime = [[], []]; + // allBusTimes.forEach((key, list) { + // for (String time in list[0]) { + // busTime[0].add(time); + // } + // for (String time in list[1]) { + // busTime[1].add(time); + // } + // }); + // busTime.sort((a, b) { + // return parseTime(a).compareTo(parseTime(b)); + // }); + // busTime[1].sort((a, b) { + // return parseTime(a).compareTo(parseTime(b)); + // }); return Padding( padding: const EdgeInsets.only(top: 4.0, bottom: 4.0), child: GestureDetector( @@ -48,9 +72,9 @@ class BusStopList extends StatelessWidget { mapStore.zoomTwoMarkers( LatLng( mapStore.allLocationData[ - mapStore.selectedCarouselIndex]['lat'], + mapStore.selectedCarouselIndex]['lat'], mapStore.allLocationData[ - mapStore.selectedCarouselIndex]['long']), + mapStore.selectedCarouselIndex]['long']), LatLng(mapStore.userlat, mapStore.userlong), 100.0); }, @@ -60,7 +84,7 @@ class BusStopList extends StatelessWidget { decoration: BoxDecoration( color: kTileBackground, borderRadius: - const BorderRadius.all(Radius.circular(20)), + const BorderRadius.all(Radius.circular(20)), border: Border.all( color: (mapStore.selectedCarouselIndex == index) ? lBlue5 @@ -108,14 +132,14 @@ class BusStopList extends StatelessWidget { // trailing: Text( (getFormattedDay() == 'Fri') - ? nextTime(busTime[1], - firstTime: busTime[0][0]) + ? nextTime(weekendTimes, + firstTime: weekendTimes[0].toString()) : (getFormattedDay() == 'Sun') - ? nextTime(busTime[0], - firstTime: busTime[1][0]) - : (getFormattedDay() == 'Sat') - ? nextTime(busTime[0]) - : nextTime(busTime[1]), + ? nextTime(weekendTimes, + firstTime: weekdaysTimes[0].toString()) + : (getFormattedDay() == 'Sat') + ? nextTime(weekendTimes) + : nextTime(weekdaysTimes), style: MyFonts.w500.setColor(lBlue2), )), ); diff --git a/lib/widgets/travel/timing_tile.dart b/lib/widgets/travel/timing_tile.dart index db0764cd..3b982398 100644 --- a/lib/widgets/travel/timing_tile.dart +++ b/lib/widgets/travel/timing_tile.dart @@ -34,13 +34,13 @@ class TimingTile extends StatelessWidget { ), trailing: isLeft ? Text( - 'Left', - style: MyFonts.w500.setColor(kGrey11), - ) + 'Left', + style: MyFonts.w500.setColor(kGrey11), + ) : const SizedBox( - height: 0, - width: 0, - ), + height: 0, + width: 0, + ), ), ); } diff --git a/lib/widgets/ui/appbar.dart b/lib/widgets/ui/appbar.dart index c0e4bba7..e2bd90d5 100644 --- a/lib/widgets/ui/appbar.dart +++ b/lib/widgets/ui/appbar.dart @@ -1,8 +1,14 @@ import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; +import 'package:onestop_dev/functions/notifications/get_notifications.dart'; import 'package:onestop_dev/globals/my_colors.dart'; import 'package:onestop_dev/globals/my_fonts.dart'; -import 'package:onestop_dev/pages/profile.dart'; +import 'package:onestop_dev/models/profile/profile_model.dart'; +import 'package:onestop_dev/pages/profile/profile_page.dart'; +import 'package:onestop_dev/stores/login_store.dart'; +import 'package:onestop_dev/pages/notifications/notifications.dart'; +import 'package:onestop_dev/pages/profile/edit_profile.dart'; +import 'package:badges/badges.dart' as badges; AppBar appBar(BuildContext context, {bool displayIcon = true}) { return AppBar( @@ -22,7 +28,10 @@ AppBar appBar(BuildContext context, {bool displayIcon = true}) { color: lBlue2, ), onPressed: () { - Navigator.pushNamed(context, ProfilePage.id); + // Navigator.pushNamed(context, ProfilePage.id); + print(ProfileModel.fromJson(LoginStore.userData)); + print(LoginStore.userData); + Navigator.push(context, MaterialPageRoute(builder: (buildContext) => Profile(profileModel: ProfileModel.fromJson(LoginStore.userData),))); }, ), ) @@ -64,23 +73,35 @@ AppBar appBar(BuildContext context, {bool displayIcon = true}) { ]), // textAlign: TextAlign.start, ), - // Expanded( - // child: Image.asset( - // 'assets/images/AppLogo.png', - // // scale: 4, - // ), - // ), - const SizedBox( - width: 35, - height: 35, - ) - // CircleAvatar( - // backgroundColor: kAppBarGrey, - // child: IconButton( - // onPressed: () {}, - // icon: Icon(Icons.notifications), - // color: lBlue2, - // )), + FutureBuilder>( + future: getSavedNotifications(false), + builder: (context,snapshot) { + var badgeColor = Colors.transparent; + if (snapshot.hasData) { + int unread = snapshot.data!.where((element) => element.read == false).length; + if (unread > 0) { + badgeColor = kYellow; + } + } + return CircleAvatar( + backgroundColor: kAppBarGrey, + child: IconButton( + onPressed: () { + Navigator.pushNamed(context, NotificationPage.id); + }, + icon: badges.Badge( + badgeColor: badgeColor, + elevation: 0, + position: badges.BadgePosition.topStart(), + child: const Icon( + FluentIcons.alert_24_filled, + color: lBlue2, + ), + ), + color: lBlue2, + )); + } + ), ], ), elevation: 0.0, diff --git a/lib/widgets/ui/guest_restrict.dart b/lib/widgets/ui/guest_restrict.dart new file mode 100644 index 00000000..833a1d71 --- /dev/null +++ b/lib/widgets/ui/guest_restrict.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:onestop_dev/globals/my_colors.dart'; +import 'package:onestop_dev/globals/my_fonts.dart'; + +class GuestRestrictAccess extends StatelessWidget { + const GuestRestrictAccess({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "Not Accessible in Guest Mode", + style: MyFonts.w400.setColor(kWhite), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/ui/notification_tile.dart b/lib/widgets/ui/notification_tile.dart new file mode 100644 index 00000000..fd27126e --- /dev/null +++ b/lib/widgets/ui/notification_tile.dart @@ -0,0 +1,119 @@ +import 'package:fluentui_system_icons/fluentui_system_icons.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:onestop_dev/globals/my_colors.dart'; +import 'package:onestop_dev/globals/my_fonts.dart'; +import 'package:onestop_dev/pages/notifications/notifications.dart'; + +class NotificationTile extends StatelessWidget { + const NotificationTile({Key? key, required this.notifModel}) + : super(key: key); + + final NotifsModel notifModel; + + IconData get notificationIcon { + switch (notifModel.category.toLowerCase()) { + case "lost": + case "found": + return FluentIcons.document_search_24_filled; + case "buy": + case "sell": + return FluentIcons.money_24_filled; + case "travel": + return FluentIcons.vehicle_car_24_filled; + } + return FluentIcons.checkbox_1_20_filled; + } + + @override + Widget build(BuildContext context) { + var iconColor = notifModel.read ? kGreenDisabled : kGreen ; + var titleColor = notifModel.read ? kGrey2 : kWhite; + var bodyColor = notifModel.read ? kGrey2 : lBlue; + var tileBg = notifModel.read ? kTimetableDisabled : kTimetableGreen; + return Container( + decoration: BoxDecoration( + color: tileBg, + borderRadius: BorderRadius.circular(25), + ), + child: Padding( + padding: const EdgeInsets.only(top: 10.0, bottom: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 50, + width: 50, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: iconColor, + ), + child: Icon( + notificationIcon, + color: kAppBarGrey, + size: 25, + ), + ), + ], + ), + ), + Expanded( + flex: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const SizedBox( + height: 5.0, + ), + Text( + notifModel.title!, + style: MyFonts.w500.size(15).setColor(titleColor), + ), + const SizedBox( + height: 3.0, + ), + Text( + notifModel.body!, + style: MyFonts.w400.size(13).setColor(bodyColor), + ), + const SizedBox( + height: 3.0, + ), + ], + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: Text( + DateFormat.MMMMd().format(notifModel.time), + style: MyFonts.w400.setColor(bodyColor), + ), + // child: Container( + // decoration: BoxDecoration( + // color: lBlue2, + // borderRadius: BorderRadius.circular(25), + // // color: kTimetableGreen, + // // border: showHighlight + // // ? Border.all(color: Colors.blueAccent) + // // : Border.all(color: Colors.transparent), + // // ) + // ), + // padding: EdgeInsets.all(5), + // // color: lBlue2, + // child: Center(child: Text('12 new', style: MyFonts.w600.setColor(kAppBarGrey),)), + // ), + ) + ], + ), + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 4bad1a79..65d560f4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,10 +15,10 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.3.3+25 +version: 2.0.0+27 environment: - sdk: ">=2.15.1 <3.0.0" + sdk: ">=2.17.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -61,9 +61,9 @@ dependencies: flutter_mobx: ^2.0.5 add_2_calendar: ^2.1.3 timeago: ^3.2.2 - get: 4.6.1 + get: ^4.6.5 map_launcher: ^2.3.0+1 - json_annotation: ^4.7.0 + json_annotation: ^4.8.1 sembast: ^3.2.0 shimmer: ^2.0.0 google_maps_flutter: ^2.1.10 @@ -72,9 +72,12 @@ dependencies: path_provider: ^2.0.11 path: ^1.8.0 infinite_scroll_pagination: ^3.2.0 - upgrader: ^5.1.0 + upgrader: ^6.2.0 badges: ^2.0.3 - + image: ^4.0.15 + firebase_messaging: ^14.1.3 + flutter_local_notifications: ^13.0.0 + firebase_core: ^2.3.0 dev_dependencies: flutter_test: @@ -83,7 +86,7 @@ dev_dependencies: build_runner: ^2.1.10 mobx_codegen: ^2.0.5+2 json_serializable: ^6.2.0 - flutter_launcher_icons: ^0.10.0 + flutter_launcher_icons: ^0.12.0 flutter_lints: ^2.0.1 dependency_validator: ^3.2.2 change_app_package_name: ^1.1.0 diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index ee2f29e6..00000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,29 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:onestop_dev/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}