This commit is contained in:
venbaittech 2025-01-22 18:36:50 +05:30
parent 1b03125858
commit 6b5a4b96ae
5 changed files with 744 additions and 571 deletions

View File

@ -1035,49 +1035,47 @@
// //
// [ // [
// { // {
// chart_heading :"Guest Nights by Region" // chart_heading :"Population Growth Over Time"
// chart_type :"fl_stacked_bar" // chart_type :"line_trend"
// dataset :"hotels" // dataset :"population"
// group_by :"GUEST_REGION" // group_by :"GENDER"
// is_chart :"true" // is_chart :"true"
// kpi :"hotel_occupancy_rate_chart_1" // kpi :"population"
// main_id :"economy" // main_id :"social"
// response:[ // response:[
// { // {
// "ObsKey": { // "ObsKey": {
// "FREQ": "A", // "FREQ": "A",
// "GUEST_REGION": "AF", // "GENDER": "M",
// "H_INDICATOR": "GUN", // "MEASURE": "POP",
// "H_TYPE": "_Z", // "POP_IND": "_Z",
// "MEASURE": "H",
// "REF_AREA": "AE", // "REF_AREA": "AE",
// "SOURCE_DETAIL": "FCSC", // "SOURCE_DETAIL": "FCSC",
// "TIME_PERIOD": "2016", // "TIME_PERIOD": "1970",
// "UNIT_MEASURE": "NUMBER" // "UNIT_MEASURE": "PS"
// }, // },
// "ObsValue": { // "ObsValue": {
// "Value": "2659446" // "Value": "149195"
// }
// } // }
// },
// { // {
// "ObsKey": { // "ObsKey": {
// "FREQ": "A", // "FREQ": "A",
// "GUEST_REGION": "OC", // "GENDER": "F",
// "H_INDICATOR": "GUN", // "MEASURE": "POP",
// "H_TYPE": "_Z", // "POP_IND": "_Z",
// "MEASURE": "H",
// "REF_AREA": "AE", // "REF_AREA": "AE",
// "SOURCE_DETAIL": "FCSC", // "SOURCE_DETAIL": "FCSC",
// "TIME_PERIOD": "2018", // "TIME_PERIOD": "1995",
// "UNIT_MEASURE": "NUMBER" // "UNIT_MEASURE": "PS"
// }, // },
// "ObsValue": { // "ObsValue": {
// "Value": "1127282" // "Value": "850654"
// } // }
// } // }
// //
// ] // ]
// sub_id :"tourism" // sub_id :"population"
// url :"https://releaseeuaestat.fcsc.gov.ae/rest/data/FCSA,DF_GUEST_REGION,4.3.0/...A..GUN.OTH+OC+AF+EC+AM+AC+ASC+GCC+UAE.?startPeriod=2016&dimensionAtObservation=AllDimensions" // url :"https://releaseeuaestat.fcsc.gov.ae/rest/data/FCSA,DF_POP,2.7.0/....A..?startPeriod=1970&dimensionAtObservation=AllDimensions"
// } // }
// ] // ]

View File

