router update

This commit is contained in:
VINISTAN 2024-12-04 19:39:23 +05:30
parent 3ab1010409
commit c86f9663ed
9 changed files with 1495 additions and 317 deletions

View File

@ -207,7 +207,7 @@
// ),
// ),
// ];
//
// //
// ShellRoute get inAppRoutes => ShellRoute(
// builder: (context, state, child) => LoggedInHomeScaffold(
// body: child,
@ -218,7 +218,7 @@
// ],
// );
// }
//
// //
// String? _pathCache;
//
// @riverpod
@ -292,9 +292,9 @@
// return router;
// }
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../domain/use_cases/preferences_use_case.dart';
import '../presentation/Screens/changepassword.dart';
@ -303,47 +303,59 @@ import '../presentation/Screens/otp_verification.dart';
import '../presentation/Screens/profilepage.dart';
import '../presentation/routes/auth_routes/login_route.dart';
import '../presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
import '../presentation/routes/drawer_routes/Drawer Items/feedback.dart';
import '../presentation/routes/drawer_routes/Drawer Items/manage_users.dart';
final GoRouter router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => LoginRoute(),
//builder: (context, state) => LoginRoute(),
builder: (context, state) => MyHomePage(),
),
GoRoute(
path: '/profile',
builder: (context, state) => ProfileScreen(userId: '',),
),
// GoRoute(
// path: '/home',
// builder: (context, state) => HomeRoute(),
// ),
GoRoute(
path: '/myhomepage',
builder: (context, state) => MyHomePage(),
),
GoRoute(
path: '/changepw',
builder: (context, state) => Changepassword(),
),
GoRoute(
path: '/mailverification',
builder: (context, state) => EmailVerificationScreen(email: '', userId: '', otp: '', otpId: '', sendVerificationCode: (String ) { },),
builder: (context, state) => EmailVerificationScreen(
email: '',
userId: '',
otp: '',
otpId: '',
sendVerificationCode: (String) {},
),
),
GoRoute(
path: '/changepass',
builder: (context, state) => Changepassword(),
path: '/changepassword',
builder: (context, state) => Changepassword(
userId: '',
),
),
GoRoute(
path: '/confirmpasswd',
builder: (context, state) => ConfirmPassword(email: '', userId: '',),
builder: (context, state) => ConfirmPassword(
email: '',
userId: '',
),
),
// Drawer Routers
GoRoute(
path: '/feedback',
builder: (context, state) => FeedbackForm(),
),
GoRoute(
path: '/profile',
builder: (context, state) => ProfileScreen(
userId: '',
),
),
GoRoute(
path: '/manageuser',
builder: (context, state) => ManageUserRouter(),
),
],
);

View File

@ -27,15 +27,28 @@ class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: RegisterScreen(),
//home: ProfileScreen(),
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: router, // Use the GoRouter instance from app_router.dart
);
}
}
// class MainApp extends StatelessWidget {
// const MainApp({super.key});
//
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// home: RegisterScreen(),
// //home: ProfileScreen(),
// debugShowCheckedModeBanner: false,
// );
// }
// }
// class MainApp extends ConsumerWidget {
// const MainApp({super.key});
//

View File

