UAE number page search functionality added

This commit is contained in:
venbaittech 2025-02-24 18:41:21 +05:30
parent 9368e08f91
commit cd141bfcb4
5 changed files with 910 additions and 556 deletions

View File

@ -42,9 +42,7 @@ class UaeNumbers extends StatelessWidget {
'UAE Numbers', 'UAE Numbers',
'أرقام الإمارات', 'أرقام الإمارات',
)), )),
body: uaenumberWidget(), body: uaenumberWidget(),
), ),
); );
} }
@ -59,7 +57,9 @@ class uaenumberWidget extends ConsumerStatefulWidget {
class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> { class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
@override @override
TextEditingController _searchController = TextEditingController();
List<dynamic> homePageData = []; List<dynamic> homePageData = [];
List<dynamic> filteredData = [];
bool isLoading = true; bool isLoading = true;
int? expandedIndex = 0; int? expandedIndex = 0;
@ -68,6 +68,17 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
super.initState(); super.initState();
final locale = ref.read(localeProvider); final locale = ref.read(localeProvider);
fetchData(locale?.languageCode ?? 'en'); fetchData(locale?.languageCode ?? 'en');
_searchController.addListener(() {
setState(() {
filterData(_searchController.text);
});
});
}
@override
void dispose() {
_searchController.dispose();
super.dispose();
} }
Future<void> fetchData(locale) async { Future<void> fetchData(locale) async {
@ -77,7 +88,13 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
final response = await http.get(Uri.parse(baseUrl + '?language=$locale')); final response = await http.get(Uri.parse(baseUrl + '?language=$locale'));
if (response.statusCode == 200) { if (response.statusCode == 200) {
setState(() { setState(() {
homePageData = json.decode(response.body); homePageData = (json.decode(response.body) as List)
.map((e) => Map<String, dynamic>.from(e))
.toList();
filteredData = List.from(homePageData);
// Show all initially
// print("HomeDAta $homePageData"); // print("HomeDAta $homePageData");
isLoading = false; isLoading = false;
}); });
@ -92,6 +109,63 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
} }
} }
void filterData(String query) {
if (query.isEmpty) {
setState(() {
filteredData = List.from(homePageData); // Reset if empty
});
return;
}
List<Map<String, dynamic>> tempList = [];
for (var mainTopic in homePageData) {
if (mainTopic["main_topic"].toLowerCase().contains(query.toLowerCase())) {
tempList.add(mainTopic);
continue;
}
List<Map<String, dynamic>> matchingSubTopics = [];
for (var subTopic in mainTopic["sub_topics"]) {
if (subTopic["sub_topic"].toLowerCase().contains(query.toLowerCase())) {
matchingSubTopics.add(subTopic);
continue;
}
List<Map<String, dynamic>> matchingTileData = [];
for (var tile in subTopic["tile_data"]) {
if (tile["data_set"].toLowerCase().contains(query.toLowerCase()) ||
tile["data_set_tile_heading"]
.toLowerCase()
.contains(query.toLowerCase())) {
matchingTileData.add(tile);
}
}
if (matchingTileData.isNotEmpty) {
matchingSubTopics.add({
...subTopic,
"tile_data": matchingTileData,
});
}
}
if (matchingSubTopics.isNotEmpty) {
tempList.add({
...mainTopic,
"sub_topics": matchingSubTopics,
});
}
}
setState(() {
filteredData = tempList;
print(filteredData); // Debugging: Check filtered output in console
});
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
@ -101,7 +175,8 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
return Padding( return Padding(
padding: const EdgeInsets.only(left: 16.0,right: 16.0,top: 5.0,bottom: 5.0), padding:
const EdgeInsets.only(left: 16.0, right: 16.0, top: 5.0, bottom: 5.0),
child: ListView( child: ListView(
children: [ children: [
Container( Container(
@ -113,39 +188,43 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
), ),
child: Padding( child: Padding(
padding: EdgeInsets.only(left: 12.0), padding: EdgeInsets.only(left: 12.0),
child: TextField( child: TextField(
decoration: InputDecoration( controller: _searchController,
hintText: "Search", onChanged: (value) {
hintStyle: TextStyle(color: Color(0xFF898C81)), filterData(
value); // Call filter function directly on input change
},
decoration: InputDecoration(
hintText: "Search",
hintStyle: TextStyle(color: Color(0xFF898C81)),
prefixIcon: Image(
image: ExactAssetImage(MiscIconAssetPath.search),
width: 24,
height: 24,
),
prefixIcon: Image( // prefixIcon: Image.asset(
image: ExactAssetImage(MiscIconAssetPath.search), // MiscIconAssetPath.search,
width: 24, // // fit: BoxFit.contain,
height: 24, // ),
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 18.0),
), ),
// prefixIcon: Image.asset(
// MiscIconAssetPath.search,
// // fit: BoxFit.contain,
// ),
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 18.0),
), ),
),), ),
), ),
SizedBox( SizedBox(
height: myheight / 40, height: myheight / 40,
), ),
...homePageData.map<Widget>((mainTopic) { ...filteredData.map<Widget>((mainTopic) {
String colorPattern = mainTopic['color_pattern']; String colorPattern = mainTopic['color_pattern'];
print('colorPattern $colorPattern'); print('colorPattern $colorPattern');
Color backgroundColor = Color(int.parse(colorPattern)); Color backgroundColor = Color(int.parse(colorPattern));
print('backgroundColor $backgroundColor'); print('backgroundColor $backgroundColor');
Color borderColor = backgroundColor; Color borderColor = backgroundColor;
int index = homePageData.indexOf(mainTopic); int index = filteredData.indexOf(mainTopic);
bool isFirstTile = index == 0; bool isFirstTile = index == 0;
return CustomExpandableTile( return CustomExpandableTile(
@ -158,8 +237,8 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
}, },
title: mainTopic['main_topic'], title: mainTopic['main_topic'],
titleBackgroundColor: backgroundColor, titleBackgroundColor: backgroundColor,
children: _buildSubTopics(mainTopic['sub_topics'] ?? [], mywidth,myheight, children: _buildSubTopics(mainTopic['sub_topics'] ?? [], mywidth,
borderColor, colorPattern, mainTopic['main_topic']), myheight, borderColor, colorPattern, mainTopic['main_topic']),
); );
}), }),
], ],
@ -167,8 +246,8 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
); );
} }
List<Widget> _buildSubTopics(List<dynamic> subTopics, double myWidth,myheight, List<Widget> _buildSubTopics(List<dynamic> subTopics, double myWidth,
Color borderColor, String colorPattern, mainTopic) { myheight, Color borderColor, String colorPattern, mainTopic) {
print('colorPattern123 $borderColor'); print('colorPattern123 $borderColor');
// Sort sub-topics based on `sub_topic_list_order` // Sort sub-topics based on `sub_topic_list_order`
subTopics.sort((a, b) => (a['sub_topic_list_order'] ?? 0) subTopics.sort((a, b) => (a['sub_topic_list_order'] ?? 0)
@ -209,7 +288,6 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
? myWidth ? myWidth
: (myWidth - 16) / 2.6; // Subtract spacing for padding : (myWidth - 16) / 2.6; // Subtract spacing for padding
return Expanded( return Expanded(
child: Padding( child: Padding(
padding: padding:
@ -224,7 +302,7 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
borderColor, borderColor,
colorPattern, colorPattern,
cardWidth, cardWidth,
mainTopic// Pass the calculated width mainTopic // Pass the calculated width
), ),
), ),
); );
@ -237,7 +315,7 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
Widget buildCategoryTitle(String title, Color color) { Widget buildCategoryTitle(String title, Color color) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 1.2,bottom: 1.2), padding: const EdgeInsets.only(top: 1.2, bottom: 1.2),
// padding: const EdgeInsets.symmetric(vertical: 8.0), // padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Center( child: Center(
child: Text( child: Text(
@ -275,7 +353,6 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
Color boldColor, Color boldColor,
colorPattern, colorPattern,
double mywidth, double mywidth,
String mainTopic) { String mainTopic) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
@ -305,18 +382,16 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
borderRadius: borderRadius:
BorderRadius.circular(12), // Optional: Rounded corners BorderRadius.circular(12), // Optional: Rounded corners
), ),
padding: const EdgeInsets.only(top: 3.0, bottom: 3.0, left: 5.0, right: 5.0), padding: const EdgeInsets.only(
top: 3.0, bottom: 3.0, left: 5.0, right: 5.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
title, title,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: robotoRegular11, style: robotoRegular11,
), ),
SizedBox(height: 0.1), SizedBox(height: 0.1),
Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle), Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle),
SizedBox(height: 0.3), SizedBox(height: 0.3),
@ -377,37 +452,37 @@ class _CustomExpandableTileState extends State<CustomExpandableTile> {
onTap: () => widget.onTap(widget.index), onTap: () => widget.onTap(widget.index),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, // Ensuring the background outside the rounded container is white color: Colors
.white, // Ensuring the background outside the rounded container is white
), ),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: widget.titleBackgroundColor, color: widget.titleBackgroundColor,
borderRadius: BorderRadius.all(Radius.circular(35)) borderRadius: BorderRadius.all(Radius.circular(35))),
), padding: const EdgeInsets.only(
padding: const EdgeInsets.only( left: 16, bottom: 5, top: 5, right: 10),
left: 16, bottom: 5, top: 5, right: 10), child: Row(
child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
children: [ Text(
Text( widget.title,
widget.title, style: TextStyle(
style: TextStyle( color: Colors.white,
color: Colors.white, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, fontSize: 20,
fontSize: 20, ),
), ),
), Icon(
Icon( widget.isExpanded
widget.isExpanded ? Icons.keyboard_arrow_up
? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
: Icons.keyboard_arrow_down, color: Colors.white,
color: Colors.white, size: 28.0,
size: 28.0, ),
), ],
], ),
), ),
), ),
),
), ),
ClipRRect( ClipRRect(
child: AnimatedContainer( child: AnimatedContainer(

View File

@ -2051,34 +2051,40 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
child: Container( child: Container(
padding: EdgeInsets.all(4), padding: EdgeInsets.all(4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isBookmarked ?Colors.white.withAlpha(90):null, // Background color color: isBookmarked
borderRadius: BorderRadius.circular(8), // Curved corners ? Colors.white.withAlpha(90)
: null, // Background color
borderRadius: BorderRadius.circular(
8), // Curved corners
), ),
child: Row( child: Row(
children: [ children: [
isBookmarked? isBookmarked
Text( ? Text(
context.translate( context.translate(
'Bookmarked', 'Bookmarked',
'إشارة مرجعية', 'إشارة مرجعية',
), ),
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: Color(int.parse( color: Color(int.parse(
(chartScreenData['body_color'] ?? '#898C81') (chartScreenData[
.replaceFirst('#', '0xff'))), 'body_color'] ??
), '#898C81')
): .replaceFirst(
Text( '#', '0xff'))),
context.translate( ),
'Bookmark', )
'إشارة مرجعية', : Text(
), context.translate(
style: const TextStyle( 'Bookmark',
fontSize: 16, 'إشارة مرجعية',
color: Colors.white, ),
), style: const TextStyle(
), fontSize: 16,
color: Colors.white,
),
),
SizedBox(width: 5), SizedBox(width: 5),
// Text( // Text(
@ -2103,8 +2109,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Icons.bookmarks_rounded, Icons.bookmarks_rounded,
color: isBookmarked color: isBookmarked
? Color(int.parse( ? Color(int.parse(
(chartScreenData['body_color'] ?? '#898C81') (chartScreenData[
.replaceFirst('#', '0xff'))) 'body_color'] ??
'#898C81')
.replaceFirst(
'#', '0xff')))
: Colors.white, : Colors.white,
), ),
], ],
@ -2128,14 +2137,13 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
SizedBox(width: 5), SizedBox(width: 5),
GestureDetector( GestureDetector(
onTap: () => shareCurrentPage(context), onTap: () => shareCurrentPage(context),
child: SvgPicture.asset( child: SvgPicture.asset(
UaeNumbersAssetPath.share, UaeNumbersAssetPath.share,
semanticsLabel: 'share', semanticsLabel: 'share',
width: 24, width: 24,
height: 24, height: 24,
) )),
),
], ],
), ),
SizedBox( SizedBox(
@ -2274,6 +2282,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
print('item item item $item'); print('item item item $item');
final chart_type = item['chart_type']; final chart_type = item['chart_type'];
final chart_heading = item['chart_heading']; final chart_heading = item['chart_heading'];
final card_full_length =
item['card_full_length'];
print('cardfulllength $card_full_length');
final response = final response =
item['response'] as List<dynamic>? ?? item['response'] as List<dynamic>? ??
[]; [];
@ -2287,11 +2298,15 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
chart_type == 'averages') chart_type == 'averages')
? 180.0 ? 180.0
: 130.0; : 130.0;
// double myheight = MediaQuery.of(context).size.height;
// double mywidth = MediaQuery.of(context).size.width;
// final cardWidth = rowItems.length == 1 ? myWidth : (myWidth - 16) / 2.6;
print('find width $cardData');
final itemdata = cardData[index]; final itemdata = cardData[index];
bool isLastSingleCard = // bool isOddLength = cardData.length % 2 != 0;
(index == cardData.length - 1 && // bool isLastSingleCard = isOddLength &&
cardData.length % 2 != 0); // index == cardData.length - 1;
// print('isLastSingleCard $isLastSingleCard');
if (response.isEmpty) { if (response.isEmpty) {
return const SizedBox.shrink(); return const SizedBox.shrink();
@ -2302,7 +2317,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
if (response.length == 1) { if (response.length == 1) {
return Container( return Container(
margin: const EdgeInsets.all(10), margin: const EdgeInsets.all(10),
width: isLastSingleCard width: card_full_length
? double.infinity ? double.infinity
: null, : null,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -2359,117 +2374,144 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}, },
), ),
const SizedBox(height: 1), const SizedBox(height: 1),
Flexible( MouseRegion(
fit: FlexFit.loose, onEnter: (event) {
// child: FittedBox( // Show tooltip on hover
final overlay = Overlay
.of(context)
.context
.findRenderObject()
as RenderBox;
final entry =
OverlayEntry(
builder: (context) =>
Positioned(
left: overlay
.localToGlobal(
Offset.zero)
.dx,
top: overlay
.localToGlobal(
Offset.zero)
.dy,
child: Material(
color: Colors
.transparent,
child: Container(
padding:
EdgeInsets
.all(8),
decoration:
BoxDecoration(
color: Colors
.black87,
borderRadius:
BorderRadius
.circular(
4),
),
child: Text(
chart_heading ??
'NA',
style: TextStyle(
color: Colors
.white),
),
),
),
),
);
Overlay.of(context)
.insert(entry);
Future.delayed(
Duration(seconds: 2),
() => entry.remove());
},
child: Text( child: Text(
'${chart_heading ?? 'NA'}', chart_heading ?? 'NA',
textAlign: textAlign:
TextAlign.center, TextAlign.center,
maxLines: 2, maxLines: 2,
// Limit to 2 lines overflow: TextOverflow
softWrap: true, .ellipsis, // Truncate text with '...'
// Enable soft wrapping
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
style: TextStyle( style: TextStyle(
fontSize: 9, fontSize: 11,
fontWeight: fontWeight:
FontWeight.w400, FontWeight.w400,
color: Colors.black87, color: Colors.black87,
), ),
), ),
// ),
), ),
const SizedBox(height: 5), const SizedBox(height: 5),
Flexible( Text(
fit: FlexFit.loose, RegExp(r'\d').hasMatch(
child: SizedBox( response[0][
height: 20.0, 'display_value'] ??
child: FittedBox( '')
child: Text( ? '(${response[0]['display_value'] ?? 'NA'})'
// '(${response[0]['display_value'] ?? 'NA'})', : '${response[0]['display_value'] ?? 'NA'}',
RegExp(r'\d').hasMatch( style: const TextStyle(
response[0][ fontSize: 11,
'display_value'] ?? color: Colors.grey,
'') overflow: TextOverflow
? '(${response[0]['display_value'] ?? 'NA'})' .ellipsis, // Truncate if text overflows
: '${response[0]['display_value'] ?? 'NA'}',
style:
const TextStyle(
fontSize: 10,
color: Colors.grey,
overflow:
TextOverflow
.ellipsis,
),
),
),
), ),
maxLines:
1, // Limit to one line to prevent overflow
textAlign: TextAlign
.center, // Ensure proper alignment
), ),
const SizedBox(height: 1), const SizedBox(height: 1),
Flexible( Row(
fit: FlexFit.loose, mainAxisAlignment:
child: SizedBox( MainAxisAlignment
height: 50.0, .center, // Center-aligns the row contents
child: FittedBox( children: [
fit: BoxFit.contain, Text(
child: Row( response[0]['value'] ??
children: [ 'NA',
Text( textAlign: TextAlign
response[0][ .center, // Ensures text is centered
'value'] ?? style: TextStyle(
'NA', fontSize: 23,
// '${data['roundedAverage'] ?? fontWeight:
// 'NA'}', FontWeight.w800,
style: TextStyle( color: (response[0][
fontSize: 18, 'font_color'] ??
fontWeight: '')
FontWeight .isEmpty
.w800, ? bodyColor
color: response[0] : _getColorFromHex(
[ response[0][
'calculation'] == 'font_color']),
'different'
? _getColorFromHex(
response[0]
[
'font_color'])
: bodyColor,
// color: Color(
// 0xFF90B0D5),
),
),
const SizedBox(
width:
1), // Space between text and icon
if (response[0][
'calculation'] ==
'different') ...[
if (response[0][
'font_color'] ==
'#D83731')
const Icon(
Icons
.arrow_downward,
color: Colors
.red,
size: 20)
else if (response[
0][
'font_color'] ==
'#11AF22')
const Icon(
Icons
.arrow_upward,
color: Colors
.green,
size: 20),
],
],
), ),
), ),
), const SizedBox(
), width:
4), // Space between text and icon
if (response[0]
['calculation'] ==
'different') ...[
if (response[0][
'font_color'] ==
'#D83731')
const Icon(
Icons
.arrow_downward,
color: Colors.red,
size: 20)
else if (response[0][
'font_color'] ==
'#11AF22')
const Icon(
Icons
.arrow_upward,
color:
Colors.green,
size: 20),
],
],
)
], ],
), ),
), ),
@ -2477,7 +2519,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
} else { } else {
return Container( return Container(
margin: const EdgeInsets.all(10), margin: const EdgeInsets.all(10),
width: isLastSingleCard width: card_full_length
? double.infinity ? double.infinity
: null, : null,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -2532,28 +2574,65 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}, },
), ),
const SizedBox(height: 3), const SizedBox(height: 3),
Flexible( MouseRegion(
fit: FlexFit.loose, onEnter: (event) {
child: FittedBox( final overlay =
child: SizedBox( Overlay.of(context);
// height: 70.0, final entry = OverlayEntry(
child: Text( builder: (context) =>
'${chart_heading ?? 'NA'}', Positioned(
// "TOTAL", left: event.position.dx,
textAlign: top: event.position.dy +
TextAlign.center, 10, // Adjust tooltip position
maxLines: child: Material(
2, // Limit to 2 lines color: Colors
softWrap: .transparent,
true, // Enable soft wrapping child: Container(
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully padding:
style: TextStyle( EdgeInsets.all(
fontSize: 8, 8),
fontWeight: decoration:
FontWeight.w400, BoxDecoration(
color: Colors.black87, color: Colors
.black87,
borderRadius:
BorderRadius
.circular(
4),
),
child: Text(
chart_heading ??
'NA',
style: TextStyle(
color: Colors
.white,
fontSize: 10),
),
),
), ),
), ),
);
overlay.insert(entry);
Future.delayed(
Duration(seconds: 2),
() => entry.remove());
},
child: SizedBox(
width: double
.infinity, // Ensures it uses available space
child: Text(
chart_heading ?? 'NA',
textAlign:
TextAlign.center,
maxLines: 2,
overflow: TextOverflow
.ellipsis, // Truncate with '...'
style: TextStyle(
fontSize: 11,
fontWeight:
FontWeight.w400,
color: Colors.black87,
),
), ),
), ),
), ),
@ -2569,38 +2648,30 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
: '${response[0]['display_value'] ?? 'NA'}', : '${response[0]['display_value'] ?? 'NA'}',
style: const TextStyle( style: const TextStyle(
fontSize: 10, fontSize: 11,
color: Colors.grey, color: Colors.grey,
overflow: overflow:
TextOverflow.ellipsis, TextOverflow.ellipsis,
), ),
), ),
const SizedBox(height: 1), const SizedBox(height: 1),
Flexible( Text(
fit: FlexFit.loose, response[0]['value'] ?? 'NA',
child: FittedBox( overflow: TextOverflow
fit: BoxFit.contain, .ellipsis, // Truncate text if it overflows
child: Text( maxLines:
response[0]['value'] ?? 1, // Ensures text stays in a single line
'NA', style: TextStyle(
fontSize: 23,
// apiService.formatAmount( fontWeight: FontWeight.w900,
// data['lastYearValue']), color: (response[0][
// apiService.formatAmount( 'font_color'] ??
// data['lastYearValue']), '')
style: TextStyle( .isEmpty
fontSize: 18, ? bodyColor
fontWeight: : _getColorFromHex(
FontWeight.w900, response[0]
color: response[0][ ['font_color']),
'calculation'] ==
'different'
? _getColorFromHex(
response[0][
'font_color'])
: bodyColor,
),
),
), ),
), ),
SizedBox( SizedBox(
@ -2612,30 +2683,25 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
1, // Divider line thickness 1, // Divider line thickness
), ),
), ),
Flexible( Text(
fit: FlexFit.loose, response[1]['value'] ?? 'NA',
child: FittedBox( style: TextStyle(
fit: BoxFit.contain, fontSize: 16,
child: Text( fontWeight: FontWeight.w600,
response[1]['value'] ?? color: (response[1][
'NA', 'font_color'] ??
// apiService.formatAmount( '')
// data['secondLastYearValue']), .isEmpty
style: TextStyle( ? const Color(
fontSize: 14, 0xFFD83731)
fontWeight: : _getColorFromHex(
FontWeight.w600, response[1]
color: response[1][ ['font_color']),
'calculation'] ==
'different'
? _getColorFromHex(
response[0][
'font_color'])
: const Color(
0xFFD83731),
),
),
), ),
textAlign: TextAlign
.center, // Ensure proper alignment
overflow: TextOverflow
.ellipsis, // Truncate if text overflows
), ),
Text( Text(
// '(${response[1]['display_value'] ?? 'NA'})', // '(${response[1]['display_value'] ?? 'NA'})',
@ -2646,7 +2712,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
? '(${response[1]['display_value'] ?? 'NA'})' ? '(${response[1]['display_value'] ?? 'NA'})'
: '${response[1]['display_value'] ?? 'NA'}', : '${response[1]['display_value'] ?? 'NA'}',
style: const TextStyle( style: const TextStyle(
fontSize: 9, fontSize: 8,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey, color: Colors.grey,
overflow: overflow:
@ -2783,6 +2849,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
); );
} }
} }
Future<void> shareCurrentPage(BuildContext context) async { Future<void> shareCurrentPage(BuildContext context) async {
try { try {
// Get current route from go_router // Get current route from go_router
@ -2798,7 +2865,8 @@ Future<void> shareCurrentPage(BuildContext context) async {
width: 200, width: 200,
height: 200, height: 200,
); );
final Uint8List? capturedImage = await screenshotController.captureFromWidget( final Uint8List? capturedImage =
await screenshotController.captureFromWidget(
Material(child: svgWidget), Material(child: svgWidget),
); );
@ -2824,6 +2892,7 @@ Future<void> shareCurrentPage(BuildContext context) async {
); );
} }
} }
// Function to convert hex color string to Color // Function to convert hex color string to Color
Color _getColorFromHex(String hexColor) { Color _getColorFromHex(String hexColor) {
hexColor = hexColor.replaceFirst('#', ''); hexColor = hexColor.replaceFirst('#', '');

View File

@ -195,45 +195,124 @@ class _MyHomePageState extends ConsumerState<MyHomePage> {
} }
void _showExitConfirmation(BuildContext context) { void _showExitConfirmation(BuildContext context) {
double myheight = MediaQuery.of(context).size.height;
showDialog( showDialog(
context: context, context: context,
builder: (context) => AlertDialog( barrierDismissible: false, // User must tap a button to dismiss dialog
title: Text( builder: (dialogContext) => AlertDialog(
context.translate( shape: RoundedRectangleBorder(
'Logout', borderRadius: BorderRadius.circular(5.0), // Rounded corners
'تسجيل الخروج',
),
), ),
content: Text( contentPadding: EdgeInsets.zero,
context.translate( title: Text(
'Are you sure you want to logout?', context.translate('Log Out Confirmation', 'تأكيد تسجيل الخروج'),
'هل أنت متأكد أنك تريد تسجيل الخروج؟', textAlign: TextAlign.center,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
content: Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
context.translate('Are you sure you want to log out?',
'هل أنت متأكد أنك تريد تسجيل الخروج؟'),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
color: Color(0xFF898C81),
),
), ),
), ),
actions: [ actions: [
TextButton( Row(
onPressed: () => Navigator.of(context).pop(), // Close dialog mainAxisAlignment:
child: Text( MainAxisAlignment.spaceEvenly, // Space buttons evenly
context.translate( children: [
'Cancel', SizedBox(
'إلغاء', width: 120, // Set button width
child: TextButton(
onPressed: () => Navigator.pop(dialogContext),
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
side: BorderSide(
color: Color(0xFFAA8E83), // Border color
width: 1,
),
),
child: Text(
context.translate('Cancel', 'إلغاء'),
style: TextStyle(
color: Color(0xFFAA8E83),
fontSize: 16,
),
),
),
), ),
), SizedBox(
), width: 120, // Set button width
TextButton( child: TextButton(
onPressed: () => logout(context), // Exit the app onPressed: () => logout(context),
child: Text( style: TextButton.styleFrom(
context.translate( backgroundColor: Color(0xFFAA8E83), // Background color
'Logout', foregroundColor: Colors.white,
'تسجيل الخروج', shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: Text(
context.translate('Log Out', 'تسجيل الخروج'),
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
), ),
), ],
), ),
SizedBox(height: 10), // Add spacing below buttons
], ],
), ),
); );
} }
// void _showExitConfirmation(BuildContext context) {
// showDialog(
// context: context,
// builder: (context) => AlertDialog(
// title: Text(
// context.translate(
// 'Logout',
// 'تسجيل الخروج',
// ),
// ),
// content: Text(
// context.translate(
// 'Are you sure you want to logout?',
// 'هل أنت متأكد أنك تريد تسجيل الخروج؟',
// ),
// ),
// actions: [
// TextButton(
// onPressed: () => Navigator.of(context).pop(), // Close dialog
// child: Text(
// context.translate(
// 'Cancel',
// 'إلغاء',
// ),
// ),
// ),
// TextButton(
// onPressed: () => logout(context), // Exit the app
// child: Text(
// context.translate(
// 'Logout',
// 'تسجيل الخروج',
// ),
// ),
// ),
// ],
// ),
// );
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
@ -421,8 +500,10 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
child: IconButton( child: IconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
iconSize: 20, iconSize: 20,
icon:Icon( icon: Icon(
locale.languageCode == 'ar' ?Icons.arrow_back : Icons.arrow_forward, locale.languageCode == 'ar'
? Icons.arrow_back
: Icons.arrow_forward,
color: Colors.white), color: Colors.white),
onPressed: () { onPressed: () {
tutorialCoachMark.next(); tutorialCoachMark.next();
@ -440,11 +521,11 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
), ),
), ),
TargetContent( TargetContent(
padding: EdgeInsets.only(left:locale.languageCode == 'ar' padding: EdgeInsets.only(
? 0 left: locale.languageCode == 'ar' ? 0 : screenWidth * 0.4,
: screenWidth * 0.4, bottom: 0,right:locale.languageCode == 'ar' bottom: 0,
? screenWidth * 0.4 right: locale.languageCode == 'ar' ? screenWidth * 0.4 : 0,
: 0 ,), ),
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: SizedBox( child: SizedBox(
width: 200, width: 200,
@ -528,16 +609,25 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: Icon(Icons.arrow_back, icon: Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
locale.languageCode=='ar' ?tutorialCoachMark.next() : tutorialCoachMark.previous(); locale.languageCode == 'ar'
? tutorialCoachMark.next()
: tutorialCoachMark.previous();
}, },
), ),
), ),
@ -545,16 +635,23 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon:Icon(Icons.arrow_forward, icon: Icon(Icons.arrow_forward,
color: Colors.white), color: Colors.white),
onPressed: () { onPressed: () {
locale.languageCode=='ar' ?tutorialCoachMark.previous() : tutorialCoachMark.next(); locale.languageCode == 'ar'
? tutorialCoachMark.previous()
: tutorialCoachMark.next();
}, },
), ),
), ),
@ -570,9 +667,11 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
), ),
), ),
TargetContent( TargetContent(
padding: EdgeInsets.only(left:locale.languageCode == 'ar' padding: EdgeInsets.only(
? 0: screenWidth * 0.4, bottom: 0, right: locale.languageCode == 'en' left: locale.languageCode == 'ar' ? 0 : screenWidth * 0.4,
? 0: screenWidth * 0.4, ), bottom: 0,
right: locale.languageCode == 'en' ? 0 : screenWidth * 0.4,
),
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: Container( child: Container(
width: 200, width: 200,
@ -685,21 +784,36 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0,), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0,
),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: Icon(Icons.arrow_back, icon: Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.finish(); tutorialCoachMark.finish();
ref.read(previousHomeTourProvider.notifier).state = true; ref
ref.read(chartsTourProvider.notifier).state = false; .read(previousHomeTourProvider
.notifier)
.state = true;
ref
.read(
chartsTourProvider.notifier)
.state = false;
context.go( context.go(
'/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',); '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',
);
} else { } else {
tutorialCoachMark.next(); tutorialCoachMark.next();
} }
@ -710,9 +824,15 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1,), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1,
),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
@ -723,8 +843,14 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
tutorialCoachMark.next(); tutorialCoachMark.next();
} else { } else {
tutorialCoachMark.finish(); tutorialCoachMark.finish();
ref.read(previousHomeTourProvider.notifier).state = true; ref
ref.read(chartsTourProvider.notifier).state = false; .read(previousHomeTourProvider
.notifier)
.state = true;
ref
.read(
chartsTourProvider.notifier)
.state = false;
context.go( context.go(
'/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments');
} }
@ -745,9 +871,11 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
), ),
), ),
TargetContent( TargetContent(
padding: EdgeInsets.only(left:locale.languageCode == 'ar' padding: EdgeInsets.only(
? 0: screenWidth * 0.4, bottom: 0, right: locale.languageCode == 'en' left: locale.languageCode == 'ar' ? 0 : screenWidth * 0.4,
? 0: screenWidth * 0.4, ), bottom: 0,
right: locale.languageCode == 'en' ? 0 : screenWidth * 0.4,
),
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: Container( child: Container(
width: 200, width: 200,
@ -838,8 +966,12 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: Icon(locale.languageCode == 'ar' ?Icons.arrow_back : Icons.arrow_forward , icon: Icon(
color: Colors.white,), locale.languageCode == 'ar'
? Icons.arrow_back
: Icons.arrow_forward,
color: Colors.white,
),
onPressed: () { onPressed: () {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
}, },
@ -857,8 +989,11 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
), ),
), ),
TargetContent( TargetContent(
padding: EdgeInsets.only(left:locale.languageCode == 'ar' ? 0 : screenWidth * 0.4, bottom: 0, padding: EdgeInsets.only(
right:locale.languageCode == 'ar' ? screenWidth * 0.4 : 0 ,), left: locale.languageCode == 'ar' ? 0 : screenWidth * 0.4,
bottom: 0,
right: locale.languageCode == 'ar' ? screenWidth * 0.4 : 0,
),
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: Container( child: Container(
width: 200, width: 200,
@ -1048,7 +1183,8 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
RoundedCornerContainer( RoundedCornerContainer(
key: mainTopic['main_topic'] == 'ECONOMY' || mainTopic['main_topic'] == 'اقتصاد' key: mainTopic['main_topic'] == 'ECONOMY' ||
mainTopic['main_topic'] == 'اقتصاد'
? cardTopicKey ? cardTopicKey
: null, : null,
text: mainTopic['main_topic'], text: mainTopic['main_topic'],
@ -1062,7 +1198,8 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
SizedBox( SizedBox(
height: myheight / 4.8, // Set dynamic height height: myheight / 4.8, // Set dynamic height
child: Container( child: Container(
key: mainTopic['main_topic'] == 'ECONOMY' || mainTopic['main_topic'] == 'اقتصاد' key: mainTopic['main_topic'] == 'ECONOMY' ||
mainTopic['main_topic'] == 'اقتصاد'
? cardsKey ? cardsKey
: null, : null,
// color: Colors.grey[200], // Set a background color for the scrollable container // color: Colors.grey[200], // Set a background color for the scrollable container

View File

@ -21,7 +21,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
int _sortColumnIndex = 0; int _sortColumnIndex = 0;
bool _isAscending = true; bool _isAscending = true;
List<User> filteredUserData = []; List<User> filteredUserData = [];
bool isLoading = true; bool isLoading = true;
// final List<String> statusOptions = ['Approved', 'Denied', 'Pending']; // final List<String> statusOptions = ['Approved', 'Denied', 'Pending'];
@ -53,9 +53,10 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
); );
setState(() { setState(() {
isLoading = true; isLoading = true;
userData = result.map((record) { userData = result.map((record) {
final createdDate = DateTime.parse(record.created).add(Duration(hours: 4));// Parse the created date final createdDate = DateTime.parse(record.created)
.add(Duration(hours: 4)); // Parse the created date
final formattedDate = DateFormat('dd/MM/yyyy').format(createdDate); final formattedDate = DateFormat('dd/MM/yyyy').format(createdDate);
return User( return User(
id: record.id, // Correctly passing the ID id: record.id, // Correctly passing the ID
@ -66,13 +67,12 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
); );
}).toList(); }).toList();
userData.sort((a,b){ userData.sort((a, b) {
DateTime dateA= DateFormat('dd/MM/yyyy').parse(a.registrationDate); DateTime dateA = DateFormat('dd/MM/yyyy').parse(a.registrationDate);
DateTime dateB = DateFormat('dd/MM/yyyy').parse(b.registrationDate); DateTime dateB = DateFormat('dd/MM/yyyy').parse(b.registrationDate);
return dateB.compareTo(dateA); return dateB.compareTo(dateA);
}); });
filteredUserData = List.from(userData); filteredUserData = List.from(userData);
isLoading = false; isLoading = false;
@ -341,181 +341,184 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
child: TextField( child: TextField(
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search", hintText: "Search",
hintStyle: const TextStyle( hintStyle: TextStyle(color: Color(0xFF898C81)),
color: Color(0xFFC3C6CB),
fontSize: 14,
),
prefixIcon: Image( prefixIcon: Image(
image: ExactAssetImage(MiscIconAssetPath.search), image: ExactAssetImage(MiscIconAssetPath.search),
width: 24, width: 24,
height: 24, height: 24,
color: Color(0xFFAA8E83) color: Color(0xFFAA8E83)),
),
// prefixIcon: Image.asset( // prefixIcon: Image.asset(
// MiscIconAssetPath.search, // MiscIconAssetPath.search,
// // fit: BoxFit.contain, // // fit: BoxFit.contain,
// ), // ),
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding: EdgeInsets.symmetric(
EdgeInsets.symmetric(vertical: 8.0, horizontal: 18.0), vertical: 8.0, horizontal: 18.0),
), ),
onChanged: filterUsers, onChanged: filterUsers,
),), ),
),
), ),
SizedBox(height: myheight / 40), SizedBox(height: myheight / 40),
isLoading isLoading
? Center(child: CircularProgressIndicator()) ? Center(child: CircularProgressIndicator())
:filteredUserData.isEmpty : filteredUserData.isEmpty
? Center( ? Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox(height: myheight / 5), SizedBox(height: myheight / 5),
// Icon(Icons.search, // Icon(Icons.search,
// size: 60, color: Colors.grey), // size: 60, color: Colors.grey),
Image.asset( Image.asset(
MiscIconAssetPath.group, MiscIconAssetPath.group,
width: 60, width: 60,
height: 60, height: 60,
), ),
SizedBox(height: 15), SizedBox(height: 15),
// Space between icon and text // Space between icon and text
Text( Text(
"No results found", "No results found",
style: TextStyle( style: TextStyle(
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.grey[700], color: Colors.grey[700],
),
),
SizedBox(height: 12), // Space between texts
FittedBox(
child: Text(
"We couldn't find anything matching your search.",
style: TextStyle(
fontSize: 18, color: Color(0xFF898C81)),
textAlign: TextAlign.center,
),
),
],
),
),
)
: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width,
),
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: _isAscending,
columns: [
DataColumn(
label: Text(
AppLocalizations.of(context)!.user_name,
),
onSort: (columnIndex, ascending) {
_sort((user) => user.userName.toLowerCase(),
columnIndex, ascending);
},
),
DataColumn(
label: Text(
AppLocalizations.of(context)!.email_id,
),
onSort: (columnIndex, ascending) {
_sort((user) => user.emailId.toLowerCase(),
columnIndex, ascending);
},
),
DataColumn(
label: Text(
AppLocalizations.of(context)!.reg_date,
),
onSort: (columnIndex, ascending) {
_sort(
(user) => DateFormat('dd/MM/yyyy')
.parse(user.registrationDate),
columnIndex,
ascending,
);
},
),
DataColumn(
label: Text(
AppLocalizations.of(context)!.status,
),
onSort: (columnIndex, ascending) {
_sort((user) => user.status.toLowerCase(),
columnIndex, ascending);
},
),
],
rows: filteredUserData.isEmpty
? [
DataRow(
cells: List<DataCell>.generate(
4, // Ensure it matches the number of DataColumns
(index) => DataCell(
index == 0
? Text(
'No results found',
style: TextStyle(
fontStyle:
FontStyle.italic),
)
: const Text(
''), // Empty cells for other columns
placeholder: true,
),
),
), ),
] ),
: filteredUserData.map((user) {
return DataRow( SizedBox(height: 12), // Space between texts
cells: [ FittedBox(
DataCell(Text(user.userName)), child: Text(
DataCell(Text(user.emailId)), "We couldn't find anything matching your search.",
DataCell(Text(user.registrationDate)), style: TextStyle(
DataCell( fontSize: 18,
DropdownButton<String>( color: Color(0xFF898C81)),
value: user.status, textAlign: TextAlign.center,
items: statusOptions.entries ),
.map((status) { ),
return DropdownMenuItem<String>( ],
value: status.key, ),
child: Text( ),
status.value, )
style: TextStyle( : SingleChildScrollView(
color: getStatusColor( scrollDirection: Axis.horizontal,
status.key), child: ConstrainedBox(
), constraints: BoxConstraints(
), minWidth: MediaQuery.of(context).size.width,
); ),
}).toList(), child: DataTable(
onChanged: (newStatus) { sortColumnIndex: _sortColumnIndex,
print(user); sortAscending: _isAscending,
if (newStatus != null) { columns: [
_showConfirmationDialog( DataColumn(
user, newStatus); label: Text(
} AppLocalizations.of(context)!.user_name,
}, ),
onSort: (columnIndex, ascending) {
_sort(
(user) => user.userName.toLowerCase(),
columnIndex,
ascending);
},
),
DataColumn(
label: Text(
AppLocalizations.of(context)!.email_id,
),
onSort: (columnIndex, ascending) {
_sort(
(user) => user.emailId.toLowerCase(),
columnIndex,
ascending);
},
),
DataColumn(
label: Text(
AppLocalizations.of(context)!.reg_date,
),
onSort: (columnIndex, ascending) {
_sort(
(user) => DateFormat('dd/MM/yyyy')
.parse(user.registrationDate),
columnIndex,
ascending,
);
},
),
DataColumn(
label: Text(
AppLocalizations.of(context)!.status,
),
onSort: (columnIndex, ascending) {
_sort((user) => user.status.toLowerCase(),
columnIndex, ascending);
},
),
],
rows: filteredUserData.isEmpty
? [
DataRow(
cells: List<DataCell>.generate(
4, // Ensure it matches the number of DataColumns
(index) => DataCell(
index == 0
? Text(
'No results found',
style: TextStyle(
fontStyle:
FontStyle.italic),
)
: const Text(
''), // Empty cells for other columns
placeholder: true,
),
), ),
), ),
], ]
); : filteredUserData.map((user) {
}).toList(), return DataRow(
cells: [
DataCell(Text(user.userName)),
DataCell(Text(user.emailId)),
DataCell(
Text(user.registrationDate)),
DataCell(
DropdownButton<String>(
value: user.status,
items: statusOptions.entries
.map((status) {
return DropdownMenuItem<
String>(
value: status.key,
child: Text(
status.value,
style: TextStyle(
color: getStatusColor(
status.key),
),
),
);
}).toList(),
onChanged: (newStatus) {
print(user);
if (newStatus != null) {
_showConfirmationDialog(
user, newStatus);
}
},
),
),
],
);
}).toList(),
),
),
), ),
),
),
], ],
), ),
), ),

