bug fix and forgot password

This commit is contained in:
venbaittech 2025-03-27 18:43:32 +05:30
parent a0d7a733a4
commit efb0d38664
11 changed files with 636 additions and 502 deletions

View File

@ -20,12 +20,12 @@ if (project.hasProperty('google-services.json')) {
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "43"
flutterVersionCode = "44"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0.42"
flutterVersionName = "1.0.43"
}
def keystorePropertiesFile = rootProject.file("key.properties")

View File

@ -30,13 +30,27 @@
<meta-data android:name="flutter_deeplinking_enabled"
android:value="true"/>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="www.fcsc.com"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="fcsc-a161c.web.app"
android:scheme="flutterdeeplink"
android:host="fcsc"
android:pathPrefix="/login" />
<data
android:scheme="flutterdeeplink"
android:host="fcsc"
android:pathPrefix="/chartScreen"/>
<data
android:scheme="flutterdeeplink"
android:host="fcsc"
android:pathPrefix="/forgot-password"/>
</intent-filter>
<!-- <intent-filter >-->
<!-- <action android:name="android.intent.action.VIEW" />-->

View File

@ -667,7 +667,8 @@ final GoRouter router = GoRouter(
redirect: (context, state) async {
if (state.uri.path == '/SessionCheckScreen' ||
state.uri.path == '/login' ||
state.uri.path == '/register') {
state.uri.path == '/register' ||
state.uri.path == '/forgot-password/:email') {
return null;
}

View File

@ -240,7 +240,8 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
onChanged: (value) {
filterData(
value); // Call filter function directly on input change
},
}, // Ensures vertical alignment
// Centers text horizontally
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.search,
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
@ -261,8 +262,9 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
// // fit: BoxFit.contain,
// ),
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(vertical: 9, horizontal: 18.0),
// contentPadding:
// EdgeInsets.symmetric(vertical: 9, horizontal: 18.0),
contentPadding: EdgeInsets.zero,
),
),
),

View File

@ -107,6 +107,66 @@ class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
return null;
}
// Future<void> updatePassword(
// String email, String oldPassword, String newPassword) async {
// print(email);
// try {
// setState(() {
// isLoading = true;
// });
// // Authenticate as admin
// final adminAuth = await _pb.admins
// .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
// final token = adminAuth.token;
//
// final headers = {
// 'Authorization': 'Bearer $token',
// };
//
// // Update password
// await _pb.collection('users').update(
// email,
// body: {
// 'password': newPassword,
// 'passwordConfirm': newPassword,
// },
// headers: headers,
// );
//
// setState(() {
// isLoading = false;
// _isPasswordUpdated = true;
// });
//
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content:
// Text(AppLocalizations.of(context)!.password_update_successfully),
// backgroundColor: Colors.green,
// ),
// );
//
// print('_isPasswordUpdated $_isPasswordUpdated');
//
// // Navigator.push(
// // context,
// // MaterialPageRoute(
// // builder: (context) => ProfileScreen(userId: userId)),
// // );
// } catch (e) {
// setState(() {
// isLoading = false;
// });
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(context.translate(
// 'Failed to update password: $e', 'فشل في تحديث كلمة المرور')),
// backgroundColor: Colors.red,
// ),
// );
// }
// }
Future<void> updatePassword(
String email, String oldPassword, String newPassword) async {
try {
@ -122,9 +182,27 @@ class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
'Authorization': 'Bearer $token',
};
// Update password
// Step 1: Find User by Email
final result = await _pb.collection('users').getList(
filter: 'email = "$email"',
headers: headers,
);
if (result.items.isEmpty) {
// throw Exception("User not found");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('User not found'),
backgroundColor: Colors.red,
),
);
}
final userId = result.items.first.id;
// Step 3: Update Password
await _pb.collection('users').update(
email,
userId,
body: {
'password': newPassword,
'passwordConfirm': newPassword,
@ -146,19 +224,14 @@ class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
);
print('_isPasswordUpdated $_isPasswordUpdated');
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => ProfileScreen(userId: userId)),
// );
} catch (e) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.translate('Failed to update password: $e','فشل في تحديث كلمة المرور')),
content: Text('Failed to update password: $e'),
backgroundColor: Colors.red,
),
);