@ -71,7 +71,7 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
}
// Update password
await pb.collection('users').update(
await _pb.collection('users').update(
userId, // User ID
body: {
'password': newPassword,

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
@ -515,12 +516,15 @@ class _ProfileScreenState extends State<ProfileScreen> {
Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Changepassword()),
);
context.go('/confirmpasswd');
},
// {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => Changepassword(userId: '',)),
// );
// },
child: Text(
"Change Password",
style: TextStyle(
@ -532,35 +536,38 @@ class _ProfileScreenState extends State<ProfileScreen> {
SizedBox(height: 20),
ElevatedButton.icon(
onPressed: () {
if ((_formKey.currentState?.validate() ?? false) &&
(isChecked)) {
_formKey.currentState?.save();
showConfirmationDialog(context);
} else {
setState(() {
showError =
!isChecked; // Show error if the checkbox is not checked
});
}
// if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
// _formKey.currentState?.save();
// showConfirmationDialog(context);
// // if (isChecked) {
// // _formKey.currentState?.save();
// // // _confirmSaveProfile();
// // showConfirmationDialog(context);
// // }
// else {
// setState(() {
// showError = !isChecked; // Show error if the checkbox is not checked
// });
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text('Please accept the terms and conditions.',style: TextStyle(color: Colors.white),)),
// );
//}
//}
context.go('/myhomepage');
},
// {
// if ((_formKey.currentState?.validate() ?? false) &&
// (isChecked)) {
// _formKey.currentState?.save();
// showConfirmationDialog(context);
// } else {
// setState(() {
// showError =
// !isChecked; // Show error if the checkbox is not checked
// });
// }
// // if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
// // _formKey.currentState?.save();
// // showConfirmationDialog(context);
// // // if (isChecked) {
// // // _formKey.currentState?.save();
// // // // _confirmSaveProfile();
// // // showConfirmationDialog(context);
// // // }
// // else {
// // setState(() {
// // showError = !isChecked; // Show error if the checkbox is not checked
// // });
//
// // ScaffoldMessenger.of(context).showSnackBar(
// // SnackBar(content: Text('Please accept the terms and conditions.',style: TextStyle(color: Colors.white),)),
// // );
// //}
// //}
// },
icon: Icon(
Icons.save,
color: Colors.white,

View File

@ -157,97 +157,105 @@ class LoginRoute extends HookConsumerWidget {
final loginBtn = SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () async {
final isValid = formKey.currentState!.validate();
if (!isValid) return;
final session = await context.loaderWithErrorDialog(
() => ref
.read(
authUseCaseProvider.notifier,
)
.login(
emailCtl.text,
pwCtl.text,
),
errorDialogBuilder: (
error, [
StackTrace? stackTrace,
]) {
if (error == LoginError.invalidEmailPw) {
return context.simpleDialog(
title: context.translate(
'Incorrect credentials',
'أوراق غير صحيحة',
),
content: context.translate(
'Your email or password is invalid. Please try again.',
'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.',
),
);
}
if (error == LoginError.emailAddressNotVerified) {
return context.simpleDialog(
title: context.translate(
'Verification Error',
'خطأ التحقق',
),
content: context.translate(
'${emailCtl.text} is not a verified email address. Please check your email for a verification link.',
'${emailCtl.text} ليس عنوان بريد إلكتروني تم التحقق منه. يرجى التحقق من بريدك الإلكتروني للحصول على رابط التحقق.',
),
extraAction: ElevatedButton(
onPressed: () async {
Navigator.of(
context,
rootNavigator: true,
).pop();
await context.loaderWithErrorDialog(
() => ref
.read(authUseCaseProvider.notifier)
.requestVerificationEmail(emailCtl.text),
);
if (!context.mounted) return;
context.simpleDialog(
title: 'Email Re-sent',
content:
'We\'ve sent you the verification email at ${emailCtl.text} again.',
);
},
child: Text(
context.translate(
'I did not receive an email',
'لم أتلق بريدًا إلكترونيًا',
),
),
),
);
}
return context.simpleDialog();
},
);
if (!context.mounted || session == null) return;
// Extract userId from the session
final userId = session.id;
final bool isUpdate = await profileStatus(userId);
print('Is profile completed: $isUpdate');
if (isUpdate) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => DemoHome()),
);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => ProfileScreen(userId: userId)),
);
}
// context.go('/${context.language}/${BottomNavBarItem.home.routePath}');
onPressed: () {
context.go('/profile');
},
// async {
// final isValid = formKey.currentState!.validate();
// if (!isValid) return;
// final session = await context.loaderWithErrorDialog(
// () => ref
// .read(
// authUseCaseProvider.notifier,
// )
// .login(
// emailCtl.text,
// pwCtl.text,
// ),
// errorDialogBuilder: (
// error, [
// StackTrace? stackTrace,
// ]) {
// if (error == LoginError.invalidEmailPw) {
// return context.simpleDialog(
// title: context.translate(
// 'Incorrect credentials',
// 'أوراق غير صحيحة',
// ),
// content: context.translate(
// 'Your email or password is invalid. Please try again.',
// 'بريدك الإلكتروني أو كلمة المرور غير صالحة. حاول مرة اخرى.',
// ),
// );
// }
// if (error == LoginError.emailAddressNotVerified) {
// return context.simpleDialog(
// title: context.translate(
// 'Verification Error',
// 'خطأ التحقق',
// ),
// content: context.translate(
// '${emailCtl.text} is not a verified email address. Please check your email for a verification link.',
// '${emailCtl.text} ليس عنوان بريد إلكتروني تم التحقق منه. يرجى التحقق من بريدك الإلكتروني للحصول على رابط التحقق.',
// ),
// extraAction: ElevatedButton(
// onPressed: () {
// context.go('/profile');
// },
// // async {
// // Navigator.of(
// // context,
// // rootNavigator: true,
// // ).pop();
// // await context.loaderWithErrorDialog(
// // () => ref
// // .read(authUseCaseProvider.notifier)
// // .requestVerificationEmail(emailCtl.text),
// // );
// // if (!context.mounted) return;
// // context.simpleDialog(
// // title: 'Email Re-sent',
// // content:
// // 'We\'ve sent you the verification email at ${emailCtl.text} again.',
// // );
// // },
// child: Text(
// context.translate(
// 'I did not receive an email',
// 'لم أتلق بريدًا إلكترونيًا',
// ),
// ),
// ),
// );
// }
// return context.simpleDialog();
// },
// );
// // if (!context.mounted || session == null) return;
// // Extract userId from the session
// // final userId = session.id;
// //
// // final bool isUpdate = await profileStatus(userId);
// //
// // print('Is profile completed: $isUpdate');
//
// // if (isUpdate) {
// // Navigator.pushReplacement(
// // context,
// // MaterialPageRoute(builder: (context) => DemoHome()),
// // );
// // }
// // else {
//
// // Navigator.pushReplacement(
// // context,
// // MaterialPageRoute(
// // builder: (context) => ProfileScreen(userId: userId)),
// // );
// //}
//
// // context.go('/${context.language}/${BottomNavBarItem.home.routePath}');
// },
style: ButtonStyle(
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(

View File

@ -1,164 +1,167 @@
import 'dart:math';
import 'package:external_repos/external_repos.dart';
// import 'dart:math';
//
// import 'package:external_repos/external_repos.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_hooks/flutter_hooks.dart';
// import 'package:hooks_riverpod/hooks_riverpod.dart';
// import 'package:uae_stat/config/my_theme.dart';
// import 'package:uae_stat/domain/use_cases/language.dart';
// import 'package:uae_stat/presentation/components/indicators/indicator_view.dart';
// import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart';
// import 'package:uae_stat/presentation/components/my_drawer.dart';
// import 'package:uae_stat/presentation/components/space.dart';
// import 'package:uae_stat/presentation/components/themed_app_bar.dart';
// import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
//
// bool _wasHomeNeverBuiltThisSession = true;
//
// class HomeRoute extends HookConsumerWidget {
// const HomeRoute({super.key});
//
// @override
// Widget build(BuildContext context, WidgetRef ref) {
// final bodyContent = Column(
// children: IndicatorTopic.values.map(
// (topic) {
// final scaledHeight = context.height * pow(50 / 880, 1.1);
// final titleText = Text(
// context.translate(
// topic.nameEN,
// topic.nameAR,
// ),
// textAlign: TextAlign.center,
// style: TextStyle(
// fontFamily: context.translate(
// 'Roboto',
// 'NotoKufi',
// ),
// color: Colors.white,
// fontSize: 20,
// fontWeight: FontWeight.w700,
// ),
// );
// final title = Container(
// height: context.height > 880 ? null : scaledHeight,
// width: context.width,
// margin: const EdgeInsets.symmetric(
// horizontal: 24,
// ),
// padding: const EdgeInsets.symmetric(
// vertical: 5,
// ),
// decoration: BoxDecoration(
// color: MyTheme.topicColor(topic),
// borderRadius: BorderRadius.circular(100),
// ),
// child: context.height > 880
// ? titleText
// : FittedBox(
// fit: BoxFit.scaleDown,
// child: titleText,
// ),
// );
// final ids = IndicatorEnum.values.where(
// (id) => id.topic == topic,
// );
// const horizontalGap = 16.0;
// const verticalGap = 9.0;
// final boxWidth = (context.width - (3 * horizontalGap)) / 2;
// final indicatorBoxes = ids
// .map(
// (id) => SizedBox(
// width: boxWidth,
// height: double.infinity,
// child: IndicatorView(id),
// ),
// )
// .toList();
// final scrollCtl = useScrollController();
// if (_wasHomeNeverBuiltThisSession) {
// WidgetsBinding.instance.addPostFrameCallback(
// (_) async {
// final duration = kThemeAnimationDuration * 0.75;
// const distance = -30.0;
// scrollCtl.animateTo(
// distance,
// duration: duration,
// curve: Curves.fastOutSlowIn,
// );
// await Future.delayed(duration * 2.5);
// scrollCtl.animateTo(
// distance,
// duration: duration,
// curve: Curves.fastOutSlowIn,
// );
// _wasHomeNeverBuiltThisSession = false;
// },
// );
// }
// final content = SingleChildScrollView(
// controller: scrollCtl,
// padding: const EdgeInsets.symmetric(
// vertical: verticalGap,
// horizontal: horizontalGap,
// ),
// scrollDirection: Axis.horizontal,
// child: Column(
// children: [
// Expanded(
// child: Row(
// children: [
// indicatorBoxes[0],
// horizontalGap.horizontalSpace,
// indicatorBoxes[1],
// horizontalGap.horizontalSpace,
// indicatorBoxes[2],
// ],
// ),
// ),
// verticalGap.verticalSpace,
// Expanded(
// child: Row(
// children: [
// indicatorBoxes[3],
// horizontalGap.horizontalSpace,
// indicatorBoxes[4],
// horizontalGap.horizontalSpace,
// indicatorBoxes.length == 6
// ? indicatorBoxes[5]
// : boxWidth.horizontalSpace,
// ],
// ),
// ),
// ],
// ),
// );
// return Expanded(
// child: Column(
// children: [
// title,
// Expanded(
// child: content,
// ),
// ],
// ),
// );
// },
// ).toList(),
// );
// return SafeArea(
// bottom: false,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// const ThemedAppBar(),
// Expanded(
// child: bodyContent,
// ),
// ],
// ),
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:uae_stat/config/my_theme.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/components/indicators/indicator_view.dart';
import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart';
import 'package:uae_stat/presentation/components/my_drawer.dart';
import 'package:uae_stat/presentation/components/space.dart';
import 'package:uae_stat/presentation/components/themed_app_bar.dart';
bool _wasHomeNeverBuiltThisSession = true;
class HomeRoute extends HookConsumerWidget {
const HomeRoute({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final bodyContent = Column(
children: IndicatorTopic.values.map(
(topic) {
final scaledHeight = context.height * pow(50 / 880, 1.1);
final titleText = Text(
context.translate(
topic.nameEN,
topic.nameAR,
),
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w700,
),
);
final title = Container(
height: context.height > 880 ? null : scaledHeight,
width: context.width,
margin: const EdgeInsets.symmetric(
horizontal: 24,
),
padding: const EdgeInsets.symmetric(
vertical: 5,
),
decoration: BoxDecoration(
color: MyTheme.topicColor(topic),
borderRadius: BorderRadius.circular(100),
),
child: context.height > 880
? titleText
: FittedBox(
fit: BoxFit.scaleDown,
child: titleText,
),
);
final ids = IndicatorEnum.values.where(
(id) => id.topic == topic,
);
const horizontalGap = 16.0;
const verticalGap = 9.0;
final boxWidth = (context.width - (3 * horizontalGap)) / 2;
final indicatorBoxes = ids
.map(
(id) => SizedBox(
width: boxWidth,
height: double.infinity,
child: IndicatorView(id),
),
)
.toList();
final scrollCtl = useScrollController();
if (_wasHomeNeverBuiltThisSession) {
WidgetsBinding.instance.addPostFrameCallback(
(_) async {
final duration = kThemeAnimationDuration * 0.75;
const distance = -30.0;
scrollCtl.animateTo(
distance,
duration: duration,
curve: Curves.fastOutSlowIn,
);
await Future.delayed(duration * 2.5);
scrollCtl.animateTo(
distance,
duration: duration,
curve: Curves.fastOutSlowIn,
);
_wasHomeNeverBuiltThisSession = false;
},
);
}
final content = SingleChildScrollView(
controller: scrollCtl,
padding: const EdgeInsets.symmetric(
vertical: verticalGap,
horizontal: horizontalGap,
),
scrollDirection: Axis.horizontal,
child: Column(
children: [
Expanded(
child: Row(
children: [
indicatorBoxes[0],
horizontalGap.horizontalSpace,
indicatorBoxes[1],
horizontalGap.horizontalSpace,
indicatorBoxes[2],
],
),
),
verticalGap.verticalSpace,
Expanded(
child: Row(
children: [
indicatorBoxes[3],
horizontalGap.horizontalSpace,
indicatorBoxes[4],
horizontalGap.horizontalSpace,
indicatorBoxes.length == 6
? indicatorBoxes[5]
: boxWidth.horizontalSpace,
],
),
),
],
),
);
return Expanded(
child: Column(
children: [
title,
Expanded(
child: content,
),
],
),
);
},
).toList(),
);
return SafeArea(
bottom: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ThemedAppBar(),
Expanded(
child: bodyContent,
),
],
),
);
}
}
import '../../drawer_routes/custom_drawer_routes.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@ -170,10 +173,8 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
//drawer: MyDrawer(),
//bottomNavigationBar: MyBottomNavBar(),
body: HomeRoute(),
return BaseScaffold(
body: Center(child : Text("Home Page"))
);
}
}