View File

@ -87,7 +87,7 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
void initState() { void initState() {
super.initState(); super.initState();
_checkUserId(); _checkUserId();
locale = ref.read(localeProvider)?? const Locale('en'); locale = ref.read(localeProvider) ?? const Locale('en');
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_startAppbarTour(); _startAppbarTour();
}); });
@ -202,24 +202,36 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0),
), ),
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_back, icon: const Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.next(); tutorialCoachMark.next();
} else { } else {
tutorialCoachMark.finish(); tutorialCoachMark.finish();
ref.read(scaffoldTourProvider.notifier).state = true; ref
ref.read(previousChartsTourProvider.notifier).state = false; .read(scaffoldTourProvider.notifier)
.state = true;
ref
.read(previousChartsTourProvider
.notifier)
.state = false;
context.go( context.go(
'/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',); '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',
);
} }
}, },
), ),
), ),
@ -227,9 +239,14 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1),
), ),
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_forward, icon: const Icon(Icons.arrow_forward,
@ -237,10 +254,16 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
onPressed: () { onPressed: () {
if (locale.languageCode == 'ar') { if (locale.languageCode == 'ar') {
tutorialCoachMark.finish(); tutorialCoachMark.finish();
ref.read(scaffoldTourProvider.notifier).state = true; ref
ref.read(previousChartsTourProvider.notifier).state = false; .read(scaffoldTourProvider.notifier)
.state = true;
ref
.read(previousChartsTourProvider
.notifier)
.state = false;
context.go( context.go(
'/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',); '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments',
);
} else { } else {
tutorialCoachMark.next(); tutorialCoachMark.next();
} }
@ -271,7 +294,7 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
text: AppLocalizations.of(context)!.mainMenu, text: AppLocalizations.of(context)!.mainMenu,
alignment: ContentAlign.bottom, alignment: ContentAlign.bottom,
gap: 55, gap: 55,
space:locale.languageCode=='ar' ? 20: 20, space: locale.languageCode == 'ar' ? 20 : 20,
), ),
TargetContent( TargetContent(
align: ContentAlign.bottom, align: ContentAlign.bottom,
@ -327,15 +350,25 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? Color(0xFF7DAFBC):null, color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: null,
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Color(0xFF7DAFBC): Colors.white, width: 2.0,), color: locale.languageCode == 'ar'
? Color(0xFF7DAFBC)
: Colors.white,
width: 2.0,
),
), ),
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_back, icon: const Icon(
color: Colors.white,), Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
locale.languageCode=='ar' ?tutorialCoachMark.next() : tutorialCoachMark.previous(); locale.languageCode == 'ar'
? tutorialCoachMark.next()
: tutorialCoachMark.previous();
}, },
), ),
), ),
@ -343,15 +376,24 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: locale.languageCode=='ar' ? null:Color(0xFF7DAFBC), color: locale.languageCode == 'ar'
? null
: Color(0xFF7DAFBC),
border: Border.all( border: Border.all(
color:locale.languageCode=='ar' ? Colors.white: Color(0xFF7DAFBC), width: 1), color: locale.languageCode == 'ar'
? Colors.white
: Color(0xFF7DAFBC),
width: 1),
), ),
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_forward, icon: const Icon(
color: Colors.white,), Icons.arrow_forward,
color: Colors.white,
),
onPressed: () { onPressed: () {
locale.languageCode=='ar' ?tutorialCoachMark.previous() : tutorialCoachMark.next(); locale.languageCode == 'ar'
? tutorialCoachMark.previous()
: tutorialCoachMark.next();
}, },
), ),
), ),
@ -367,8 +409,14 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
), ),
), ),
TargetContent( TargetContent(
padding: EdgeInsets.only(right:locale.languageCode=='ar' ? 0: screenWidth * 0.7, top: locale.languageCode=='ar' ?20 : 20, left: locale.languageCode=='ar' ? screenWidth * 0.7:0,), padding: EdgeInsets.only(
align: locale.languageCode=='ar' ? ContentAlign.left : ContentAlign.right, right: locale.languageCode == 'ar' ? 0 : screenWidth * 0.7,
top: locale.languageCode == 'ar' ? 20 : 20,
left: locale.languageCode == 'ar' ? screenWidth * 0.7 : 0,
),
align: locale.languageCode == 'ar'
? ContentAlign.left
: ContentAlign.right,
child: Container( child: Container(
width: 200, width: 200,
height: screenHeight / 4, height: screenHeight / 4,
@ -376,8 +424,8 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
children: [ children: [
Image.asset( Image.asset(
locale.languageCode == 'ar' locale.languageCode == 'ar'
? 'assets/app_tour/down_right.png' // Arabic locale image ? 'assets/app_tour/down_right.png' // Arabic locale image
: 'assets/app_tour/leftDown.png', // Default image : 'assets/app_tour/leftDown.png', // Default image
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
// Positioned( // Positioned(
@ -452,7 +500,6 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
elevation: 0, elevation: 0,
), ),
child: Text( child: Text(
AppLocalizations.of(context)!.skip, AppLocalizations.of(context)!.skip,
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
@ -469,8 +516,12 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
color: Colors.white, width: 2.0), color: Colors.white, width: 2.0),
), ),
child: IconButton( child: IconButton(
icon: Icon(locale.languageCode=='ar' ? Icons.arrow_forward: Icons.arrow_back, icon: Icon(
color: Colors.white,), locale.languageCode == 'ar'
? Icons.arrow_forward
: Icons.arrow_back,
color: Colors.white,
),
onPressed: () { onPressed: () {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
}, },
@ -480,12 +531,25 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
debugPrint('Got it clicked'); debugPrint('Got it clicked');
ref.read(chartsTourProvider.notifier).state = true; ref
ref.read(previousChartsTourProvider.notifier).state = true; .read(chartsTourProvider.notifier)
ref.read(homeTourProvider.notifier).state = true; .state = true;
ref.read(previousHomeTourProvider.notifier).state = true; ref
ref.read(scaffoldTourProvider.notifier).state = true; .read(
ref.read(previousScaffoldTourProvider.notifier).state = true; previousChartsTourProvider.notifier)
.state = true;
ref.read(homeTourProvider.notifier).state =
true;
ref
.read(previousHomeTourProvider.notifier)
.state = true;
ref
.read(scaffoldTourProvider.notifier)
.state = true;
ref
.read(previousScaffoldTourProvider
.notifier)
.state = true;
tutorialCoachMark.finish(); tutorialCoachMark.finish();
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@ -516,11 +580,14 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
), ),
), ),
TargetContent( TargetContent(
padding: EdgeInsets.only(left: locale.languageCode=='ar' ? 0: screenWidth * 0.7, padding: EdgeInsets.only(
left: locale.languageCode == 'ar' ? 0 : screenWidth * 0.7,
top: toggleHeight, top: toggleHeight,
right: locale.languageCode=='ar' ? screenWidth * 0.7 : 0, right: locale.languageCode == 'ar' ? screenWidth * 0.7 : 0,
), ),
align : locale.languageCode=='ar' ? ContentAlign.right :ContentAlign.left, align: locale.languageCode == 'ar'
? ContentAlign.right
: ContentAlign.left,
child: Container( child: Container(
width: 200, width: 200,
height: screenHeight / 4, height: screenHeight / 4,
@ -528,8 +595,8 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
children: [ children: [
Image.asset( Image.asset(
locale.languageCode == 'ar' locale.languageCode == 'ar'
? 'assets/app_tour/leftDown.png' // Arabic locale image ? 'assets/app_tour/leftDown.png' // Arabic locale image
: 'assets/app_tour/down_right.png', // Default image : 'assets/app_tour/down_right.png', // Default image
fit: BoxFit.contain, fit: BoxFit.contain,
) )
], ],
@ -825,9 +892,13 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
] else ...[ ] else ...[
Text(userName ?? 'Loading...'), Text(userName ?? 'Loading...'),
Tooltip( Tooltip(
message: userEmail ?? 'Loading...', // Shows full email on hover message: userEmail ??
'Loading...', // Shows full email on hover
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width * 0.6, // Adjust width as needed width: MediaQuery.of(context)
.size
.width *
0.6, // Adjust width as needed
child: Text( child: Text(
userEmail ?? 'Loading...', userEmail ?? 'Loading...',
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
@ -1078,6 +1149,16 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
} }
} }
} }
final PAuthRepo _authRepo = PAuthRepo();
Future<void> logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
await _authRepo.logout();
prefs.clear();
context.go('/login'); // Redirect to login after logout
}
void _showLogoutConfirmationDialog(BuildContext context) { void _showLogoutConfirmationDialog(BuildContext context) {
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
showDialog( showDialog(
@ -1096,8 +1177,7 @@ void _showLogoutConfirmationDialog(BuildContext context) {
content: Padding( content: Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: Text( child: Text(
context.translate( context.translate('Are you sure you want to log out?',
'Are you sure you want to log out?',
'هل أنت متأكد أنك تريد تسجيل الخروج؟'), 'هل أنت متأكد أنك تريد تسجيل الخروج؟'),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
@ -1108,7 +1188,8 @@ void _showLogoutConfirmationDialog(BuildContext context) {
), ),
actions: [ actions: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Space buttons evenly mainAxisAlignment:
MainAxisAlignment.spaceEvenly, // Space buttons evenly
children: [ children: [
SizedBox( SizedBox(
width: 120, // Set button width width: 120, // Set button width
@ -1135,10 +1216,7 @@ void _showLogoutConfirmationDialog(BuildContext context) {
SizedBox( SizedBox(
width: 120, // Set button width width: 120, // Set button width
child: TextButton( child: TextButton(
onPressed: () async { onPressed: () => logout(context),
await logout(dialogContext); // Pass dialogContext to logout
Navigator.pop(dialogContext); // Close the dialog
},
style: TextButton.styleFrom( style: TextButton.styleFrom(
backgroundColor: Color(0xFFAA8E83), // Background color backgroundColor: Color(0xFFAA8E83), // Background color
foregroundColor: Colors.white, foregroundColor: Colors.white,
@ -1159,11 +1237,3 @@ void _showLogoutConfirmationDialog(BuildContext context) {
), ),
); );
} }
Future<void> logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear(); // Clear shared preferences
context.go('/login'); // Navigate to the root route (e.g., login screen)
}