bug fix and forgot password
This commit is contained in:
parent
a0d7a733a4
commit
efb0d38664
@ -20,12 +20,12 @@ if (project.hasProperty('google-services.json')) {
|
|||||||
|
|
||||||
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
||||||
if (flutterVersionCode == null) {
|
if (flutterVersionCode == null) {
|
||||||
flutterVersionCode = "43"
|
flutterVersionCode = "44"
|
||||||
}
|
}
|
||||||
|
|
||||||
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
||||||
if (flutterVersionName == null) {
|
if (flutterVersionName == null) {
|
||||||
flutterVersionName = "1.0.42"
|
flutterVersionName = "1.0.43"
|
||||||
}
|
}
|
||||||
|
|
||||||
def keystorePropertiesFile = rootProject.file("key.properties")
|
def keystorePropertiesFile = rootProject.file("key.properties")
|
||||||
|
|||||||
@ -30,13 +30,27 @@
|
|||||||
<meta-data android:name="flutter_deeplinking_enabled"
|
<meta-data android:name="flutter_deeplinking_enabled"
|
||||||
android:value="true"/>
|
android:value="true"/>
|
||||||
<intent-filter android:autoVerify="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" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data
|
<data
|
||||||
android:scheme="https"
|
android:scheme="flutterdeeplink"
|
||||||
android:host="fcsc-a161c.web.app"
|
android:host="fcsc"
|
||||||
|
android:pathPrefix="/login" />
|
||||||
|
<data
|
||||||
|
android:scheme="flutterdeeplink"
|
||||||
|
android:host="fcsc"
|
||||||
android:pathPrefix="/chartScreen"/>
|
android:pathPrefix="/chartScreen"/>
|
||||||
|
<data
|
||||||
|
android:scheme="flutterdeeplink"
|
||||||
|
android:host="fcsc"
|
||||||
|
android:pathPrefix="/forgot-password"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<!-- <intent-filter >-->
|
<!-- <intent-filter >-->
|
||||||
<!-- <action android:name="android.intent.action.VIEW" />-->
|
<!-- <action android:name="android.intent.action.VIEW" />-->
|
||||||
|
|||||||
@ -667,7 +667,8 @@ final GoRouter router = GoRouter(
|
|||||||
redirect: (context, state) async {
|
redirect: (context, state) async {
|
||||||
if (state.uri.path == '/SessionCheckScreen' ||
|
if (state.uri.path == '/SessionCheckScreen' ||
|
||||||
state.uri.path == '/login' ||
|
state.uri.path == '/login' ||
|
||||||
state.uri.path == '/register') {
|
state.uri.path == '/register' ||
|
||||||
|
state.uri.path == '/forgot-password/:email') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -240,7 +240,8 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
|
|||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
filterData(
|
filterData(
|
||||||
value); // Call filter function directly on input change
|
value); // Call filter function directly on input change
|
||||||
},
|
}, // Ensures vertical alignment
|
||||||
|
// Centers text horizontally
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: AppLocalizations.of(context)!.search,
|
hintText: AppLocalizations.of(context)!.search,
|
||||||
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
|
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
|
||||||
@ -261,8 +262,9 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
|
|||||||
// // fit: BoxFit.contain,
|
// // fit: BoxFit.contain,
|
||||||
// ),
|
// ),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding:
|
// contentPadding:
|
||||||
EdgeInsets.symmetric(vertical: 9, horizontal: 18.0),
|
// EdgeInsets.symmetric(vertical: 9, horizontal: 18.0),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -107,6 +107,66 @@ class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
|
|||||||
return null;
|
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(
|
Future<void> updatePassword(
|
||||||
String email, String oldPassword, String newPassword) async {
|
String email, String oldPassword, String newPassword) async {
|
||||||
try {
|
try {
|
||||||
@ -122,9 +182,27 @@ class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
|
|||||||
'Authorization': 'Bearer $token',
|
'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(
|
await _pb.collection('users').update(
|
||||||
email,
|
userId,
|
||||||
body: {
|
body: {
|
||||||
'password': newPassword,
|
'password': newPassword,
|
||||||
'passwordConfirm': newPassword,
|
'passwordConfirm': newPassword,
|
||||||
@ -146,19 +224,14 @@ class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
print('_isPasswordUpdated $_isPasswordUpdated');
|
print('_isPasswordUpdated $_isPasswordUpdated');
|
||||||
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => ProfileScreen(userId: userId)),
|
|
||||||
// );
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(context.translate('Failed to update password: $e','فشل في تحديث كلمة المرور')),
|
content: Text('Failed to update password: $e'),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2695,50 +2695,54 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> shareCurrentPage(BuildContext context, bool _isSharing) async {
|
Future<void> shareCurrentPage(BuildContext context, bool isSharing) async {
|
||||||
if (_isSharing) return; // Prevent multiple taps
|
if (isSharing) return; // Prevent multiple taps
|
||||||
|
|
||||||
_isSharing = true;
|
isSharing = true;
|
||||||
try {
|
try {
|
||||||
final String currentRoute = GoRouterState.of(context).uri.toString();
|
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 shareLink = '$baseAppLink$currentRoute';
|
||||||
final String shareText = 'Check this out!';
|
final String shareText = 'Check this out!\n\n$shareLink';
|
||||||
final String svgAssetPath = 'assets/backgrounds/share/fcsc.svg';
|
print('Generated Share Link: $shareLink');
|
||||||
|
|
||||||
|
// Optional: Capture SVG to image
|
||||||
|
final String svgAssetPath = 'assets/backgrounds/share/fcsc.svg';
|
||||||
final screenshotController = ScreenshotController();
|
final screenshotController = ScreenshotController();
|
||||||
final svgWidget = SvgPicture.asset(
|
final svgWidget = SvgPicture.asset(
|
||||||
svgAssetPath,
|
svgAssetPath,
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Uint8List? capturedImage =
|
final Uint8List? capturedImage =
|
||||||
await screenshotController.captureFromWidget(
|
await screenshotController.captureFromWidget(
|
||||||
Material(child: svgWidget),
|
Material(child: svgWidget),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (capturedImage == null) {
|
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 directory = await getTemporaryDirectory();
|
||||||
final file = File('${directory.path}/share.svg');
|
final file = File('${directory.path}/share_image.png');
|
||||||
await file.writeAsBytes(capturedImage);
|
await file.writeAsBytes(capturedImage);
|
||||||
|
|
||||||
await Share.shareXFiles(
|
await Share.shareXFiles(
|
||||||
[XFile(file.path)],
|
[XFile(file.path)],
|
||||||
text: '$shareText\n$shareLink',
|
text: shareText,
|
||||||
subject: 'Shared Content',
|
subject: 'Shared Content',
|
||||||
);
|
);
|
||||||
|
|
||||||
await file.delete();
|
await file.delete();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error sharing file: $e");
|
print("Error sharing content: $e");
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('Error sharing: $e')),
|
SnackBar(content: Text('Error sharing: ${e.toString()}')),
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
_isSharing = false; // Reset flag after sharing completes
|
isSharing = false; // Reset flag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'dart:math';
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:uae_stat/domain/use_cases/language.dart';
|
||||||
// import 'package:syncfusion_flutter_charts/charts.dart';
|
// import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
|
||||||
class ChartWidget extends StatelessWidget {
|
class ChartWidget extends StatelessWidget {
|
||||||
@ -208,8 +209,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
x: entry['ObsKey']['TIME_PERIOD'],
|
x: entry['ObsKey']['TIME_PERIOD'],
|
||||||
y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0,
|
y: double.tryParse(entry['ObsValue']['Value']) ?? 0.0,
|
||||||
);
|
);
|
||||||
})
|
}).toList();
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BarChartGroupData> parseColumnChartData(dynamic chartData) {
|
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;
|
var groupByKeyValue;
|
||||||
if (chartData['chart_type_json']['chart_type'] == 'bar_chart_horizontal' ||
|
if (chartData['chart_type_json']['chart_type'] == 'bar_chart_horizontal' ||
|
||||||
chartData['chart_type_json']['chart_type'] == 'horizontal_rotate') {
|
chartData['chart_type_json']['chart_type'] == 'horizontal_rotate') {
|
||||||
@ -412,50 +413,83 @@ class ChartWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// double percentage = (value / totalValue) * 100;
|
// double percentage = (value / totalValue) * 100;
|
||||||
String percentage =
|
String percentage = (totalValue > 0)
|
||||||
(totalValue > 0)
|
|
||||||
? ((value / totalValue) * 100).toStringAsFixed(1)
|
? ((value / totalValue) * 100).toStringAsFixed(1)
|
||||||
: "0.0";
|
: "0.0";
|
||||||
// bool isTouched = index == touchedIndex;
|
// 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(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start, // Aligns dot to text start
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 10,
|
height: 10,
|
||||||
|
margin: EdgeInsets.only(top: 4), // Adjust to align with text
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: uniqueColors[index % uniqueColors.length],
|
color: uniqueColors[index % uniqueColors.length],
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
TooltipTheme(
|
Expanded(
|
||||||
|
child: TooltipTheme(
|
||||||
data: TooltipThemeData(
|
data: TooltipThemeData(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blueGrey[800], // Change background color
|
color: Colors.blueGrey[800], // Change background color
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(8),
|
||||||
8,
|
|
||||||
), // Optional: rounded corners
|
|
||||||
),
|
),
|
||||||
textStyle: TextStyle(color: Colors.white), // Change text color
|
textStyle: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: title, // Full text on hover
|
message: title, // Full text on hover
|
||||||
child: ConstrainedBox(
|
|
||||||
// Constrain width to allow wrapping
|
|
||||||
constraints: BoxConstraints(maxWidth: 250),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
|
context.translate(
|
||||||
'$title -- $percentage%',
|
'$title -- $percentage%',
|
||||||
|
'$title -- %$percentage',
|
||||||
|
),
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
// overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 5),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
@ -618,8 +652,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
case 'pie_chart':
|
case 'pie_chart':
|
||||||
double totalValue = chartData['response']
|
double totalValue = chartData['response'].map<double>((entry) {
|
||||||
.map<double>((entry) {
|
|
||||||
var value = entry['ObsValue']['Value'];
|
var value = entry['ObsValue']['Value'];
|
||||||
// print('Processing value: $value, type: ${value.runtimeType}');
|
// print('Processing value: $value, type: ${value.runtimeType}');
|
||||||
return (value is num)
|
return (value is num)
|
||||||
@ -627,8 +660,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
: value is String
|
: value is String
|
||||||
? double.tryParse(value) ?? 0.0
|
? double.tryParse(value) ?? 0.0
|
||||||
: 0.0;
|
: 0.0;
|
||||||
})
|
}).fold(0.0, (prev, element) => prev + element);
|
||||||
.fold(0.0, (prev, element) => prev + element);
|
|
||||||
|
|
||||||
ValueNotifier<int?> touchedIndex = ValueNotifier(null);
|
ValueNotifier<int?> touchedIndex = ValueNotifier(null);
|
||||||
|
|
||||||
@ -665,10 +697,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
touchCallback: (FlTouchEvent event, pieTouchResponse) {
|
touchCallback: (FlTouchEvent event, pieTouchResponse) {
|
||||||
if (pieTouchResponse?.touchedSection != null &&
|
if (pieTouchResponse?.touchedSection != null &&
|
||||||
event is! FlTapUpEvent) {
|
event is! FlTapUpEvent) {
|
||||||
touchedIndex.value =
|
touchedIndex.value = pieTouchResponse!
|
||||||
pieTouchResponse!
|
.touchedSection!.touchedSectionIndex;
|
||||||
.touchedSection!
|
|
||||||
.touchedSectionIndex;
|
|
||||||
} else {
|
} else {
|
||||||
touchedIndex.value =
|
touchedIndex.value =
|
||||||
null; // Reset when not touching
|
null; // Reset when not touching
|
||||||
@ -704,7 +734,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
// Change Row to Column
|
// Change Row to Column
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: generateIndicators(chartData, totalValue),
|
children:
|
||||||
|
generateIndicators(chartData, totalValue, context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -870,8 +901,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 10, // Horizontal spacing between items
|
spacing: 10, // Horizontal spacing between items
|
||||||
runSpacing: 5, // Vertical spacing between rows
|
runSpacing: 5, // Vertical spacing between rows
|
||||||
children:
|
children: chunkedGroupByValues.expand((chunk) {
|
||||||
chunkedGroupByValues.expand((chunk) {
|
|
||||||
return chunk.map((group) {
|
return chunk.map((group) {
|
||||||
List<String> groupByValuesList = groupByValues.toList();
|
List<String> groupByValuesList = groupByValues.toList();
|
||||||
int index = groupByValuesList.indexOf(group);
|
int index = groupByValuesList.indexOf(group);
|
||||||
@ -938,8 +968,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
print('LnTrnd1');
|
print('LnTrnd1');
|
||||||
|
|
||||||
// Extract all years from the chart data
|
// Extract all years from the chart data
|
||||||
List<int> years =
|
List<int> years = (chartData['response'] as List<dynamic>)
|
||||||
(chartData['response'] as List<dynamic>)
|
|
||||||
.map<int>(
|
.map<int>(
|
||||||
(entry) =>
|
(entry) =>
|
||||||
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0,
|
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
|
// Filter chart data to only include entries within the last 5 years
|
||||||
List<dynamic> filteredData =
|
List<dynamic> filteredData =
|
||||||
(chartData['response'] as List<dynamic>).where((entry) {
|
(chartData['response'] as List<dynamic>).where((entry) {
|
||||||
int year =
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
||||||
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
|
||||||
return year >= minYear && year <= maxYear;
|
return year >= minYear && year <= maxYear;
|
||||||
}).toList();
|
}).toList();
|
||||||
print('LnTrnd2 $filteredData');
|
print('LnTrnd2 $filteredData');
|
||||||
@ -985,8 +1013,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
|
// (entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
|
||||||
// .toSet();
|
// .toSet();
|
||||||
|
|
||||||
Set<String> uniqueXValues =
|
Set<String> uniqueXValues = filteredData.map<String>((entry) {
|
||||||
filteredData.map<String>((entry) {
|
|
||||||
String? timePeriod =
|
String? timePeriod =
|
||||||
entry['ObsKey']['TIME_PERIOD']; // Nullable String
|
entry['ObsKey']['TIME_PERIOD']; // Nullable String
|
||||||
print('TIME_PERIOD- $timePeriod');
|
print('TIME_PERIOD- $timePeriod');
|
||||||
@ -1050,8 +1077,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
throw FormatException("Invalid TIME_PERIOD format: $timePeriod");
|
throw FormatException("Invalid TIME_PERIOD format: $timePeriod");
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<double> uniqueXValuesProcessed =
|
Set<double> uniqueXValuesProcessed = uniqueXValues
|
||||||
uniqueXValues
|
|
||||||
.where((value) => value.isNotEmpty) // Remove any empty strings
|
.where((value) => value.isNotEmpty) // Remove any empty strings
|
||||||
.map(parseTimePeriod)
|
.map(parseTimePeriod)
|
||||||
.toSet();
|
.toSet();
|
||||||
@ -1150,8 +1176,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children:
|
children: groupByValues.map((group) {
|
||||||
groupByValues.map((group) {
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -1185,8 +1210,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// Extract all years from the chart data
|
// Extract all years from the chart data
|
||||||
List<int> years =
|
List<int> years = (chartData['response'] as List<dynamic>)
|
||||||
(chartData['response'] as List<dynamic>)
|
|
||||||
.map<int>(
|
.map<int>(
|
||||||
(entry) =>
|
(entry) =>
|
||||||
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0,
|
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
|
// Filter chart data to include only the selected years
|
||||||
List<dynamic> filteredData =
|
List<dynamic> filteredData =
|
||||||
(chartData['response'] as List<dynamic>).where((entry) {
|
(chartData['response'] as List<dynamic>).where((entry) {
|
||||||
int year =
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
||||||
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
|
||||||
return selectedYears.contains(year);
|
return selectedYears.contains(year);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
Set<double> uniqueXValues =
|
Set<double> uniqueXValues = filteredData
|
||||||
filteredData
|
|
||||||
.map<double>(
|
.map<double>(
|
||||||
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']),
|
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']),
|
||||||
)
|
)
|
||||||
@ -1296,8 +1318,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
|
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
|
||||||
padding: const EdgeInsets.only(right: 40, top: 10),
|
padding: const EdgeInsets.only(right: 40, top: 10),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width:
|
width: (uniqueXValues.length * 50) +
|
||||||
(uniqueXValues.length * 50) +
|
|
||||||
50, // Adjust width dynamically
|
50, // Adjust width dynamically
|
||||||
child: LineChart(
|
child: LineChart(
|
||||||
LineChartData(
|
LineChartData(
|
||||||
@ -1318,8 +1339,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children:
|
children: groupByValues.map((group) {
|
||||||
groupByValues.map((group) {
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -1359,8 +1379,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// Extract all years from the chart data
|
// Extract all years from the chart data
|
||||||
List<int> years =
|
List<int> years = (chartData['response'] as List<dynamic>)
|
||||||
(chartData['response'] as List<dynamic>)
|
|
||||||
.map<int>(
|
.map<int>(
|
||||||
(entry) =>
|
(entry) =>
|
||||||
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0,
|
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
|
// Filter chart data to include only the selected years
|
||||||
List<dynamic> filteredData =
|
List<dynamic> filteredData =
|
||||||
(chartData['response'] as List<dynamic>).where((entry) {
|
(chartData['response'] as List<dynamic>).where((entry) {
|
||||||
int year =
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
||||||
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
|
||||||
return selectedYears.contains(year);
|
return selectedYears.contains(year);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
Set<double> uniqueXValues =
|
Set<double> uniqueXValues = filteredData
|
||||||
filteredData
|
|
||||||
.map<double>(
|
.map<double>(
|
||||||
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']),
|
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']),
|
||||||
)
|
)
|
||||||
@ -1456,8 +1473,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
|
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
|
||||||
padding: const EdgeInsets.only(right: 40, top: 20),
|
padding: const EdgeInsets.only(right: 40, top: 20),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width:
|
width: (uniqueXValues.length * 50) +
|
||||||
(uniqueXValues.length * 50) +
|
|
||||||
50, // Adjust width dynamically
|
50, // Adjust width dynamically
|
||||||
child: LineChart(
|
child: LineChart(
|
||||||
LineChartData(
|
LineChartData(
|
||||||
@ -1516,13 +1532,11 @@ class ChartWidget extends StatelessWidget {
|
|||||||
int.tryParse(b['ObsKey']['TIME_PERIOD'].toString()) ?? 0;
|
int.tryParse(b['ObsKey']['TIME_PERIOD'].toString()) ?? 0;
|
||||||
|
|
||||||
// Extract QUARTER and convert "Q1", "Q2", etc. to numeric values
|
// Extract QUARTER and convert "Q1", "Q2", etc. to numeric values
|
||||||
int quarterA =
|
int quarterA = int.tryParse(
|
||||||
int.tryParse(
|
|
||||||
a['ObsKey']['QUARTER'].toString().replaceAll('Q', ''),
|
a['ObsKey']['QUARTER'].toString().replaceAll('Q', ''),
|
||||||
) ??
|
) ??
|
||||||
0;
|
0;
|
||||||
int quarterB =
|
int quarterB = int.tryParse(
|
||||||
int.tryParse(
|
|
||||||
b['ObsKey']['QUARTER'].toString().replaceAll('Q', ''),
|
b['ObsKey']['QUARTER'].toString().replaceAll('Q', ''),
|
||||||
) ??
|
) ??
|
||||||
0;
|
0;
|
||||||
@ -1536,22 +1550,44 @@ class ChartWidget extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print('chartData response sort: ${chartData['response']}');
|
||||||
|
|
||||||
// if (xValue != null && yValue != null) {
|
// if (xValue != null && yValue != null) {
|
||||||
// xAxisData.add(xValue.toString());
|
// xAxisData.add(xValue.toString());
|
||||||
// yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
|
// yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
|
||||||
// }
|
// }
|
||||||
if (xValue != null && yValue != null) {
|
// if (xValue != null && yValue != null) {
|
||||||
// Check if additional_x_group is "Timeperiod" and concatenate
|
// // 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();
|
String xLabel = xValue.toString();
|
||||||
if (xadditionalgroup == 'TIME_PERIOD' && xTimePeriod != null) {
|
if (xadditionalgroup == 'TIME_PERIOD' && xTimePeriod != null) {
|
||||||
xLabel = '$xTimePeriod-$xValue'; // Format: Label (TimePeriod)
|
xLabel = '$xTimePeriod-$xValue'; // Format: Label (TimePeriod)
|
||||||
}
|
}
|
||||||
|
|
||||||
xAxisData.add(xLabel);
|
xAxisData.add(xLabel);
|
||||||
|
}
|
||||||
|
if (yValue != null) {
|
||||||
yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
|
yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
|
||||||
// yAxisLabels.add(unitMsr ?? '');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
print('xAxisData $xAxisData');
|
||||||
|
print('yAxisData $yAxisData');
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
@ -1581,21 +1617,18 @@ class ChartWidget extends StatelessWidget {
|
|||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
minWidth:
|
minWidth:
|
||||||
screenWidth, // Ensure it at least fills available width
|
screenWidth, // Ensure it at least fills available width
|
||||||
maxWidth:
|
maxWidth: chartWidth > screenWidth
|
||||||
chartWidth > screenWidth
|
|
||||||
? chartWidth
|
? chartWidth
|
||||||
: screenWidth, // Prevent non-normalized constraints
|
: screenWidth, // Prevent non-normalized constraints
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width:
|
width: xAxisData.length *
|
||||||
xAxisData.length *
|
|
||||||
(40 + 10), // Bar width + manual spacing
|
(40 + 10), // Bar width + manual spacing
|
||||||
child: BarChart(
|
child: BarChart(
|
||||||
BarChartData(
|
BarChartData(
|
||||||
alignment: BarChartAlignment.spaceAround,
|
alignment: BarChartAlignment.spaceAround,
|
||||||
maxY:
|
maxY: yAxisData.isNotEmpty
|
||||||
yAxisData.isNotEmpty
|
|
||||||
? yAxisData.reduce(
|
? yAxisData.reduce(
|
||||||
(a, b) => a > b ? a : b,
|
(a, b) => a > b ? a : b,
|
||||||
) *
|
) *
|
||||||
@ -1625,8 +1658,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
handleBuiltInTouches: false,
|
handleBuiltInTouches: false,
|
||||||
touchTooltipData: BarTouchTooltipData(
|
touchTooltipData: BarTouchTooltipData(
|
||||||
getTooltipColor:
|
getTooltipColor: (group) =>
|
||||||
(group) => Colors.transparent,
|
Colors.transparent,
|
||||||
// fitInsideHorizontally: true,
|
// fitInsideHorizontally: true,
|
||||||
// fitInsideVertically: true,
|
// fitInsideVertically: true,
|
||||||
// tooltipPadding: const EdgeInsets.all(8),
|
// tooltipPadding: const EdgeInsets.all(8),
|
||||||
@ -1666,8 +1699,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
leftTitles: AxisTitles(
|
leftTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: false,
|
showTitles: false,
|
||||||
interval:
|
interval: (yAxisData.isNotEmpty
|
||||||
(yAxisData.isNotEmpty
|
|
||||||
? yAxisData.reduce(
|
? yAxisData.reduce(
|
||||||
(a, b) => a > b ? a : b,
|
(a, b) => a > b ? a : b,
|
||||||
) /
|
) /
|
||||||
@ -1691,10 +1723,12 @@ class ChartWidget extends StatelessWidget {
|
|||||||
getTitlesWidget: (value, meta) {
|
getTitlesWidget: (value, meta) {
|
||||||
if (value.toInt() < xAxisData.length) {
|
if (value.toInt() < xAxisData.length) {
|
||||||
String title = xAxisData[value.toInt()];
|
String title = xAxisData[value.toInt()];
|
||||||
String displayTitle =
|
String displayTitle = title.length > 10
|
||||||
title.length > 10
|
|
||||||
? title.substring(0, 10) + '...'
|
? title.substring(0, 10) + '...'
|
||||||
: title;
|
: title;
|
||||||
|
print('barChartVALUECHECKTITLE $title');
|
||||||
|
print(
|
||||||
|
'barChartVALUECHECK $displayTitle');
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
@ -1711,9 +1745,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: TooltipTheme(
|
child: TooltipTheme(
|
||||||
data: TooltipThemeData(
|
data: TooltipThemeData(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color: Colors.blueGrey[
|
||||||
Colors
|
800], // Change background color
|
||||||
.blueGrey[800], // Change background color
|
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(
|
BorderRadius.circular(
|
||||||
8,
|
8,
|
||||||
@ -1726,8 +1759,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: TooltipTheme(
|
child: TooltipTheme(
|
||||||
data: TooltipThemeData(
|
data: TooltipThemeData(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color: Colors
|
||||||
Colors
|
|
||||||
.black, // Change background color
|
.black, // Change background color
|
||||||
// color: Colors.blueGrey[800], // Change background color
|
// color: Colors.blueGrey[800], // Change background color
|
||||||
borderRadius:
|
borderRadius:
|
||||||
@ -1844,8 +1876,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If no valid TIME_PERIOD with a month is found, return original response
|
// If no valid TIME_PERIOD with a month is found, return original response
|
||||||
List<Map<String, dynamic>> finalData =
|
List<Map<String, dynamic>> finalData = sortedData.isNotEmpty
|
||||||
sortedData.isNotEmpty
|
|
||||||
? sortedData
|
? sortedData
|
||||||
: List.from(chartData['response']);
|
: List.from(chartData['response']);
|
||||||
|
|
||||||
@ -1926,8 +1957,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
leftTitles: AxisTitles(
|
leftTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: false,
|
showTitles: false,
|
||||||
interval:
|
interval: (yAxisData.isNotEmpty
|
||||||
(yAxisData.isNotEmpty
|
|
||||||
? yAxisData.reduce((a, b) => a > b ? a : b) / 5
|
? yAxisData.reduce((a, b) => a > b ? a : b) / 5
|
||||||
: 1),
|
: 1),
|
||||||
getTitlesWidget: (value, meta) {
|
getTitlesWidget: (value, meta) {
|
||||||
@ -1994,8 +2024,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
barsSpace: 20,
|
barsSpace: 20,
|
||||||
barRods: [
|
barRods: [
|
||||||
BarChartRodData(
|
BarChartRodData(
|
||||||
toY:
|
toY: (yAxisData[index] == 0)
|
||||||
(yAxisData[index] == 0)
|
|
||||||
? 0.0001
|
? 0.0001
|
||||||
: yAxisData[index],
|
: yAxisData[index],
|
||||||
// color: Colors.blueAccent,
|
// color: Colors.blueAccent,
|
||||||
@ -2132,8 +2161,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
), // Dynamically calculate max Y
|
), // Dynamically calculate max Y
|
||||||
// barGroups: _buildHorizontalRotateBarGroups(
|
// barGroups: _buildHorizontalRotateBarGroups(
|
||||||
// chartData, groupByValues), // Build bar groups
|
// chartData, groupByValues), // Build bar groups
|
||||||
barGroups:
|
barGroups: hasBarColors
|
||||||
hasBarColors
|
|
||||||
? _buildHorizontalRotateBarGroupsBarColors(
|
? _buildHorizontalRotateBarGroupsBarColors(
|
||||||
chartData,
|
chartData,
|
||||||
groupByValues,
|
groupByValues,
|
||||||
@ -2159,8 +2187,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
value.toInt(),
|
value.toInt(),
|
||||||
);
|
);
|
||||||
|
|
||||||
String displayTitle =
|
String displayTitle = title.length > 10
|
||||||
title.length > 10
|
|
||||||
? title.substring(0, 10) + '...'
|
? title.substring(0, 10) + '...'
|
||||||
: title;
|
: title;
|
||||||
|
|
||||||
@ -2177,8 +2204,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: TooltipTheme(
|
child: TooltipTheme(
|
||||||
data: TooltipThemeData(
|
data: TooltipThemeData(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color: Colors
|
||||||
Colors
|
|
||||||
.black, // Change background color
|
.black, // Change background color
|
||||||
// color: Colors.blueGrey[800], // Change background color
|
// color: Colors.blueGrey[800], // Change background color
|
||||||
borderRadius:
|
borderRadius:
|
||||||
@ -2273,8 +2299,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex',
|
'Crop is null or index out of bounds for cropType: $cropType and rodIndex: $rodIndex',
|
||||||
);
|
);
|
||||||
// crop = cropType; // Fallback to cropType
|
// crop = cropType; // Fallback to cropType
|
||||||
crop =
|
crop = (crops != null && crops.isNotEmpty)
|
||||||
(crops != null && crops.isNotEmpty)
|
|
||||||
? crops.first
|
? crops.first
|
||||||
: cropType;
|
: cropType;
|
||||||
}
|
}
|
||||||
@ -2331,8 +2356,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
case 'horizontal_rotate':
|
case 'horizontal_rotate':
|
||||||
String cropKey =
|
String cropKey = chartData['chart_type_json']
|
||||||
chartData['chart_type_json']['y_sub_group']; // Dynamically get crop key
|
['y_sub_group']; // Dynamically get crop key
|
||||||
// Group crops by CROP_TYPE
|
// Group crops by CROP_TYPE
|
||||||
Map<String, List<String>> groupedCrops = {};
|
Map<String, List<String>> groupedCrops = {};
|
||||||
|
|
||||||
@ -2551,9 +2576,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
enabled: false, // Enable touch to show tooltip
|
enabled: false, // Enable touch to show tooltip
|
||||||
handleBuiltInTouches: false,
|
handleBuiltInTouches: false,
|
||||||
touchTooltipData: BarTouchTooltipData(
|
touchTooltipData: BarTouchTooltipData(
|
||||||
getTooltipColor:
|
getTooltipColor: (group) => Colors
|
||||||
(group) =>
|
|
||||||
Colors
|
|
||||||
.transparent, // Light background for visibility
|
.transparent, // Light background for visibility
|
||||||
tooltipHorizontalAlignment:
|
tooltipHorizontalAlignment:
|
||||||
FLHorizontalAlignment.center,
|
FLHorizontalAlignment.center,
|
||||||
@ -2574,6 +2597,18 @@ class ChartWidget extends StatelessWidget {
|
|||||||
String crop = groupedCrops[cropType]![rodIndex];
|
String crop = groupedCrops[cropType]![rodIndex];
|
||||||
double value = rod.toY;
|
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
|
// Format values dynamically
|
||||||
// String formattedValue = value >= 1e6
|
// String formattedValue = value >= 1e6
|
||||||
// ? '${(value / 1e6).toStringAsFixed(1)}M'
|
// ? '${(value / 1e6).toStringAsFixed(1)}M'
|
||||||
@ -2593,7 +2628,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
0,
|
0,
|
||||||
); // for values smaller than 1000
|
); // for values smaller than 1000
|
||||||
}
|
}
|
||||||
|
print('formattedValue00 $formattedValue');
|
||||||
return BarTooltipItem(
|
return BarTooltipItem(
|
||||||
formattedValue,
|
formattedValue,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
@ -2690,8 +2725,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
|
|
||||||
// barGroups: _buildHorizontalRotateBarGroups(
|
// barGroups: _buildHorizontalRotateBarGroups(
|
||||||
// chartData, groupByValues),
|
// chartData, groupByValues),
|
||||||
barGroups:
|
barGroups: hasBarColors
|
||||||
hasBarColors
|
|
||||||
? _buildHorizontalRotateBarGroupsBarColors(
|
? _buildHorizontalRotateBarGroupsBarColors(
|
||||||
chartData,
|
chartData,
|
||||||
groupByValues,
|
groupByValues,
|
||||||
@ -2923,8 +2957,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// return FlSpot(xValue, yValue);
|
// return FlSpot(xValue, yValue);
|
||||||
// }).toList();
|
// }).toList();
|
||||||
|
|
||||||
List<FlSpot> spots =
|
List<FlSpot> spots = filteredData
|
||||||
filteredData
|
|
||||||
.where((entry) => entry['ObsKey'][groupByKey] == group)
|
.where((entry) => entry['ObsKey'][groupByKey] == group)
|
||||||
.map<FlSpot>((entry) {
|
.map<FlSpot>((entry) {
|
||||||
String timePeriod = entry['ObsKey']['TIME_PERIOD'];
|
String timePeriod = entry['ObsKey']['TIME_PERIOD'];
|
||||||
@ -2946,8 +2979,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
yValue = value;
|
yValue = value;
|
||||||
} else if (value is String) {
|
} else if (value is String) {
|
||||||
yValue =
|
yValue =
|
||||||
double.tryParse(value) ??
|
double.tryParse(value) ?? 0.0; // Handle invalid strings safely
|
||||||
0.0; // Handle invalid strings safely
|
|
||||||
} else {
|
} else {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Unexpected value type: ${value.runtimeType}",
|
"Unexpected value type: ${value.runtimeType}",
|
||||||
@ -2956,8 +2988,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
print('LineTrendX $xValue');
|
print('LineTrendX $xValue');
|
||||||
print('LineTrendY $yValue');
|
print('LineTrendY $yValue');
|
||||||
return FlSpot(xValue, yValue);
|
return FlSpot(xValue, yValue);
|
||||||
})
|
}).toList()
|
||||||
.toList()
|
|
||||||
..sort((a, b) => a.x.compareTo(b.x));
|
..sort((a, b) => a.x.compareTo(b.x));
|
||||||
|
|
||||||
print('spots - $spots');
|
print('spots - $spots');
|
||||||
@ -3014,8 +3045,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
getTooltipColor: (spot) => Colors.black,
|
getTooltipColor: (spot) => Colors.black,
|
||||||
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
|
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
|
||||||
return lineBarsSpot.map((lineBarSpot) {
|
return lineBarsSpot.map((lineBarSpot) {
|
||||||
Color lineColor =
|
Color lineColor = lineBarSpot.bar is LineChartBarData
|
||||||
lineBarSpot.bar is LineChartBarData
|
|
||||||
? (lineBarSpot.bar).color ?? Colors.white
|
? (lineBarSpot.bar).color ?? Colors.white
|
||||||
: Colors.white; // Extract bar color safely
|
: Colors.white; // Extract bar color safely
|
||||||
return LineTooltipItem(
|
return LineTooltipItem(
|
||||||
@ -3030,8 +3060,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
// text: formatNumber(lineBarSpot.y),
|
// text: formatNumber(lineBarSpot.y),
|
||||||
text:
|
text: (chartConversion != null &&
|
||||||
(chartConversion != null &&
|
|
||||||
chartConversion.isNotEmpty &&
|
chartConversion.isNotEmpty &&
|
||||||
number_format != null)
|
number_format != null)
|
||||||
? formatNumberConversion(
|
? formatNumberConversion(
|
||||||
@ -3128,10 +3157,10 @@ class ChartWidget extends StatelessWidget {
|
|||||||
return FlGridData(
|
return FlGridData(
|
||||||
show: false,
|
show: false,
|
||||||
drawVerticalLine: true,
|
drawVerticalLine: true,
|
||||||
getDrawingHorizontalLine:
|
getDrawingHorizontalLine: (value) =>
|
||||||
(value) => FlLine(color: Colors.grey, strokeWidth: 1),
|
FlLine(color: Colors.grey, strokeWidth: 1),
|
||||||
getDrawingVerticalLine:
|
getDrawingVerticalLine: (value) =>
|
||||||
(value) => FlLine(color: Colors.grey, strokeWidth: 1),
|
FlLine(color: Colors.grey, strokeWidth: 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3568,18 +3597,16 @@ class ChartWidget extends StatelessWidget {
|
|||||||
String groupValue = groupByValues.elementAt(i);
|
String groupValue = groupByValues.elementAt(i);
|
||||||
|
|
||||||
// Filter data for the current group (grouping by CROP_TYPE)
|
// Filter data for the current group (grouping by CROP_TYPE)
|
||||||
List<dynamic> groupData =
|
List<dynamic> groupData = responseData.where((entry) {
|
||||||
responseData.where((entry) {
|
|
||||||
return entry['ObsKey'][groupByKeyValueData] == groupValue;
|
return entry['ObsKey'][groupByKeyValueData] == groupValue;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
// Create BarChartRodData for each bar in the group
|
// Create BarChartRodData for each bar in the group
|
||||||
List<BarChartRodData> barRods =
|
List<BarChartRodData> barRods = groupData.map((data) {
|
||||||
groupData.map((data) {
|
|
||||||
// Ensure to retrieve and parse 'ObsValue' value (which should be a double)
|
// Ensure to retrieve and parse 'ObsValue' value (which should be a double)
|
||||||
double value =
|
double value =
|
||||||
double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0;
|
double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0;
|
||||||
// double minBarHeight = 0.5;
|
double minBarHeight = 0.1;
|
||||||
print('multi_bar1.1');
|
print('multi_bar1.1');
|
||||||
// final List<Color> uniqueColorsForTwo = [
|
// final List<Color> uniqueColorsForTwo = [
|
||||||
// Color(0xFF648CBA),
|
// Color(0xFF648CBA),
|
||||||
@ -3598,13 +3625,11 @@ class ChartWidget extends StatelessWidget {
|
|||||||
chartData['dataset'] == 'hotel_guests' ||
|
chartData['dataset'] == 'hotel_guests' ||
|
||||||
chartData['dataset'] == 'health_services' ||
|
chartData['dataset'] == 'health_services' ||
|
||||||
chartData['dataset'] == 'clinics') {
|
chartData['dataset'] == 'clinics') {
|
||||||
barColor =
|
barColor = uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length];
|
||||||
uniqueColorsForTwo[colorIndex % uniqueColorsForTwo.length];
|
|
||||||
colorIndex++;
|
colorIndex++;
|
||||||
} else if (chartData['dataset'] == 'cropsk') {
|
} else if (chartData['dataset'] == 'cropsk') {
|
||||||
barColor =
|
barColor =
|
||||||
uniqueColorsForThree[colorIndex %
|
uniqueColorsForThree[colorIndex % uniqueColorsForThree.length];
|
||||||
uniqueColorsForThree.length];
|
|
||||||
colorIndex++;
|
colorIndex++;
|
||||||
} else if (chartData['dataset'] == 'oil_and_gas') {
|
} else if (chartData['dataset'] == 'oil_and_gas') {
|
||||||
barColor =
|
barColor =
|
||||||
@ -3616,7 +3641,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return BarChartRodData(
|
return BarChartRodData(
|
||||||
toY: value, // Use the parsed value
|
// toY: value,
|
||||||
|
toY: value == 0 ? minBarHeight : value, // Use the parsed value
|
||||||
color: barColor, // Dynamic color
|
color: barColor, // Dynamic color
|
||||||
width: 20,
|
width: 20,
|
||||||
|
|
||||||
@ -3677,8 +3703,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
String groupValue = groupByValues.elementAt(i);
|
String groupValue = groupByValues.elementAt(i);
|
||||||
|
|
||||||
// Filter data for the current group
|
// Filter data for the current group
|
||||||
List<dynamic> groupData =
|
List<dynamic> groupData = responseData.where((entry) {
|
||||||
responseData.where((entry) {
|
|
||||||
return entry['ObsKey'][groupByKeyValueData1] == groupValue;
|
return entry['ObsKey'][groupByKeyValueData1] == groupValue;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
@ -3698,8 +3723,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create BarChartRodData for each bar in the group
|
// Create BarChartRodData for each bar in the group
|
||||||
List<BarChartRodData> barRods =
|
List<BarChartRodData> barRods = groupData.map((data) {
|
||||||
groupData.map((data) {
|
|
||||||
double value =
|
double value =
|
||||||
double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0;
|
double.tryParse(data['ObsValue']['Value'].toString()) ?? 0.0;
|
||||||
|
|
||||||
@ -3714,9 +3738,8 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// Determine color dynamically
|
// Determine color dynamically
|
||||||
Color barColor;
|
Color barColor;
|
||||||
if (chartData['dataset'] == 'health_services') {
|
if (chartData['dataset'] == 'health_services') {
|
||||||
barColor =
|
barColor = uniqueColorsForTwo[
|
||||||
uniqueColorsForTwo[colorIndex %
|
colorIndex % 2]; // Alternate between two colors
|
||||||
2]; // Alternate between two colors
|
|
||||||
colorIndex++; // Update index for next bar
|
colorIndex++; // Update index for next bar
|
||||||
} else {
|
} else {
|
||||||
// barColor = chartBarColors[gender] ?? Colors.grey; // Default gender-based color
|
// barColor = chartBarColors[gender] ?? Colors.grey; // Default gender-based color
|
||||||
@ -3772,14 +3795,12 @@ Widget _buildChartLegend(
|
|||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
runSpacing: 6,
|
runSpacing: 6,
|
||||||
children:
|
children: uniqueCropTypes.map((cropType) {
|
||||||
uniqueCropTypes.map((cropType) {
|
|
||||||
// Color cropColor = parsedChartBarColors[cropType] ?? Colors.grey; // Fetch color for each crop type
|
// Color cropColor = parsedChartBarColors[cropType] ?? Colors.grey; // Fetch color for each crop type
|
||||||
int index = uniqueCropTypes.toList().indexOf(
|
int index = uniqueCropTypes.toList().indexOf(
|
||||||
cropType,
|
cropType,
|
||||||
); // Get index for cycling colors
|
); // Get index for cycling colors
|
||||||
Color cropColor =
|
Color cropColor = parsedChartBarColors.isNotEmpty &&
|
||||||
parsedChartBarColors.isNotEmpty &&
|
|
||||||
parsedChartBarColors.containsKey(cropType)
|
parsedChartBarColors.containsKey(cropType)
|
||||||
? parsedChartBarColors[cropType]!
|
? parsedChartBarColors[cropType]!
|
||||||
: uniqueColors[index % uniqueColors.length];
|
: uniqueColors[index % uniqueColors.length];
|
||||||
|
|||||||
@ -702,6 +702,8 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
final dontHaveAnAccountRegisterBtn = TextButton(
|
final dontHaveAnAccountRegisterBtn = TextButton(
|
||||||
onPressed: () => {context.push('/register')},
|
onPressed: () => {context.push('/register')},
|
||||||
|
// onPressed: () =>
|
||||||
|
// {context.push('/forgot-password/surendar.m@venbainfotech.com')},
|
||||||
child: Text.rich(
|
child: Text.rich(
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
TextSpan(
|
TextSpan(
|
||||||
|
|||||||
@ -152,7 +152,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(AppLocalizations.of(context)!.status_success),),
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.status_success),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -160,13 +162,16 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
});
|
});
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
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
|
//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');
|
print('user $user');
|
||||||
double myheight = MediaQuery.of(context).size.height;
|
double myheight = MediaQuery.of(context).size.height;
|
||||||
|
|
||||||
@ -416,8 +421,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
// // fit: BoxFit.contain,
|
// // fit: BoxFit.contain,
|
||||||
// ),
|
// ),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
// contentPadding: EdgeInsets.symmetric(
|
||||||
vertical: 9, horizontal: 18.0),
|
// vertical: 9, horizontal: 18.0),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
onChanged: filterUsers,
|
onChanged: filterUsers,
|
||||||
),
|
),
|
||||||
@ -444,7 +450,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
SizedBox(height: 15),
|
SizedBox(height: 15),
|
||||||
// Space between icon and text
|
// Space between icon and text
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.no_result_found,
|
AppLocalizations.of(context)!
|
||||||
|
.no_result_found,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -455,7 +462,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
SizedBox(height: 12), // Space between texts
|
SizedBox(height: 12), // Space between texts
|
||||||
FittedBox(
|
FittedBox(
|
||||||
child: Text(
|
child: Text(
|
||||||
context.translate("We couldn't find anything matching your search.",'لم نعثر على أي شيء يطابق بحثك.'),
|
context.translate(
|
||||||
|
"We couldn't find anything matching your search.",
|
||||||
|
'لم نعثر على أي شيء يطابق بحثك.'),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: Color(0xFF898C81)),
|
color: Color(0xFF898C81)),
|
||||||
@ -533,7 +542,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
(index) => DataCell(
|
(index) => DataCell(
|
||||||
index == 0
|
index == 0
|
||||||
? Text(
|
? Text(
|
||||||
AppLocalizations.of(context)!.no_result_found,
|
AppLocalizations.of(
|
||||||
|
context)!
|
||||||
|
.no_result_found,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontStyle: FontStyle
|
fontStyle: FontStyle
|
||||||
.italic),
|
.italic),
|
||||||
@ -573,7 +584,11 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
print(user);
|
print(user);
|
||||||
if (newStatus != null) {
|
if (newStatus != null) {
|
||||||
_showConfirmationDialog(
|
_showConfirmationDialog(
|
||||||
user, newStatus, statusOptions[newStatus]!,);
|
user,
|
||||||
|
newStatus,
|
||||||
|
statusOptions[
|
||||||
|
newStatus]!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -989,7 +989,9 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.mail_outlined),
|
leading: Icon(Icons.mail_outlined),
|
||||||
title: Text(context.translate('Contact Us', 'اتصل بنا'),),
|
title: Text(
|
||||||
|
context.translate('Contact Us', 'اتصل بنا'),
|
||||||
|
),
|
||||||
onTap: () => context.push('/contact'),
|
onTap: () => context.push('/contact'),
|
||||||
),
|
),
|
||||||
if (userId != 'guest')
|
if (userId != 'guest')
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
name: uae_stat
|
name: uae_stat
|
||||||
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
|
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
version: 1.0.42+43
|
version: 1.0.43+44
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.2.3 <4.0.0"
|
sdk: ">=3.2.3 <4.0.0"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user