View File

@ -2695,50 +2695,54 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}
}
Future<void> shareCurrentPage(BuildContext context, bool _isSharing) async {
if (_isSharing) return; // Prevent multiple taps
Future<void> shareCurrentPage(BuildContext context, bool isSharing) async {
if (isSharing) return; // Prevent multiple taps
_isSharing = true;
isSharing = true;
try {
final String currentRoute = GoRouterState.of(context).uri.toString();
final String baseAppLink = 'https://fcsc-a161c.web.app';
final String baseAppLink = 'https://www.fcsc.com';
final String shareLink = '$baseAppLink$currentRoute';
final String shareText = 'Check this out!';
final String svgAssetPath = 'assets/backgrounds/share/fcsc.svg';
final String shareText = 'Check this out!\n\n$shareLink';
print('Generated Share Link: $shareLink');
// Optional: Capture SVG to image
final String svgAssetPath = 'assets/backgrounds/share/fcsc.svg';
final screenshotController = ScreenshotController();
final svgWidget = SvgPicture.asset(
svgAssetPath,
width: 200,
height: 200,
);
final Uint8List? capturedImage =
await screenshotController.captureFromWidget(
Material(child: svgWidget),
);
if (capturedImage == null) {
throw Exception('Failed to capture SVG as image');
}
print('SVG capture failed, proceeding without image.');
await Share.share(shareText, subject: 'App Link');
} else {
final directory = await getTemporaryDirectory();
final file = File('${directory.path}/share.svg');
final file = File('${directory.path}/share_image.png');
await file.writeAsBytes(capturedImage);
await Share.shareXFiles(
[XFile(file.path)],
text: '$shareText\n$shareLink',
text: shareText,
subject: 'Shared Content',
);
await file.delete();
}
} catch (e) {
print("Error sharing file: $e");
print("Error sharing content: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error sharing: $e')),
SnackBar(content: Text('Error sharing: ${e.toString()}')),
);
} finally {
_isSharing = false; // Reset flag after sharing completes
isSharing = false; // Reset flag
}
}

View File