View File

@ -0,0 +1,775 @@
import 'package:external_repos/external_repos.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/packages/go_router.dart';
import 'package:uae_stat/presentation/components/my_drawer.dart';
import 'package:mailer/mailer.dart';
import 'package:mailer/smtp_server.dart';
import 'package:uae_stat/presentation/components/space.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../../../../config/my_theme.dart';
import '../../../../domain/use_cases/preferences_use_case.dart';
import '../../../components/my_toggle.dart';
class FeedbackForm extends StatefulWidget {
const FeedbackForm({super.key});
@override
_FeedbackFormState createState() => _FeedbackFormState();
}
class _FeedbackFormState extends State<FeedbackForm>
with WidgetsBindingObserver {
final _pb =
PocketBase('https://pb.venbait.in'); // Initialize PocketBase client
// final _pb =
// PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client
final TextEditingController _feedbackController = TextEditingController();
double _easeOfUseRating = 0;
double _qualityRating = 0;
double _designRating = 0;
double _redundancyRating = 0;
int? _selectedEmojiIndex;
bool _isFeedbackSubmitted = false; // Track if feedback was submitted
bool _isFeedbackFailed = false; // New flag for failed submission
bool _isSmileySelected = true; // Track if smiley is selected
dynamic configEmail;
List<Map<String, dynamic>> get _emojiOptions => [
{
"icon": Icons.sentiment_very_dissatisfied,
"label": context.translate("Terrible", "رهيب"), // Translate here
"value": 1,
},
{
"icon": Icons.sentiment_dissatisfied,
"label": context.translate("Bad", "سيء"), // Translate here
"value": 2,
},
{
"icon": Icons.sentiment_neutral,
"label": context.translate("Okay", "تمام"), // Translate here
"value": 3,
},
{
"icon": Icons.sentiment_satisfied,
"label": context.translate("Good", "جيد"), // Translate here
"value": 4,
},
{
"icon": Icons.sentiment_very_satisfied,
"label": context.translate("Amazing", "مدهش"), // Translate here
"value": 5,
},
];
static const int _characterLimit = 1200;
final RegExp _allowedCharacters = RegExp(r'^[a-zA-Z0-9 .,!?-]*$');
bool _hasError = false;
String _errorMessage = '';
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_loadFeedbackText();
_feedbackController.addListener(_handleTextChange);
fetchEmailConfiguration();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.detached ||
state == AppLifecycleState.paused) {
_removeFeedbackText();
}
}
// Detect when navigating to another page
@override
void didPushNext() {
// Called when a new page is pushed on top of FeedbackPage
_removeFeedbackText();
}
Future<void> _saveFeedbackText(
int emojiIndex, String ratingKey, double ratingValue) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('feedbackText', _feedbackController.text);
await prefs.setInt('selected_emoji_index', emojiIndex);
await prefs.setDouble(ratingKey, ratingValue);
print('one save');
}
Future<void> _saveAllRatings() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setDouble('ease_of_use_rating', _easeOfUseRating);
await prefs.setDouble('quality_rating', _qualityRating);
await prefs.setDouble('design_rating', _designRating);
await prefs.setDouble('redundancy_rating', _redundancyRating);
}
Future<void> _loadFeedbackText() async {
final prefs = await SharedPreferences.getInstance();
// Step 1: Load values from SharedPreferences into variables
final feedbackText = prefs.getString('feedbackText') ?? '';
final savedIndex = prefs.getInt('selected_emoji_index');
final easeOfUseRating = prefs.getDouble('ease_of_use_rating') ?? 0;
final qualityRating = prefs.getDouble('quality_rating') ?? 0;
final designRating = prefs.getDouble('design_rating') ?? 0;
final redundancyRating = prefs.getDouble('redundancy_rating') ?? 0;
// Step 2: Populate fields with values without immediately clearing storage
setState(() {
_feedbackController.text = feedbackText;
if (savedIndex != null) {
_selectedEmojiIndex = savedIndex;
_isSmileySelected = true; // Indicating the user selected an emoji
}
_easeOfUseRating = easeOfUseRating;
_qualityRating = qualityRating;
_designRating = designRating;
_redundancyRating = redundancyRating;
});
// Step 3: Clear storage after a slight delay
Future.delayed(Duration(milliseconds: 50), () async {
await prefs.remove('feedbackText');
await prefs.remove('selected_emoji_index');
await prefs.remove('ease_of_use_rating');
await prefs.remove('quality_rating');
await prefs.remove('design_rating');
await prefs.remove('redundancy_rating');
});
}
// Remove feedback text from local storage
Future<void> _removeFeedbackText() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('feedbackText');
await prefs.remove('selected_emoji_index');
await prefs.remove('ease_of_use_rating');
await prefs.remove('quality_rating');
await prefs.remove('design_rating');
await prefs.remove('redundancy_rating');
}
void _handleTextChange() {
String currentText = _feedbackController.text;
// Enforce character limit and truncate excess on paste
if (currentText.length > _characterLimit) {
_feedbackController.text = currentText.substring(0, _characterLimit);
_feedbackController.selection = TextSelection.fromPosition(
TextPosition(offset: _feedbackController.text.length),
);
}
// Validate characters
if (!_allowedCharacters.hasMatch(currentText)) {
setState(() {
_hasError = true;
_errorMessage = "Invalid Characters";
});
} else {
setState(() {
_hasError = false;
_errorMessage = '';
});
}
}
@override
Widget build(BuildContext context) {
return BaseScaffold(
// appBar: AppBar(
// backgroundColor: const Color(0xFFf8f9ff),
// title: Text(context.translate('Feedback Form', 'نموذج الملاحظات')),
// actions: [
// Align(
// alignment: AlignmentDirectional.topEnd,
// child: LangToggle(
// onSaveFeedback: _saveFeedbackText,
// onLoadFeedback: _loadFeedbackText,
// selectedEmojiIndex: _selectedEmojiIndex ?? 0,
// easeOfUseRating: _easeOfUseRating,
// qualityRating: _qualityRating,
// designRating: _designRating,
// redundancyRating: _redundancyRating,
// ),
// ),
// ],
// ),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: _isFeedbackSubmitted
? _buildThankYouMessage()
: _isFeedbackFailed
? _buildFailureMessage()
: _buildFeedbackForm(),
),
),
);
}
Widget _buildFeedbackForm() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
context.translate(
'Do you have a suggestion or had any problem? Let us know.',
'هل لديك اقتراح أو واجهت أي مشكلة؟ اسمحوا لنا أن نعرف.',
),
style: const TextStyle(
fontSize: 18,
color: Color(0xFF898C81),
fontFamily: 'Roboto',
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
Text(
context.translate('How was your experience with us today?',
'كيف كانت تجربتك معنا اليوم؟'),
style: const TextStyle(
fontSize: 18,
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
color: Color(0xFF898C81),
),
),
const SizedBox(height: 10),
Container(
decoration: BoxDecoration(
border: Border.all(
color: _isSmileySelected ? Colors.transparent : Colors.red,
width: 1.5,
),
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.all(8),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(_emojiOptions.length, (index) {
return _buildEmojiButton(
icon: _emojiOptions[index]["icon"],
label: _emojiOptions[index]["label"],
index: index,
);
}),
),
if (!_isSmileySelected) // Show the error message if no smiley is selected
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
context.translate(
'Please rate your experience before submitting your feedback.',
'يرجى تقييم تجربتك قبل تقديم ملاحظاتك.',
),
style: TextStyle(color: Colors.red, fontSize: 14),
),
),
],
),
),
const SizedBox(height: 30),
Text(
context.translate('How good did we do in these aspects?',
'ما مدى جودة ما قمنا به في هذه الجوانب؟'),
style: const TextStyle(
fontSize: 18,
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
color: Color(0xFF898C81),
),
),
const SizedBox(height: 20),
_buildRatingRow(
context.translate('Ease of use', 'سهولة الاستخدام'),
_easeOfUseRating,
(rating) {
setState(() {
_easeOfUseRating = rating;
});
},
),
_buildRatingRow(
context.translate('Quality', 'جودة'),
_qualityRating,
(rating) {
setState(() {
_qualityRating = rating;
});
},
),
_buildRatingRow(
context.translate('Design', 'تصميم'),
_designRating,
(rating) {
setState(() {
_designRating = rating;
});
},
),
_buildRatingRow(
context.translate('Redundant', 'متكرر'),
_redundancyRating,
(rating) {
setState(() {
_redundancyRating = rating;
});
},
),
const SizedBox(height: 20),
TextField(
controller: _feedbackController,
minLines: 5, // Start with 5 lines
maxLines: null, // Allows the field to expand automatically
maxLength: _characterLimit,
decoration: InputDecoration(
hintText: context.translate(
'Tell us how we can improve', 'أخبرنا كيف يمكننا تحسين'),
border: OutlineInputBorder(
borderSide: BorderSide(
color: _hasError ? Colors.red : Color(0xFF7296BE),
),
),
errorText:
_hasError ? _errorMessage : null, // Show error below field
),
onChanged: (text) {
// Trigger re-validation and character limit on each change
_handleTextChange();
},
),
const SizedBox(height: 20),
Center(
child: ElevatedButton(
onPressed: _submitFeedback,
style: ButtonStyle(
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 5.5),
),
textStyle: WidgetStatePropertyAll(
TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
backgroundColor: WidgetStatePropertyAll(
MyTheme.topicColor(IndicatorTopic.environment),
),
foregroundColor: const WidgetStatePropertyAll(
Colors.white,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.translate(
'Submit',
'يُقدِّم',
),
),
6.horizontalSpace,
const Icon(Icons.chevron_right_outlined),
],
),
),
),
],
);
}
Widget _buildThankYouMessage() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.thumb_up, size: 80, color: Color(0xFF7DAFBC)),
const SizedBox(height: 20),
Text(
"Thank You",
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
const Text(
"For your valuable feedback, we truly appreciate your input!",
style: TextStyle(fontSize: 16),
textAlign: TextAlign.center,
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: () => context.go('/myhomepage'),
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
child: const Text("Go to Home"),
),
],
),
);
}
// New widget for failure message
Widget _buildFailureMessage() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.error, size: 80, color: Colors.red),
const SizedBox(height: 20),
const Text("Failed to Share Feedback",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
const Text("Your feedback could not be submitted. Please try again.",
style: TextStyle(fontSize: 16), textAlign: TextAlign.center),
const SizedBox(height: 30),
ElevatedButton(
onPressed: () {
setState(() {
_isFeedbackFailed = false; // Reset failure state
});
},
child: const Text("Retry"),
),
],
),
);
}
Widget _buildEmojiButton({
required IconData icon,
required String label,
required int index,
}) {
bool isSelected = _selectedEmojiIndex == index;
return Column(
children: [
IconButton(
icon: Icon(icon, size: 40),
color: isSelected ? Colors.green : Colors.amber,
onPressed: () {
setState(() {
_selectedEmojiIndex = index;
_isSmileySelected = true; // Hide error when a smiley is selected
});
},
),
Text(
label,
style: TextStyle(
fontWeight: FontWeight.w400,
color: isSelected ? Colors.green : Color(0xFF000000),
),
),
],
);
}
Widget _buildRatingRow(
String label,
double rating,
Function(double) onRatingUpdate,
) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label,
style: const TextStyle(
fontSize: 14,
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
color: Color(0xFF898C81),
)),
RatingBar.builder(
initialRating: rating,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
itemCount: 5,
itemSize: 30,
itemBuilder: (context, _) => const Icon(
Icons.star,
color: Colors.amber,
),
onRatingUpdate: onRatingUpdate,
unratedColor: Color(0xFF8E8E8E),
),
],
);
}
Future<void> _submitFeedback() async {
if (_selectedEmojiIndex == null) {
setState(() {
_isSmileySelected = false;
});
return;
} else {
setState(() {
_isSmileySelected = true;
});
}
if (_hasError) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please correct the errors before submitting.")),
);
return;
}
final feedbackData = {
"ease_of_use": _easeOfUseRating,
"quality": _qualityRating,
"design": _designRating,
"redundancy": _redundancyRating,
"emoji_rating": _emojiOptions[_selectedEmojiIndex!]
["label"], // Emoji rating
"feedback": _feedbackController.text,
};
try {
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token;
final response = await _pb
.collection('feedback')
.create(body: feedbackData, headers: {'Authorization': adminToken});
if (response != null) {
final createdTime = response.created;
// Send email
await sendFeedbackEmail(feedbackData, createdTime);
await _removeFeedbackText();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Feedback submitted successfully!")),
);
setState(() {
_isFeedbackSubmitted = true;
_isFeedbackFailed = false;
_resetFeedbackForm();
});
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to submit feedback: $e")),
);
setState(() {
_isFeedbackFailed = true; // Update state to show failure message
});
}
}
void _resetFeedbackForm() {
_easeOfUseRating = 0;
_qualityRating = 0;
_designRating = 0;
_redundancyRating = 0;
_selectedEmojiIndex = null;
_feedbackController.clear();
}
Future<void> fetchEmailConfiguration() async {
try {
// Fetch data from the email_configuration collection
final response =
await _pb.collection('email_configuration').getFullList();
// Filter the data where the label is "Feedback"
final feedbackConfig = response.firstWhere(
(item) =>
item.data['label'] == 'Feedback', // Accessing the 'data' property
);
// Check if a match is found
if (feedbackConfig != null) {
configEmail = feedbackConfig.data['email']; // Access the 'email' value
} else {
print('No feedback configuration found.');
}
} catch (e) {
print('Error fetching email configuration: $e');
}
}
Future<void> sendFeedbackEmail(
Map<String, dynamic> feedbackData, createdTime) async {
String username = 'emailapikey'; // Your SMTP username (API key)
String password =
'PHtE6r0MFu66jTQp8BAFsP7sH5TwNd4v/+02KwBH5ItACvAES01Tot4okDawqhoiB/FEHfaey4Nvteyf5ePQJG28YW9OCWqyqK3sx/VYSPOZsbq6x00auVwYd0zUVY7pe9ds0yLTvNraNA=='; // Your SMTP password
final smtpServer = SmtpServer('smtp.zeptomail.in',
port: 587,
username: username,
password: password,
ssl: false, // Use TLS
ignoreBadCertificate:
true); // Set to true if you're testing with a self-signed certificate
// Check if additional feedback was provided
String additionalFeedback = feedbackData["feedback"]?.isNotEmpty == true
? feedbackData["feedback"]
: "No additional feedback provided.";
// Format separately for date and time
// Parse the string to DateTime
// Parse the input as UTC and convert to DateTime in UTC timezone
DateTime feedbackDateTime = DateTime.parse(createdTime).toUtc();
// Format date as DD-MM-YYYY in UTC
final String formattedDate =
DateFormat('dd-MM-yyyy').format(feedbackDateTime);
// Format to the desired output: "dd.MM.yyyy HH:mm 'UTC'"
final DateFormat formatter = DateFormat("dd.MM.yyyy HH:mm 'UTC'");
String formattedDateTime = formatter.format(feedbackDateTime);
String email = configEmail; // Direct assignment
// Create the email message
final message = Message()
..from = Address('bbone@venbait.in', 'FCSC')
..recipients.add(email) // Set the recipient email
..subject = 'UAE Stats Feedback'
..text = '''
Dear [App Owner/Admin],
You have received new feedback from a user through the mobile application.
User Details:
1. Name: Guest
2. Date of Submission: $formattedDate
3. Time of Submission: $formattedDateTime
Feedback:
1. How was your experience with us today? Rating: ${feedbackData["emoji_rating"]}
2. How did we perform in key areas?
1. Ease of Use: ${feedbackData["ease_of_use"]}
2. Quality: ${feedbackData["quality"]}
3. Design: ${feedbackData["design"]}
4. Redundancy: ${feedbackData["redundancy"]}
3. Additional Feedback:
1. $additionalFeedback
Thank you,
The FCSC App Team
''';
try {
// Send the email
print("Message details:");
print("From: ${message.from}");
print("To: ${message.recipients}");
print("Subject: ${message.subject}");
print("Body: ${message.text}");
final sendReport = await send(message, smtpServer);
print('Message sent: ' + sendReport.toString());
} catch (e) {
print('Message not sent: $e');
// Handle the error as needed
}
}
@override
void dispose() {
_feedbackController.dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
class LangToggle extends ConsumerWidget {
final Future<void> Function(
int emojiIndex, String ratingKey, double ratingValue) onSaveFeedback;
final Future<void> Function() onLoadFeedback;
final int selectedEmojiIndex;
final double easeOfUseRating;
final double qualityRating;
final double designRating;
final double redundancyRating;
const LangToggle({
required this.onSaveFeedback,
required this.onLoadFeedback,
required this.selectedEmojiIndex,
required this.easeOfUseRating,
required this.qualityRating,
required this.designRating,
required this.redundancyRating,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final isOn = context.language == LanguageLocale.enUS;
return MyToggle(
isOn: isOn,
onTap: () async {
await onSaveFeedback(
selectedEmojiIndex,
'ease_of_use_rating',
easeOfUseRating,
);
await onSaveFeedback(
selectedEmojiIndex,
'quality_rating',
qualityRating,
);
await onSaveFeedback(
selectedEmojiIndex,
'design_rating',
designRating,
);
await onSaveFeedback(
selectedEmojiIndex,
'redundancy_rating',
redundancyRating,
);
final languageAfter = isOn ? LanguageLocale.arAE : LanguageLocale.enUS;
final grs = GoRouterState.of(context);
grs.pathParameters['locale'] = languageAfter.toString();
context.go(grs.pathWithParameters);
ref.read(preferencesUseCaseProvider.notifier).updatePreferences(
(prefs) => prefs.copyWith(language: languageAfter),
);
await onLoadFeedback(); // Reload feedback text after toggling language
},
knobTextWhenOn: 'ع',
knobTextWhenOff: 'EN',
pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300,
);
}
}

View File

@ -0,0 +1,254 @@
import 'package:flutter/material.dart';
import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart';
import 'package:uae_stat/presentation/components/my_drawer.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
class ManageUserRouter extends StatefulWidget {
@override
State<ManageUserRouter> createState() => _ManageUserRouterState();
}
class _ManageUserRouterState extends State<ManageUserRouter> {
// Sample data for the table
final List<User> userData = List.generate(
5,
(index) => User(
userName: 'Conan Keller ${index + 1}',
emailId: 'ConanKeller${index + 1}@gmail.com',
registrationDate: '18/07/2024',
status: 'Pending',
),
);
// Sorting state
int _sortColumnIndex = 0;
bool _isAscending = true;
// Method to sort the data based on a column
void _sort<T>(Comparable<T> Function(User user) getField, int columnIndex,
bool ascending) {
setState(() {
_sortColumnIndex = columnIndex;
_isAscending = ascending;
userData.sort((a, b) {
final aValue = getField(a);
final bValue = getField(b);
return ascending
? Comparable.compare(aValue, bValue)
: Comparable.compare(bValue, aValue);
});
});
}
// Define dropdown items
final List<String> statusOptions = ['Approved', 'Denied', 'Pending'];
// Method to get status color
Color getStatusColor(String status) {
switch (status) {
case 'Approved':
return Colors.green;
case 'Denied':
return Colors.red;
case 'Pending':
return Colors.blue;
default:
return Colors.black;
}
}
//Method to show a confirmation dialog when status is changed
Future<void> _showConfirmationDialog(User user, String newStatus) async {
double myheight = MediaQuery.of(context).size.height;
return showDialog<void>(
context: context,
barrierDismissible: false, // User must tap button to dismiss dialog
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0), // Rounded corners
),
contentPadding: EdgeInsets.zero, // Ensure no padding issues with close icon
content: Stack(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: myheight/30,),
Text(
'Are you sure you want to change \n the status to $newStatus?',
style: TextStyle(fontSize: 15),
textAlign: TextAlign.center,
),
],
),
),
Positioned(
right: 0,
top: 0,
child: IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.of(context).pop(); // Close the dialog
},
),
),
],
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TextButton(
onPressed: () {
Navigator.of(context)
.pop(); // Close dialog without changing status
},
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
10.0), // Adjust the radius as needed
),
side: BorderSide(
color: Colors.blue, // Set the outline color
width: 2.0, // Set the border width
),
),
child: Text('No'),
),
TextButton(
onPressed: () {
setState(() {
user.status = newStatus; // Change status
});
Navigator.of(context).pop();
},
style: TextButton.styleFrom(
backgroundColor: Colors.blue, // Set background color
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10.0), // Set text color
)),
child: Text(
'Yes',
style: TextStyle(color: Colors.white),
),
),
],
)
],
);
},
);
}
@override
Widget build(BuildContext context) {
double myheight = MediaQuery.of(context).size.height;
return BaseScaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
child: Column(
children: [
TextField(
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search),
hintText: 'Search',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
),
),
SizedBox(height: myheight / 40),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: _isAscending,
columns: [
DataColumn(
label: const Text('User Name'),
onSort: (columnIndex, ascending) => _sort(
(user) => user.userName, columnIndex, ascending),
numeric: false,
),
DataColumn(
label: const Text('Email ID'),
onSort: (columnIndex, ascending) =>
_sort((user) => user.emailId, columnIndex, ascending),
numeric: false,
),
DataColumn(
label: const Text('Registration Date'),
onSort: (columnIndex, ascending) => _sort(
(user) => user.registrationDate,
columnIndex,
ascending),
numeric: false,
),
DataColumn(
label: const Text('Status'),
onSort: (columnIndex, ascending) =>
_sort((user) => user.status, columnIndex, ascending),
numeric: false,
),
],
rows: userData.map((user) {
return DataRow(
cells: [
DataCell(Text(user.userName)),
DataCell(Text(user.emailId)),
DataCell(Text(user.registrationDate)),
DataCell(
DropdownButton<String>(
value: user.status,
items: statusOptions.map((status) {
return DropdownMenuItem<String>(
value: status,
child: Text(
status,
style:
TextStyle(color: getStatusColor(status)),
),
);
}).toList(),
onChanged: (String? newStatus) {
if (newStatus != null) {
_showConfirmationDialog(user,
newStatus); // Show dialog for confirmation
}
},
),
),
],
);
}).toList(),
),
),
],
),
),
),
);
}
}
// User data model
class User {
final String userName;
final String emailId;
final String registrationDate;
String status;
User({
required this.userName,
required this.emailId,
required this.registrationDate,
this.status = 'Pending',
});
}