@ -108,7 +108,7 @@ class ChartWidget extends StatelessWidget {
}).toSet(); }).toSet();
} }
Widget buildChart(dynamic chartData) { Widget buildChart(dynamic chartData, BuildContext context) {
print('chartDataccccccc $chartData'); print('chartDataccccccc $chartData');
// Extract group_by dynamically from the chartData // Extract group_by dynamically from the chartData
if (chartData == null || chartData['response'] == null) { if (chartData == null || chartData['response'] == null) {
@ -379,7 +379,7 @@ class ChartWidget extends StatelessWidget {
), ),
gridData: FlGridData(show: false), gridData: FlGridData(show: false),
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),
barGroups: _generateBarGroups(chartData, groupByKey), barGroups: _generateBarGroups(context, chartData, groupByKey),
), ),
), ),
), ),
@ -432,6 +432,17 @@ class ChartWidget extends StatelessWidget {
) )
], ],
); );
case 'line_trend':
case 'line_trend':
return LineChart(LineChartData(
lineTouchData: lineTouchData1(),
gridData: gridData(),
titlesData: titlesData1(),
borderData: borderData(),
lineBarsData: lineBarsData(chartData),
minX: 1970, // Adjust based on your data range
maxX: 2025, // Adjust based on your data range
));
case 'fl_multi_bar': case 'fl_multi_bar':
return BarChart( return BarChart(
BarChartData( BarChartData(
@ -477,6 +488,116 @@ class ChartWidget extends StatelessWidget {
} }
} }
// Function to create LineChartBarData for Males and Females
List<LineChartBarData> lineBarsData(dynamic chartData) {
List<LineChartBarData> lineBars = [];
// Filter data for males and females
List<Map<String, dynamic>> maleData = [];
List<Map<String, dynamic>> femaleData = [];
// Separate the data based on gender
for (var entry in chartData['response']) {
if (entry['ObsKey']['GENDER'] == 'M') {
maleData.add(entry);
} else if (entry['ObsKey']['GENDER'] == 'F') {
femaleData.add(entry);
}
}
// Prepare data for Male
List<FlSpot> maleSpots = maleData.map<FlSpot>((entry) {
double xValue = double.parse(entry['ObsKey']['TIME_PERIOD']);
double yValue = double.parse(entry['ObsValue']['Value']);
return FlSpot(xValue, yValue);
}).toList();
// Prepare data for Female
List<FlSpot> femaleSpots = femaleData.map<FlSpot>((entry) {
double xValue = double.parse(entry['ObsKey']['TIME_PERIOD']);
double yValue = double.parse(entry['ObsValue']['Value']);
return FlSpot(xValue, yValue);
}).toList();
// Add the Male line (Blue color)
lineBars.add(
LineChartBarData(
spots: maleSpots,
isCurved: true,
color: Colors.blue,
barWidth: 3,
belowBarData: BarAreaData(show: false),
),
);
// Add the Female line (Pink color)
lineBars.add(
LineChartBarData(
spots: femaleSpots,
isCurved: true,
color: Colors.pink,
barWidth: 3,
belowBarData: BarAreaData(show: false),
),
);
return lineBars;
}
// Sample implementation for other chart details like titles, grid, etc.
LineTouchData lineTouchData1() {
return LineTouchData(
touchTooltipData: LineTouchTooltipData(
// tooltipBgColor: Colors.blueAccent,
),
// touchCallback: (LineTouchResponse touchResponse) {},
handleBuiltInTouches: true,
);
}
FlGridData gridData() {
return FlGridData(
show: true,
drawVerticalLine: true,
getDrawingHorizontalLine: (value) =>
FlLine(color: Colors.grey, strokeWidth: 1),
getDrawingVerticalLine: (value) =>
FlLine(color: Colors.grey, strokeWidth: 1),
);
}
FlTitlesData titlesData1() {
return FlTitlesData(
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
return Text(
value.toInt().toString(),
style: TextStyle(color: Colors.black, fontSize: 12),
);
},
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
return Text(
value.toInt().toString(),
style: TextStyle(color: Colors.black, fontSize: 12),
);
},
),
),
);
}
FlBorderData borderData() {
return FlBorderData(
show: true, border: Border.all(color: Colors.black, width: 1));
}
// Define the list of unique colors // Define the list of unique colors
final List<Color> uniqueColors = [ final List<Color> uniqueColors = [
Color(0xFF648CBA), Color(0xFF648CBA),
@ -493,7 +614,7 @@ class ChartWidget extends StatelessWidget {
} }
List<BarChartGroupData> _generateBarGroups( List<BarChartGroupData> _generateBarGroups(
dynamic chartData, String groupByKey) { BuildContext context, dynamic chartData, String groupByKey) {
Map<String, Map<String, double>> groupedData = {}; Map<String, Map<String, double>> groupedData = {};
// Group data by `group_by` and `TIME_PERIOD`, accumulating the values for each group and year // Group data by `group_by` and `TIME_PERIOD`, accumulating the values for each group and year
@ -521,6 +642,8 @@ class ChartWidget extends StatelessWidget {
List<String> timePeriods = groupedData.values.first.keys.toList(); List<String> timePeriods = groupedData.values.first.keys.toList();
print('timePeriods $timePeriods'); print('timePeriods $timePeriods');
double barWidth = calculateBarWidth(context, timePeriods.length);
// For each time period, generate a BarChartGroupData // For each time period, generate a BarChartGroupData
for (int i = 0; i < timePeriods.length; i++) { for (int i = 0; i < timePeriods.length; i++) {
// Intermediate variable to track the current toY value as we stack bars // Intermediate variable to track the current toY value as we stack bars
@ -555,7 +678,8 @@ class ChartWidget extends StatelessWidget {
BarChartRodData( BarChartRodData(
toY: currentToY, // Use the accumulated `currentToY` value toY: currentToY, // Use the accumulated `currentToY` value
rodStackItems: rodStackItems, // Add the stacked items rodStackItems: rodStackItems, // Add the stacked items
width: 20, // width: 20,
width: barWidth,
borderRadius: BorderRadius.zero, borderRadius: BorderRadius.zero,
color: Colors color: Colors
.transparent, // This will act as a container for stacked items .transparent, // This will act as a container for stacked items
@ -644,10 +768,36 @@ class ChartWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return buildChart(chartData); return buildChart(chartData, context);
} }
} }
double calculateBarWidth(BuildContext context, int totalBars) {
double width = MediaQuery.of(context).size.width; // Chart width
double padding = 16.0; // Space between bars
double availableWidth = (width - 100);
if (totalBars <= 0) {
throw ArgumentError("TotalBars must be greater than 0");
}
double barWidth = (availableWidth - (padding * (totalBars - 1))) / totalBars;
print('barWidth - $barWidth');
// Ensure bar width does not exceed availableWidth
if (barWidth > availableWidth) {
barWidth = availableWidth;
}
// Optional: Add a minimum width constraint if needed
double minWidth = 10.0; // Example minimum width
if (barWidth < minWidth) {
barWidth = minWidth;
}
return barWidth;
}
class ChartData { class ChartData {
final String? x; final String? x;
final double y; final double y;

View File

@ -213,7 +213,7 @@ class _FeedbackFormState extends State<FeedbackForm>
title: Text(AppLocalizations.of(context)!.feedback_title), title: Text(AppLocalizations.of(context)!.feedback_title),
// appBar: AppBar( // appBar: AppBar(
// backgroundColor: const Color(0xFFf8f9ff), // backgroundColor: const Color(0xFFf8f9ff),
// title: Text(context.translate('Feedback Form', 'نموذج الملاحظات')), // title: Text(AppLocalizations.of(context)!.feedback_title),
// actions: [ // actions: [
// Align( // Align(
// alignment: AlignmentDirectional.topEnd, // alignment: AlignmentDirectional.topEnd,

View File

@ -1,5 +1,7 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -7,19 +9,12 @@ import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
import '../../components/my_toggle.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart';
class BaseScaffold extends ConsumerStatefulWidget {
final Widget body;
final Widget title;
final bool? showBackButton;
final bool? mycenterTitle;
final List<Widget>? actions;
final Color? appbarColor, mytitleColor;
class BaseScaffold extends ConsumerStatefulWidget {
const BaseScaffold({ const BaseScaffold({
Key? key, super.key,
required this.body, required this.body,
required this.title, required this.title,
this.actions, this.actions,
@ -27,7 +22,13 @@ class BaseScaffold extends ConsumerStatefulWidget {
this.mycenterTitle = false, this.mycenterTitle = false,
this.appbarColor, this.appbarColor,
this.mytitleColor, this.mytitleColor,
}) : super(key: key); });
final Widget body;
final Widget title;
final bool? showBackButton;
final bool? mycenterTitle;
final List<Widget>? actions;
final Color? appbarColor, mytitleColor;
@override @override
_BaseScaffoldState createState() => _BaseScaffoldState(); _BaseScaffoldState createState() => _BaseScaffoldState();
@ -48,6 +49,7 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
String? collectionIds; String? collectionIds;
String? collectionId; String? collectionId;
bool isLoggedOut = false;
@override @override
void initState() { void initState() {
@ -55,7 +57,6 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
_checkUserId(); _checkUserId();
} }
// Method to retrieve userId from SharedPreferences
Future<String?> getUserId() async { Future<String?> getUserId() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
return prefs.getString('userId'); // Retrieve the userId return prefs.getString('userId'); // Retrieve the userId
@ -69,125 +70,39 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
userId = fetchedUserId; userId = fetchedUserId;
}); });
//print('NAVUser ID: $userId'); //print('NAVUser ID: $userId');
_initializeUserData(); _fetchUserData();
} else { } else {
print('No userId found'); print('No userId found');
// Handle the case where userId is not available // Handle the case where userId is not available
} }
} }
// Future<void> _fetchUserData() async {
// try {
// final adminAuth = await _pb.admins
// .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
// final adminToken = adminAuth.token;
// //print('adminToken- ${adminToken}');
// final userDetailsResponse = await _pb.collection('users').getOne(
// userId!,
// headers: {
// 'Authorization': 'Bearer $adminToken',
// },
// );
// print('NAVuserDetails: $userDetailsResponse');
//
// setState(() {
// userName = userDetailsResponse.data['uname'] ?? '';
// userEmail = userDetailsResponse.data['email'] ?? '';
// userAvatar = userDetailsResponse.data['avatar'] ?? '';
// role = userDetailsResponse.data['role'] ?? '';
// String recordId = userId;
// String collectionId =
// userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_';
//
// if (userAvatar!.isNotEmpty && recordId.isNotEmpty) {
// _avatarUrl =
// 'https://pb.venbait.in/api/files/$collectionId/$recordId/$userAvatar';
// } else {
// _avatarUrl = ''; // Reset to default or empty
// }
// });
// } catch (e) {
// print('Error fetching user details: $e');
// }
// }
Future<void> _initializeUserData() async {
print("Laoding 1");
final prefs = await SharedPreferences.getInstance();
// final userDataString = prefs.getString('userData');
if (prefs.containsKey('userData')) {
// print("Loading user data from local storage: $userData");
final String? userDataString = prefs.getString('userData');
if (userDataString != null) {
// Decode the JSON string into a Map
final Map<String, dynamic> userData = jsonDecode(userDataString);
// Access the userName field
setState(() {
userName = userData['userNames'];
userEmail = userData['userEmails'];
userAvatar = userData['userAvatars'];
role = userData['roles'];
String recordId = userId;
String collectionId = userData['collectionIds'];
if (userAvatar!.isNotEmpty && recordId.isNotEmpty) {
_avatarUrl =
'https://pb.venbait.in/api/files/$collectionId/$recordId/$userAvatar';
} else {
_avatarUrl = ''; // Reset to default or empty
}
});
} else {
print("No user data found in local storage.");
}
} else {
// Fetch data from server and save it to local storage
await _fetchUserData();
}
}
Future<void> _fetchUserData() async { Future<void> _fetchUserData() async {
try { try {
// print("Fetching _fetchUserData");
final adminAuth = await _pb.admins final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token; final adminToken = adminAuth.token;
//print('adminToken- ${adminToken}');
final userDetailsResponse = await _pb.collection('users').getOne( final userDetailsResponse = await _pb.collection('users').getOne(
userId!, userId!,
headers: { headers: {
'Authorization': 'Bearer $adminToken', 'Authorization': 'Bearer $adminToken',
}, },
); );
// print('User details fetched from server: $userDetailsResponse'); print('NAVuserDetails: $userDetailsResponse');
final userData = {
'userNames': userDetailsResponse.data['uname'] ?? '',
'userEmails': userDetailsResponse.data['email'] ?? '',
'userAvatars': userDetailsResponse.data['avatar'] ?? '',
'roles': userDetailsResponse.data['role'] ?? '',
'collectionIds':
userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_',
};
final prefs = await SharedPreferences.getInstance();
await prefs.setString('userData', jsonEncode(userData));
setState(() { setState(() {
userNames = userData['userNames']; userName = userDetailsResponse.data['uname'] ?? '';
userEmails = userData['userEmails']; userEmail = userDetailsResponse.data['email'] ?? '';
userAvatars = userData['userAvatars']; userAvatar = userDetailsResponse.data['avatar'] ?? '';
roles = userData['roles']; role = userDetailsResponse.data['role'] ?? '';
String recordId = userId; String recordId = userId;
collectionIds = userData['collectionIds']; String collectionId =
userDetailsResponse.data['collectionId'] ?? '_pb_users_auth_';
if (userAvatars!.isNotEmpty && recordId.isNotEmpty) { if (userAvatar!.isNotEmpty && recordId.isNotEmpty) {
_avatarUrl = _avatarUrl =
'https://pb.venbait.in/api/files/$collectionIds/$recordId/$userAvatars'; 'https://pb.venbait.in/api/files/$collectionId/$recordId/$userAvatar';
} else { } else {
_avatarUrl = ''; // Reset to default or empty _avatarUrl = ''; // Reset to default or empty
} }
@ -199,6 +114,9 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
Future<void> logout() async { Future<void> logout() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
// setState(() {
// isLoggedOut = true;
// });
prefs.clear(); prefs.clear();
context.go('/'); context.go('/');
} }
@ -221,14 +139,16 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
// onPressed: () {}, // onPressed: () {},
// icon: const Icon(Icons.toggle_off_outlined), // icon: const Icon(Icons.toggle_off_outlined),
// ), // ),
MyToggle(isOn: locale?.languageCode == 'en', MyToggle(
isOn: locale?.languageCode == 'en',
knobTextWhenOn: 'ع', knobTextWhenOn: 'ع',
knobTextWhenOff: 'EN', knobTextWhenOff: 'EN',
pathColorWhenOn: Colors.grey.shade300, pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: (){ onTap: () {
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
},), },
),
], ],
leading: Stack( leading: Stack(
children: [ children: [
@ -272,9 +192,11 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
Row( Row(
children: [ children: [
SizedBox( SizedBox(
width: mywidth / 8, width: mywidth / 8,
child: Image( child: Image(
image: AssetImage('assets/logos/fcsc.png'))), image: AssetImage('assets/logos/fcsc.png'),
),
),
], ],
), ),
Divider(), Divider(),
@ -295,7 +217,8 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
) )
: Image( : Image(
image: AssetImage( image: AssetImage(
'assets/edit_profile/profile.png'), 'assets/edit_profile/profile.png',
),
fit: BoxFit.cover, fit: BoxFit.cover,
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
@ -317,10 +240,10 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
), ),
], ],
) ),
], ],
), ),
) ),
], ],
), ),
), ),
@ -332,8 +255,10 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
if (role == 'admin') if (role == 'admin')
ListTile( ListTile(
leading: Icon(Icons.manage_accounts), leading: Icon(Icons.manage_accounts),
// title: Text('Manage User'), title: Text('Manage User'),
title: Text(AppLocalizations.of(context)!.manage_user,), // title: Text(
// AppLocalizations.of(context)!.manage_user,
// ),
onTap: () => context.go('/manageuser'), onTap: () => context.go('/manageuser'),
), ),
ListTile( ListTile(