@ -4,6 +4,7 @@ import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
// import 'package:syncfusion_flutter_charts/charts.dart';
class ChartWidget extends StatelessWidget {
@ -208,8 +209,7 @@ class ChartWidget extends StatelessWidget {
x: entry['ObsKey']['TIME_PERIOD'],
y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0,
);
})
.toList();
}).toList();
}
List<BarChartGroupData> parseColumnChartData(dynamic chartData) {
@ -380,7 +380,8 @@ class ChartWidget extends StatelessWidget {
// ];
// }
List<Widget> generateIndicators(dynamic chartData, double totalValue) {
List<Widget> generateIndicators(
dynamic chartData, double totalValue, BuildContext context) {
var groupByKeyValue;
if (chartData['chart_type_json']['chart_type'] == 'bar_chart_horizontal' ||
chartData['chart_type_json']['chart_type'] == 'horizontal_rotate') {
@ -412,50 +413,83 @@ class ChartWidget extends StatelessWidget {
}
// double percentage = (value / totalValue) * 100;
String percentage =
(totalValue > 0)
String percentage = (totalValue > 0)
? ((value / totalValue) * 100).toStringAsFixed(1)
: "0.0";
// bool isTouched = index == touchedIndex;
// return Wrap(
// alignment: WrapAlignment.center,
// spacing: 12,
// runSpacing: 8,
// children: [
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Container(
// width: 10,
// height: 10,
// decoration: BoxDecoration(
// color: uniqueColors[index % uniqueColors.length],
// shape: BoxShape.circle,
// ),
// ),
// SizedBox(width: 8),
// Flexible(
// child: Text(
// context.translate(
// '$title -- $percentage%',
// '$title -- %$percentage',
// ),
// textAlign: TextAlign.start,
// style: TextStyle(fontSize: 12),
// softWrap: true,
// maxLines: 2, // Allows wrapping within two lines
// overflow: TextOverflow.ellipsis, // Prevents overflow
// ),
// ),
// ],
// ),
// ],
// );
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start, // Aligns dot to text start
children: [
Container(
width: 10,
height: 10,
margin: EdgeInsets.only(top: 4), // Adjust to align with text
decoration: BoxDecoration(
color: uniqueColors[index % uniqueColors.length],
shape: BoxShape.circle,
),
),
SizedBox(width: 8),
TooltipTheme(
Expanded(
child: TooltipTheme(
data: TooltipThemeData(
decoration: BoxDecoration(
color: Colors.blueGrey[800], // Change background color
borderRadius: BorderRadius.circular(
8,
), // Optional: rounded corners
borderRadius: BorderRadius.circular(8),
),
textStyle: TextStyle(color: Colors.white), // Change text color
textStyle: TextStyle(color: Colors.white),
),
child: Tooltip(
message: title, // Full text on hover
child: ConstrainedBox(
// Constrain width to allow wrapping
constraints: BoxConstraints(maxWidth: 250),
child: Text(
context.translate(
'$title -- $percentage%',
'$title -- %$percentage',
),
style: TextStyle(fontSize: 12),
softWrap: true,
maxLines: 2,
// overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow
),
),
),
),
SizedBox(width: 5),
],
);
}).toList();
@ -618,8 +652,7 @@ class ChartWidget extends StatelessWidget {
),
);
case 'pie_chart':
double totalValue = chartData['response']
.map<double>((entry) {
double totalValue = chartData['response'].map<double>((entry) {
var value = entry['ObsValue']['Value'];
// print('Processing value: $value, type: ${value.runtimeType}');
return (value is num)
@ -627,8 +660,7 @@ class ChartWidget extends StatelessWidget {
: value is String
? double.tryParse(value) ?? 0.0
: 0.0;
})
.fold(0.0, (prev, element) => prev + element);
}).fold(0.0, (prev, element) => prev + element);
ValueNotifier<int?> touchedIndex = ValueNotifier(null);
@ -665,10 +697,8 @@ class ChartWidget extends StatelessWidget {
touchCallback: (FlTouchEvent event, pieTouchResponse) {
if (pieTouchResponse?.touchedSection != null &&
event is! FlTapUpEvent) {
touchedIndex.value =
pieTouchResponse!
.touchedSection!
.touchedSectionIndex;
touchedIndex.value = pieTouchResponse!
.touchedSection!.touchedSectionIndex;
} else {
touchedIndex.value =
null; // Reset when not touching
@ -704,7 +734,8 @@ class ChartWidget extends StatelessWidget {
child: Column(
// Change Row to Column
crossAxisAlignment: CrossAxisAlignment.start,
children: generateIndicators(chartData, totalValue),
children:
generateIndicators(chartData, totalValue, context),
),
),
),
@ -870,8 +901,7 @@ class ChartWidget extends StatelessWidget {
child: Wrap(
spacing: 10, // Horizontal spacing between items
runSpacing: 5, // Vertical spacing between rows
children:
chunkedGroupByValues.expand((chunk) {
children: chunkedGroupByValues.expand((chunk) {
return chunk.map((group) {
List<String> groupByValuesList = groupByValues.toList();
int index = groupByValuesList.indexOf(group);
@ -938,8 +968,7 @@ class ChartWidget extends StatelessWidget {
print('LnTrnd1');
// Extract all years from the chart data
List<int> years =
(chartData['response'] as List<dynamic>)
List<int> years = (chartData['response'] as List<dynamic>)
.map<int>(
(entry) =>
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0,
@ -974,8 +1003,7 @@ class ChartWidget extends StatelessWidget {
// Filter chart data to only include entries within the last 5 years
List<dynamic> filteredData =
(chartData['response'] as List<dynamic>).where((entry) {
int year =
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
return year >= minYear && year <= maxYear;
}).toList();
print('LnTrnd2 $filteredData');
@ -985,8 +1013,7 @@ class ChartWidget extends StatelessWidget {
// (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
// .toSet();
Set<String> uniqueXValues =
filteredData.map<String>((entry) {
Set<String> uniqueXValues = filteredData.map<String>((entry) {
String? timePeriod =
entry['ObsKey']['TIME_PERIOD']; // Nullable String
print('TIME_PERIOD- $timePeriod');
@ -1050,8 +1077,7 @@ class ChartWidget extends StatelessWidget {
throw FormatException("Invalid TIME_PERIOD format: $timePeriod");
}
Set<double> uniqueXValuesProcessed =
uniqueXValues
Set<double> uniqueXValuesProcessed = uniqueXValues
.where((value) => value.isNotEmpty) // Remove any empty strings
.map(parseTimePeriod)
.toSet();
@ -1150,8 +1176,7 @@ class ChartWidget extends StatelessWidget {
child: Wrap(
spacing: 12,
runSpacing: 8,
children:
groupByValues.map((group) {
children: groupByValues.map((group) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
@ -1185,8 +1210,7 @@ class ChartWidget extends StatelessWidget {
// }
// Extract all years from the chart data
List<int> years =
(chartData['response'] as List<dynamic>)
List<int> years = (chartData['response'] as List<dynamic>)
.map<int>(
(entry) =>
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0,
@ -1212,13 +1236,11 @@ class ChartWidget extends StatelessWidget {
// Filter chart data to include only the selected years
List<dynamic> filteredData =
(chartData['response'] as List<dynamic>).where((entry) {
int year =
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
return selectedYears.contains(year);
}).toList();
Set<double> uniqueXValues =
filteredData
Set<double> uniqueXValues = filteredData
.map<double>(
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']),
)
@ -1296,8 +1318,7 @@ class ChartWidget extends StatelessWidget {
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
padding: const EdgeInsets.only(right: 40, top: 10),
child: SizedBox(
width:
(uniqueXValues.length * 50) +
width: (uniqueXValues.length * 50) +
50, // Adjust width dynamically
child: LineChart(
LineChartData(
@ -1318,8 +1339,7 @@ class ChartWidget extends StatelessWidget {
child: Wrap(
spacing: 12,
runSpacing: 8,
children:
groupByValues.map((group) {
children: groupByValues.map((group) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
@ -1359,8 +1379,7 @@ class ChartWidget extends StatelessWidget {
// }
// Extract all years from the chart data
List<int> years =
(chartData['response'] as List<dynamic>)
List<int> years = (chartData['response'] as List<dynamic>)
.map<int>(
(entry) =>
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0,
@ -1386,13 +1405,11 @@ class ChartWidget extends StatelessWidget {
// Filter chart data to include only the selected years
List<dynamic> filteredData =
(chartData['response'] as List<dynamic>).where((entry) {
int year =
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
return selectedYears.contains(year);
}).toList();
Set<double> uniqueXValues =
filteredData
Set<double> uniqueXValues = filteredData
.map<double>(
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']),
)
@ -1456,8 +1473,7 @@ class ChartWidget extends StatelessWidget {
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
padding: const EdgeInsets.only(right: 40, top: 20),
child: SizedBox(
width:
(uniqueXValues.length * 50) +
width: (uniqueXValues.length * 50) +
50, // Adjust width dynamically
child: LineChart(
LineChartData(
@ -1516,13 +1532,11 @@ class ChartWidget extends StatelessWidget {
int.tryParse(b['ObsKey']['TIME_PERIOD'].toString()) ?? 0;
// Extract QUARTER and convert "Q1", "Q2", etc. to numeric values
int quarterA =
int.tryParse(
int quarterA = int.tryParse(
a['ObsKey']['QUARTER'].toString().replaceAll('Q', ''),
) ??
0;
int quarterB =
int.tryParse(
int quarterB = int.tryParse(
b['ObsKey']['QUARTER'].toString().replaceAll('Q', ''),
) ??
0;
@ -1536,22 +1550,44 @@ class ChartWidget extends StatelessWidget {
});
}
print('chartData response sort: ${chartData['response']}');
// if (xValue != null && yValue != null) {
// xAxisData.add(xValue.toString());
// yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
// }
if (xValue != null && yValue != null) {
// Check if additional_x_group is "Timeperiod" and concatenate
// if (xValue != null && yValue != null) {
// // Check if additional_x_group is "Timeperiod" and concatenate
// String xLabel = xValue.toString();
// if (xadditionalgroup == 'TIME_PERIOD' && xTimePeriod != null) {
// xLabel = '$xTimePeriod-$xValue'; // Format: Label (TimePeriod)
// }
//
// xAxisData.add(xLabel);
// yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
// // yAxisLabels.add(unitMsr ?? '');
// }
}
for (var entry in chartData['response']) {
var xValue = entry['ObsKey'][groupByKey];
var xTimePeriod = entry['ObsKey']['TIME_PERIOD'];
var yValue = entry['ObsValue']['Value'];
var xadditionalgroup =
chartData['chart_type_json']['additional_x_group'];
if (xValue != null) {
String xLabel = xValue.toString();
if (xadditionalgroup == 'TIME_PERIOD' && xTimePeriod != null) {
xLabel = '$xTimePeriod-$xValue'; // Format: Label (TimePeriod)
}
xAxisData.add(xLabel);
}
if (yValue != null) {
yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
// yAxisLabels.add(unitMsr ?? '');
}
}
print('xAxisData $xAxisData');
print('yAxisData $yAxisData');
return Column(
children: [
Text(
@ -1581,21 +1617,18 @@ class ChartWidget extends StatelessWidget {
constraints: BoxConstraints(
minWidth:
screenWidth, // Ensure it at least fills available width
maxWidth:
chartWidth > screenWidth
maxWidth: chartWidth > screenWidth
? chartWidth
: screenWidth, // Prevent non-normalized constraints
),
child: Center(
child: SizedBox(
width:
xAxisData.length *
width: xAxisData.length *
(40 + 10), // Bar width + manual spacing
child: BarChart(
BarChartData(
alignment: BarChartAlignment.spaceAround,
maxY:
yAxisData.isNotEmpty
maxY: yAxisData.isNotEmpty
? yAxisData.reduce(
(a, b) => a > b ? a : b,
) *
@ -1625,8 +1658,8 @@ class ChartWidget extends StatelessWidget {
enabled: false,
handleBuiltInTouches: false,
touchTooltipData: BarTouchTooltipData(
getTooltipColor:
(group) => Colors.transparent,
getTooltipColor: (group) =>
Colors.transparent,
// fitInsideHorizontally: true,
// fitInsideVertically: true,
// tooltipPadding: const EdgeInsets.all(8),
@ -1666,8 +1699,7 @@ class ChartWidget extends StatelessWidget {
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
interval:
(yAxisData.isNotEmpty
interval: (yAxisData.isNotEmpty
? yAxisData.reduce(
(a, b) => a > b ? a : b,
) /
@ -1691,10 +1723,12 @@ class ChartWidget extends StatelessWidget {
getTitlesWidget: (value, meta) {
if (value.toInt() < xAxisData.length) {
String title = xAxisData[value.toInt()];
String displayTitle =
title.length > 10
String displayTitle = title.length > 10
? title.substring(0, 10) + '...'
: title;
print('barChartVALUECHECKTITLE $title');
print(
'barChartVALUECHECK $displayTitle');
return Padding(
padding: const EdgeInsets.only(
@ -1711,9 +1745,8 @@ class ChartWidget extends StatelessWidget {
child: TooltipTheme(
data: TooltipThemeData(
decoration: BoxDecoration(
color:
Colors
.blueGrey[800], // Change background color
color: Colors.blueGrey[
800], // Change background color
borderRadius:
BorderRadius.circular(
8,
@ -1726,8 +1759,7 @@ class ChartWidget extends StatelessWidget {
child: TooltipTheme(
data: TooltipThemeData(
decoration: BoxDecoration(
color:
Colors
color: Colors
.black, // Change background color
// color: Colors.blueGrey[800], // Change background color
borderRadius:
@ -1844,8 +1876,7 @@ class ChartWidget extends StatelessWidget {
});
// If no valid TIME_PERIOD with a month is found, return original response
List<Map<String, dynamic>> finalData =
sortedData.isNotEmpty
List<Map<String, dynamic>> finalData = sortedData.isNotEmpty
? sortedData
: List.from(chartData['response']);
@ -1926,8 +1957,7 @@ class ChartWidget extends StatelessWidget {
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
interval:
(yAxisData.isNotEmpty
interval: (yAxisData.isNotEmpty
? yAxisData.reduce((a, b) => a > b ? a : b) / 5
: 1),
getTitlesWidget: (value, meta) {
@ -1994,8 +2024,7 @@ class ChartWidget extends StatelessWidget {
barsSpace: 20,
barRods: [
BarChartRodData(
toY:
(yAxisData[index] == 0)
toY: (yAxisData[index] == 0)
? 0.0001
: yAxisData[index],
// color: Colors.blueAccent,
@ -2132,8 +2161,7 @@ class ChartWidget extends StatelessWidget {
), // Dynamically calculate max Y
// barGroups: _buildHorizontalRotateBarGroups(
// chartData, groupByValues), // Build bar groups
barGroups:
hasBarColors
barGroups: hasBarColors
? _buildHorizontalRotateBarGroupsBarColors(
chartData,
groupByValues,
@ -2159,8 +2187,7 @@ class ChartWidget extends StatelessWidget {
value.toInt(),
);
String displayTitle =
title.length > 10
String displayTitle = title.length > 10
? title.substring(0, 10) + '...'
: title;
@ -2177,8 +2204,7 @@ class ChartWidget extends StatelessWidget {
child: TooltipTheme(
data: TooltipThemeData(
decoration: BoxDecoration(
color:
Colors
color: Colors
.black, // Change background color
// color: Colors.blueGrey[800], // Change background color
borderRadius:
@ -2273,8 +2299,7 @@ class ChartWidget extends StatelessWidget {
'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex',
);
// crop = cropType; // Fallback to cropType
crop =
(crops != null && crops.isNotEmpty)
crop = (crops != null && crops.isNotEmpty)
? crops.first
: cropType;
}
@ -2331,8 +2356,8 @@ class ChartWidget extends StatelessWidget {
);
case 'horizontal_rotate':
String cropKey =
chartData['chart_type_json']['y_sub_group']; // Dynamically get crop key
String cropKey = chartData['chart_type_json']
['y_sub_group']; // Dynamically get crop key
// Group crops by CROP_TYPE
Map<String, List<String>> groupedCrops = {};
@ -2551,9 +2576,7 @@ class ChartWidget extends StatelessWidget {
enabled: false, // Enable touch to show tooltip
handleBuiltInTouches: false,
touchTooltipData: BarTouchTooltipData(
getTooltipColor:
(group) =>
Colors
getTooltipColor: (group) => Colors
.transparent, // Light background for visibility
tooltipHorizontalAlignment:
FLHorizontalAlignment.center,
@ -2574,6 +2597,18 @@ class ChartWidget extends StatelessWidget {
String crop = groupedCrops[cropType]![rodIndex];
double value = rod.toY;
// Show tooltip for zero values
if (value == 0) {
return BarTooltipItem(
'0', // Display "0" instead of hiding
textAlign: TextAlign.right,
const TextStyle(
color: Colors.black,
fontSize: 12,
),
);
}
// Format values dynamically
// String formattedValue = value >= 1e6
// ? '${(value / 1e6).toStringAsFixed(1)}M'
@ -2593,7 +2628,7 @@ class ChartWidget extends StatelessWidget {
0,
); // for values smaller than 1000
}
print('formattedValue00 $formattedValue');
return BarTooltipItem(
formattedValue,
textAlign: TextAlign.right,
@ -2690,8 +2725,7 @@ class ChartWidget extends StatelessWidget {
// barGroups: _buildHorizontalRotateBarGroups(
// chartData, groupByValues),
barGroups:
hasBarColors
barGroups: hasBarColors
? _buildHorizontalRotateBarGroupsBarColors(
chartData,
groupByValues,
@ -2923,8 +2957,7 @@ class ChartWidget extends StatelessWidget {
// return FlSpot(xValue, yValue);
// }).toList();
List<FlSpot> spots =
filteredData
List<FlSpot> spots = filteredData
.where((entry) => entry['ObsKey'][groupByKey] == group)
.map<FlSpot>((entry) {
String timePeriod = entry['ObsKey']['TIME_PERIOD'];
@ -2946,8 +2979,7 @@ class ChartWidget extends StatelessWidget {
yValue = value;
} else if (value is String) {
yValue =
double.tryParse(value) ??
0.0; // Handle invalid strings safely
double.tryParse(value) ?? 0.0; // Handle invalid strings safely
} else {
throw Exception(
"Unexpected value type: ${value.runtimeType}",
@ -2956,8 +2988,7 @@ class ChartWidget extends StatelessWidget {
print('LineTrendX $xValue');
print('LineTrendY $yValue');
return FlSpot(xValue, yValue);
})
.toList()
}).toList()
..sort((a, b) => a.x.compareTo(b.x));
print('spots - $spots');
@ -3014,8 +3045,7 @@ class ChartWidget extends StatelessWidget {
getTooltipColor: (spot) => Colors.black,
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
return lineBarsSpot.map((lineBarSpot) {
Color lineColor =
lineBarSpot.bar is LineChartBarData
Color lineColor = lineBarSpot.bar is LineChartBarData
? (lineBarSpot.bar).color ?? Colors.white
: Colors.white; // Extract bar color safely
return LineTooltipItem(
@ -3030,8 +3060,7 @@ class ChartWidget extends StatelessWidget {
),
TextSpan(
// text: formatNumber(lineBarSpot.y),
text:
(chartConversion != null &&
text: (chartConversion != null &&
chartConversion.isNotEmpty &&
number_format != null)
? formatNumberConversion(
@ -3128,10 +3157,10 @@ class ChartWidget extends StatelessWidget {
return FlGridData(
show: false,
drawVerticalLine: true,
getDrawingHorizontalLine:
(value) => FlLine(color: Colors.grey, strokeWidth: 1),
getDrawingVerticalLine:
(value) => FlLine(color: Colors.grey, strokeWidth: 1),
getDrawingHorizontalLine: (value) =>
FlLine(color: Colors.grey, strokeWidth: 1),
getDrawingVerticalLine: (value) =>
FlLine(color: Colors.grey, strokeWidth: 1),
);
}
@ -3568,18 +3597,16 @@ class ChartWidget extends StatelessWidget {
String groupValue = groupByValues.elementAt(i);
// Filter data for the current group (grouping by CROP_TYPE)
List<dynamic> groupData =
responseData.where((entry) {
List<dynamic> groupData = responseData.where((entry) {
return entry['ObsKey'][groupByKeyValueData] == groupValue;
}).toList();
// Create BarChartRodData for each bar in the group
List<BarChartRodData> barRods =
groupData.map((data) {
List<BarChartRodData> barRods = groupData.map((data) {
// Ensure to retrieve and parse 'ObsValue' value (which should be a double)
double value =
double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0;
// double minBarHeight = 0.5;
double minBarHeight = 0.1;
print('multi_bar1.1');
// final List<Color> uniqueColorsForTwo = [
// Color(0xFF648CBA),
@ -3598,13 +3625,11 @@ class ChartWidget extends StatelessWidget {
chartData['dataset'] == 'hotel_guests' ||
chartData['dataset'] == 'health_services' ||
chartData['dataset'] == 'clinics') {
barColor =
uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length];
barColor = uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length];
colorIndex++;
} else if (chartData['dataset'] == 'cropsk') {
barColor =
uniqueColorsForThree[colorIndex %
uniqueColorsForThree.length];
uniqueColorsForThree[colorIndex % uniqueColorsForThree.length];
colorIndex++;
} else if (chartData['dataset'] == 'oil_and_gas') {
barColor =
@ -3616,7 +3641,8 @@ class ChartWidget extends StatelessWidget {
}
return BarChartRodData(
toY: value, // Use the parsed value
// toY: value,
toY: value == 0 ? minBarHeight : value, // Use the parsed value
color: barColor, // Dynamic color
width: 20,
@ -3677,8 +3703,7 @@ class ChartWidget extends StatelessWidget {
String groupValue = groupByValues.elementAt(i);
// Filter data for the current group
List<dynamic> groupData =
responseData.where((entry) {
List<dynamic> groupData = responseData.where((entry) {
return entry['ObsKey'][groupByKeyValueData1] == groupValue;
}).toList();
@ -3698,8 +3723,7 @@ class ChartWidget extends StatelessWidget {
});
// Create BarChartRodData for each bar in the group
List<BarChartRodData> barRods =
groupData.map((data) {
List<BarChartRodData> barRods = groupData.map((data) {
double value =
double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0;
@ -3714,9 +3738,8 @@ class ChartWidget extends StatelessWidget {
// Determine color dynamically
Color barColor;
if (chartData['dataset'] == 'health_services') {
barColor =
uniqueColorsForTwo[colorIndex %
2]; // Alternate between two colors
barColor = uniqueColorsForTwo[
colorIndex % 2]; // Alternate between two colors
colorIndex++; // Update index for next bar
} else {
// barColor = chartBarColors[gender] ?? Colors.grey; // Default gender-based color
@ -3772,14 +3795,12 @@ Widget _buildChartLegend(
alignment: WrapAlignment.center,
spacing: 12,
runSpacing: 6,
children:
uniqueCropTypes.map((cropType) {
children: uniqueCropTypes.map((cropType) {
// Color cropColor = parsedChartBarColors[cropType] ?? Colors.grey; // Fetch color for each crop type
int index = uniqueCropTypes.toList().indexOf(
cropType,
); // Get index for cycling colors
Color cropColor =
parsedChartBarColors.isNotEmpty &&
Color cropColor = parsedChartBarColors.isNotEmpty &&
parsedChartBarColors.containsKey(cropType)
? parsedChartBarColors[cropType]!
: uniqueColors[index % uniqueColors.length];

View File

@ -702,6 +702,8 @@ class LoginRoute extends HookConsumerWidget {
);
final dontHaveAnAccountRegisterBtn = TextButton(
onPressed: () => {context.push('/register')},
// onPressed: () =>
// {context.push('/forgot-password/surendar.m@venbainfotech.com')},
child: Text.rich(
textAlign: TextAlign.center,
TextSpan(

View File

@ -152,7 +152,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(AppLocalizations.of(context)!.status_success),),
SnackBar(
content: Text(AppLocalizations.of(context)!.status_success),
),
);
} catch (e) {
setState(() {
@ -160,13 +162,16 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
});
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.translate('Error updating status: $e','$e خطأ في تحديث الحالة: '))),
SnackBar(
content: Text(context.translate(
'Error updating status: $e', '$e خطأ في تحديث الحالة: '))),
);
}
}
//Method to show a confirmation dialog when status is changed
Future<void> _showConfirmationDialog(User user, String newStatus,String statusUpdate) async {
Future<void> _showConfirmationDialog(
User user, String newStatus, String statusUpdate) async {
print('user $user');
double myheight = MediaQuery.of(context).size.height;
@ -416,8 +421,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
// // fit: BoxFit.contain,
// ),
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
vertical: 9, horizontal: 18.0),
// contentPadding: EdgeInsets.symmetric(
// vertical: 9, horizontal: 18.0),
contentPadding: EdgeInsets.zero,
),
onChanged: filterUsers,
),
@ -444,7 +450,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
SizedBox(height: 15),
// Space between icon and text
Text(
AppLocalizations.of(context)!.no_result_found,
AppLocalizations.of(context)!
.no_result_found,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
@ -455,7 +462,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
SizedBox(height: 12), // Space between texts
FittedBox(
child: Text(
context.translate("We couldn't find anything matching your search.",'لم نعثر على أي شيء يطابق بحثك.'),
context.translate(
"We couldn't find anything matching your search.",
'لم نعثر على أي شيء يطابق بحثك.'),
style: TextStyle(
fontSize: 18,
color: Color(0xFF898C81)),
@ -533,7 +542,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
(index) => DataCell(
index == 0
? Text(
AppLocalizations.of(context)!.no_result_found,
AppLocalizations.of(
context)!
.no_result_found,
style: TextStyle(
fontStyle: FontStyle
.italic),
@ -573,7 +584,11 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
print(user);
if (newStatus != null) {
_showConfirmationDialog(
user, newStatus, statusOptions[newStatus]!,);
user,
newStatus,
statusOptions[
newStatus]!,
);
}
},
),

View File

@ -989,7 +989,9 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
),
ListTile(
leading: Icon(Icons.mail_outlined),
title: Text(context.translate('Contact Us', 'اتصل بنا'),),
title: Text(
context.translate('Contact Us', 'اتصل بنا'),
),
onTap: () => context.push('/contact'),
),
if (userId != 'guest')

View File

@ -1,7 +1,7 @@
name: uae_stat
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
publish_to: "none"
version: 1.0.42+43
version: 1.0.43+44
environment:
sdk: ">=3.2.3 <4.0.0"