View File

@ -0,0 +1,108 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class BaseScaffold extends StatelessWidget {
final Widget body;
const BaseScaffold({required this.body});
@override
Widget build(BuildContext context) {
// Get the current route to highlight the active item
String currentRoute = GoRouterState.of(context).matchedLocation;
return Scaffold(
appBar: AppBar(title: Text(""),),
drawer: Drawer(
child: ListView(
children: [
DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(children: [
],)
Divider(),
ListTile()
],
),
//child: Text('Drawer Header', style: TextStyle(color: Colors.white, fontSize: 24)),
),
ListTile(
leading: Icon(Icons.person),
title: Text('Profile'),
onTap: () => context.go('/profile'),
),
ListTile(
leading: Icon(Icons.note),
title: Text('Feedback'),
onTap: () => context.go('/feedback'),
),
ListTile(
leading : Icon(Icons.percent),
title: Text('Manage User'),
onTap: () => context.go('/manageuser'),
),
],
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _getSelectedIndex(currentRoute),
onTap: (index) => _onItemTapped(context, index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.home,color: Colors.black,), label: 'Home',),
BottomNavigationBarItem(icon: Icon(Icons.info,color: Colors.black,), label: 'About',),
BottomNavigationBarItem(icon: Icon(Icons.settings,color: Colors.black,), label: 'Settings'),
BottomNavigationBarItem(icon: Icon(Icons.person,color: Colors.black,), label: 'Profile'),
],
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
),
body: body,
);
}
//Map the current route to the selected index
int _getSelectedIndex(String route) {
switch (route) {
case '/':
return 0;
case '/about':
return 1;
case '/settings':
return 2;
case '/profile':
return 3;
default:
return 0;
}
}
//Handle navigation when an item is tapped
void _onItemTapped(BuildContext context, int index) {
switch (index) {
case 0:
context.go('/');
break;
case 1:
context.go('/about');
break;
case 2:
context.go('/settings');
break;
case 3:
context.go('/profile');
break;
}
}
}