charts added
This commit is contained in:
parent
1bde1c624a
commit
066235889b
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
|
<configuration default="false" name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
|
||||||
<option name="filePath" value="$PROJECT_DIR$/lib/main.dart" />
|
<option name="filePath" value="$PROJECT_DIR$/frontend/lib/main.dart" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
@ -295,6 +295,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart';
|
import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart';
|
||||||
|
import 'package:uae_stat/presentation/Screens/demo_home2.dart';
|
||||||
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
|
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
|
||||||
|
|
||||||
import '../domain/use_cases/preferences_use_case.dart';
|
import '../domain/use_cases/preferences_use_case.dart';
|
||||||
@ -302,6 +303,7 @@ import '../presentation/Screens/auth_verification/changepassword.dart';
|
|||||||
import '../presentation/Screens/auth_verification/confirm_password.dart';
|
import '../presentation/Screens/auth_verification/confirm_password.dart';
|
||||||
import '../presentation/Screens/auth_verification/create_new_pw.dart';
|
import '../presentation/Screens/auth_verification/create_new_pw.dart';
|
||||||
import '../presentation/Screens/auth_verification/otp_verification.dart';
|
import '../presentation/Screens/auth_verification/otp_verification.dart';
|
||||||
|
import '../presentation/Screens/charts/chart.dart';
|
||||||
import '../presentation/Screens/demo_home.dart';
|
import '../presentation/Screens/demo_home.dart';
|
||||||
import '../presentation/Screens/profilepage.dart';
|
import '../presentation/Screens/profilepage.dart';
|
||||||
import '../presentation/routes/auth_routes/login_route.dart';
|
import '../presentation/routes/auth_routes/login_route.dart';
|
||||||
@ -313,13 +315,12 @@ final GoRouter router = GoRouter(
|
|||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/',
|
path: '/',
|
||||||
builder: (context, state) => LoginRoute(),
|
builder: (context, state) => LoginRoute(),
|
||||||
//builder: (context, state) => MyHomePage(),
|
//builder: (context, state) => MyHomePage(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/login',
|
path: '/login',
|
||||||
builder: (context, state) => LoginRoute(),
|
builder: (context, state) => LoginRoute(),
|
||||||
|
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/myhomepage',
|
path: '/myhomepage',
|
||||||
@ -330,8 +331,20 @@ builder: (context, state) => LoginRoute(),
|
|||||||
builder: (context, state) => RegisterScreen(),
|
builder: (context, state) => RegisterScreen(),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/DemoHome',
|
path: '/DemoHome/:dataSets',
|
||||||
builder: (context, state) => ChartPage(),
|
builder: (context, state) {
|
||||||
|
final dataSets = state.pathParameters['dataSets']!;
|
||||||
|
print('Router $dataSets');
|
||||||
|
return ChartPage(dataSets: dataSets);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/Chart/:dataSets',
|
||||||
|
builder: (context, state) {
|
||||||
|
final dataSets = state.pathParameters['dataSets']!;
|
||||||
|
print('Router $dataSets');
|
||||||
|
return ChartScreen(dataSets: dataSets);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/mailverification',
|
path: '/mailverification',
|
||||||
@ -390,4 +403,3 @@ builder: (context, state) => LoginRoute(),
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
1225
lib/presentation/Screens/charts/chart.dart
Normal file
1225
lib/presentation/Screens/charts/chart.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,15 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
home: ChartPage(),
|
home: ChartPage(dataSets: ''),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChartPage extends StatefulWidget {
|
class ChartPage extends StatefulWidget {
|
||||||
|
final String dataSets;
|
||||||
|
const ChartPage({Key? key, required this.dataSets});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ChartPageState createState() => ChartPageState();
|
ChartPageState createState() => ChartPageState();
|
||||||
}
|
}
|
||||||
@ -30,13 +33,13 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
fetchChartData();
|
fetchChartData(widget.dataSets);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchChartData() async {
|
Future<void> fetchChartData(datasets) async {
|
||||||
const baseUrl =
|
const baseUrl =
|
||||||
'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL
|
'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL
|
||||||
final url = Uri.parse('$baseUrl?dataset=hotels');
|
final url = Uri.parse('$baseUrl?dataset=$datasets');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await http.get(url);
|
final response = await http.get(url);
|
||||||
@ -57,24 +60,34 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ChartData> parseLineChartData(List<dynamic> response) {
|
List<ChartData> parseLineChartData(List<dynamic> response) {
|
||||||
return response.map((entry) {
|
// Group by timePeriod (year) and sum the values
|
||||||
// Attempt to fetch the TIMEPERIOD
|
Map<String, double> groupedData = {};
|
||||||
final rawTimePeriod =
|
|
||||||
entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD'];
|
|
||||||
final formattedTimePeriod = rawTimePeriod != null
|
|
||||||
? rawTimePeriod.toString() // Use as-is if valid
|
|
||||||
: 'Unknown'; // Fallback value if null
|
|
||||||
|
|
||||||
// Parse the value or fallback to 0.0
|
response.forEach((entry) {
|
||||||
|
final year = entry['ObsKey']['TIME_PERIOD']?.toString() ?? 'Unknown';
|
||||||
final value =
|
final value =
|
||||||
double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ??
|
double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ??
|
||||||
0.0;
|
0.0;
|
||||||
|
|
||||||
return ChartData(
|
// Add the value to the existing year (if exists) or initialize it
|
||||||
timePeriod: formattedTimePeriod,
|
if (groupedData.containsKey(year)) {
|
||||||
value: value,
|
groupedData[year] = groupedData[year]! + value;
|
||||||
);
|
} else {
|
||||||
}).toList();
|
groupedData[year] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort the grouped data by year in ascending order
|
||||||
|
var sortedEntries = groupedData.entries.toList()
|
||||||
|
..sort((a, b) => int.parse(a.key).compareTo(int.parse(b.key)));
|
||||||
|
|
||||||
|
// Convert the sorted data to a list of ChartData
|
||||||
|
return sortedEntries
|
||||||
|
.map((entry) => ChartData(
|
||||||
|
timePeriod: entry.key,
|
||||||
|
value: entry.value,
|
||||||
|
value1: 0.0)) // Add value1 as 0.0
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ChartData> parseBarChartData(List<dynamic> response) {
|
List<ChartData> parseBarChartData(List<dynamic> response) {
|
||||||
@ -82,63 +95,127 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
.asMap()
|
.asMap()
|
||||||
.entries
|
.entries
|
||||||
.map((entry) => ChartData(
|
.map((entry) => ChartData(
|
||||||
timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ??
|
timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? 'Unknown',
|
||||||
'Unknown', // Fallback to 'Unknown' if null
|
|
||||||
value: double.tryParse(
|
value: double.tryParse(
|
||||||
entry.value['ObsValue']['Value'].toString()) ??
|
entry.value['ObsValue']['Value'].toString()) ??
|
||||||
0.0, // Handle null/invalid value
|
0.0,
|
||||||
|
value1: 0.0, // Ensure value1 is passed as well
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ChartData> parseColumnChartData(List<dynamic> response) {
|
||||||
|
List<ChartData> chartDataList = [];
|
||||||
|
|
||||||
|
// Temporary map to store values by TIME_PERIOD
|
||||||
|
Map<String, ChartData> timePeriodMap = {};
|
||||||
|
|
||||||
|
for (var entry in response) {
|
||||||
|
String timePeriod = entry['ObsKey']['TIME_PERIOD'].toString();
|
||||||
|
double value =
|
||||||
|
double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ??
|
||||||
|
0.0;
|
||||||
|
String indicator = entry['ObsKey']['H_INDICATOR'];
|
||||||
|
|
||||||
|
// If the entry is for TOR, map it to 'value'
|
||||||
|
if (indicator == 'TOR') {
|
||||||
|
if (timePeriodMap.containsKey(timePeriod)) {
|
||||||
|
// Update the value by creating a new ChartData object
|
||||||
|
timePeriodMap[timePeriod] = ChartData(
|
||||||
|
timePeriod: timePeriod,
|
||||||
|
value: value, // Set the new value
|
||||||
|
value1: timePeriodMap[timePeriod]?.value1 ?? 0.0,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
timePeriodMap[timePeriod] = ChartData(
|
||||||
|
timePeriod: timePeriod,
|
||||||
|
value: value,
|
||||||
|
value1: 0.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the entry is for TAR, map it to 'value1'
|
||||||
|
if (indicator == 'TAR') {
|
||||||
|
if (timePeriodMap.containsKey(timePeriod)) {
|
||||||
|
// Create a new ChartData object with the updated value1
|
||||||
|
timePeriodMap[timePeriod] = ChartData(
|
||||||
|
timePeriod: timePeriod,
|
||||||
|
value: timePeriodMap[timePeriod]?.value ??
|
||||||
|
0.0, // Retain the current value
|
||||||
|
value1: value, // Update the value1
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
timePeriodMap[timePeriod] = ChartData(
|
||||||
|
timePeriod: timePeriod,
|
||||||
|
value: 0.0,
|
||||||
|
value1: value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the map to a list
|
||||||
|
chartDataList = timePeriodMap.values.toList();
|
||||||
|
|
||||||
|
return chartDataList;
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildChart(dynamic chartData) {
|
Widget buildChart(dynamic chartData) {
|
||||||
print('chartData $chartData');
|
print('chartData $chartData');
|
||||||
switch (chartData['chart_type']) {
|
switch (chartData['chart_type']) {
|
||||||
case 'line':
|
case 'area':
|
||||||
return SfCartesianChart(
|
return SfCartesianChart(
|
||||||
primaryXAxis: CategoryAxis(
|
primaryXAxis: CategoryAxis(
|
||||||
title: AxisTitle(text: 'Year'),
|
title: AxisTitle(text: 'Year'),
|
||||||
labelRotation: 45, // Rotate labels if they overlap
|
labelRotation: 45, // Rotate labels if they overlap
|
||||||
),
|
|
||||||
title: ChartTitle(text: 'Hotel Estabhlishments'),
|
|
||||||
legend: Legend(isVisible: true),
|
|
||||||
tooltipBehavior: TooltipBehavior(
|
|
||||||
enable: true,
|
|
||||||
builder: (dynamic data, dynamic point, dynamic series,
|
|
||||||
int pointIndex, int seriesIndex) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'${data.timePeriod}: ${formatNumber(data.value)}',
|
|
||||||
style: const TextStyle(color: Colors.black),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
series: <CartesianSeries<ChartData, String>>[
|
|
||||||
LineSeries<ChartData, String>(
|
|
||||||
dataSource: parseLineChartData(chartData['response']),
|
|
||||||
xValueMapper: (ChartData data, _) => data.timePeriod,
|
|
||||||
yValueMapper: (ChartData data, _) => data.value,
|
|
||||||
name: chartData['dataset'],
|
|
||||||
color: Colors.red,
|
|
||||||
dataLabelSettings: DataLabelSettings(
|
|
||||||
isVisible: true,
|
|
||||||
builder: (dynamic data, dynamic point, dynamic series,
|
|
||||||
int pointIndex, int seriesIndex) {
|
|
||||||
return Text(
|
|
||||||
formatNumber(data.value),
|
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.black),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
title: ChartTitle(text: 'Hotel Estabhlishments'),
|
||||||
);
|
legend: Legend(isVisible: true),
|
||||||
|
tooltipBehavior: TooltipBehavior(
|
||||||
|
enable: true,
|
||||||
|
builder: (dynamic data, dynamic point, dynamic series,
|
||||||
|
int pointIndex, int seriesIndex) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'${data.timePeriod}: ${formatNumber(data.value)}',
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
series: <CartesianSeries>[
|
||||||
|
// AreaSeries for the area chart
|
||||||
|
AreaSeries<ChartData, String>(
|
||||||
|
dataSource: parseLineChartData(
|
||||||
|
chartData['response']), // your chart data
|
||||||
|
color: Color(0xFF7DAFBC), // Area color
|
||||||
|
borderDrawMode: BorderDrawMode
|
||||||
|
.excludeBottom, // Optional, adjust border settings
|
||||||
|
borderColor: Colors.green, // Border color
|
||||||
|
borderWidth: 2, // Border width
|
||||||
|
xValueMapper: (ChartData data, _) =>
|
||||||
|
data.timePeriod, // Map x to DateTime
|
||||||
|
yValueMapper: (ChartData data, _) => data.value,
|
||||||
|
// name: chartData['dataset'],
|
||||||
|
name: 'Hotels',
|
||||||
|
dataLabelSettings: DataLabelSettings(
|
||||||
|
isVisible: true,
|
||||||
|
builder: (dynamic data, dynamic point, dynamic series,
|
||||||
|
int pointIndex, int seriesIndex) {
|
||||||
|
return Text(
|
||||||
|
formatNumber(data.value),
|
||||||
|
style: const TextStyle(fontSize: 12, color: Colors.black),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
), // Map y to numerical value
|
||||||
|
)
|
||||||
|
]);
|
||||||
case 'bar':
|
case 'bar':
|
||||||
return SfCartesianChart(
|
return SfCartesianChart(
|
||||||
primaryXAxis: CategoryAxis(),
|
primaryXAxis: CategoryAxis(),
|
||||||
@ -166,7 +243,7 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
xValueMapper: (ChartData data, _) => data.timePeriod,
|
xValueMapper: (ChartData data, _) => data.timePeriod,
|
||||||
yValueMapper: (ChartData data, _) => data.value,
|
yValueMapper: (ChartData data, _) => data.value,
|
||||||
name: chartData['dataset'],
|
name: chartData['dataset'],
|
||||||
color: Colors.red,
|
color: Color(0xFF7DAFBC),
|
||||||
dataLabelSettings: DataLabelSettings(
|
dataLabelSettings: DataLabelSettings(
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
builder: (dynamic data, dynamic point, dynamic series,
|
builder: (dynamic data, dynamic point, dynamic series,
|
||||||
@ -182,6 +259,41 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
case 'column':
|
||||||
|
return SfCartesianChart(
|
||||||
|
primaryXAxis: CategoryAxis(
|
||||||
|
title: AxisTitle(text: 'Year'),
|
||||||
|
labelRotation: 45, // Rotate labels if they overlap
|
||||||
|
),
|
||||||
|
primaryYAxis: NumericAxis(
|
||||||
|
title: AxisTitle(text: 'No of rooms'),
|
||||||
|
),
|
||||||
|
legend: Legend(isVisible: true),
|
||||||
|
title: ChartTitle(text: 'Hotel Occupancy Rate'),
|
||||||
|
enableSideBySideSeriesPlacement: true,
|
||||||
|
tooltipBehavior: TooltipBehavior(enable: true),
|
||||||
|
series: <CartesianSeries<ChartData, int>>[
|
||||||
|
// First Series (value)
|
||||||
|
|
||||||
|
ColumnSeries<ChartData, int>(
|
||||||
|
name: 'Available Rooms',
|
||||||
|
// opacity: 0.9,
|
||||||
|
// width: 0.4,
|
||||||
|
color: Color(0xFF587BA3),
|
||||||
|
dataSource: parseColumnChartData(chartData['response']),
|
||||||
|
xValueMapper: (ChartData data, _) => int.parse(data.timePeriod),
|
||||||
|
yValueMapper: (ChartData data, _) => data.value1,
|
||||||
|
),
|
||||||
|
// Second Series (value1)
|
||||||
|
ColumnSeries<ChartData, int>(
|
||||||
|
color: Color(0xFF90B0D5),
|
||||||
|
name: 'Occupied Rooms',
|
||||||
|
dataSource: parseColumnChartData(chartData['response']),
|
||||||
|
xValueMapper: (ChartData data, _) => int.parse(data.timePeriod),
|
||||||
|
yValueMapper: (ChartData data, _) => data.value,
|
||||||
|
),
|
||||||
|
], // Numeric Y-axis to plot the values
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return Center(child: Text('Unknown chart type'));
|
return Center(child: Text('Unknown chart type'));
|
||||||
}
|
}
|
||||||
@ -192,46 +304,84 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFF7DAFBC),
|
backgroundColor: const Color(0xFF7DAFBC),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Color(0xFF7DAFBC),
|
backgroundColor: const Color(0xFF7DAFBC),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back_ios_new, color: Colors.white),
|
icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/myhomepage');
|
context.go('/myhomepage');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
title: Text(
|
title: const Text(
|
||||||
'Charts',
|
'Charts',
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: isLoading
|
body: isLoading
|
||||||
? Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: ListView.builder(
|
: Column(
|
||||||
itemCount: chartsData.length,
|
children: [
|
||||||
itemBuilder: (context, index) {
|
Card(
|
||||||
return Card(
|
margin: const EdgeInsets.all(10),
|
||||||
margin: EdgeInsets.all(10),
|
color: Colors.white,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: const [
|
||||||
// Text(
|
Text(
|
||||||
// 'Chart: ${chartsData[index]['chart_type']}',
|
'Card 1 Title',
|
||||||
// style: TextStyle(
|
style: TextStyle(
|
||||||
// fontSize: 18, fontWeight: FontWeight.bold),
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
// ),
|
|
||||||
// SizedBox(height: 10),
|
|
||||||
Container(
|
|
||||||
height: 300,
|
|
||||||
child: buildChart(chartsData[index]),
|
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text('Content for the first card goes here.'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
Card(
|
||||||
|
margin: const EdgeInsets.all(10),
|
||||||
|
color: Colors.white,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: const [
|
||||||
|
Text(
|
||||||
|
'Card 2 Title',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text('Content for the second card goes here.'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: chartsData.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.all(10),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 300,
|
||||||
|
child: buildChart(chartsData[index]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -240,23 +390,35 @@ class ChartPageState extends State<ChartPage> {
|
|||||||
class ChartData {
|
class ChartData {
|
||||||
final String timePeriod;
|
final String timePeriod;
|
||||||
final double value;
|
final double value;
|
||||||
|
final double value1;
|
||||||
final String formattedValue;
|
final String formattedValue;
|
||||||
|
|
||||||
ChartData({required this.timePeriod, required this.value})
|
ChartData(
|
||||||
|
{required this.timePeriod, required this.value, required this.value1})
|
||||||
: formattedValue = formatNumber(value);
|
: formattedValue = formatNumber(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String formatNumber(double value) {
|
||||||
|
// if (value >= 1e12) {
|
||||||
|
// return '${(value / 1e12).toStringAsFixed(2)} T'; // Trillions
|
||||||
|
// } else if (value >= 1e9) {
|
||||||
|
// return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions
|
||||||
|
// } else if (value >= 1e6) {
|
||||||
|
// return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions
|
||||||
|
// } else if (value >= 1e5) {
|
||||||
|
// return '${(value / 1e5).toStringAsFixed(2)} L'; // Lakhs
|
||||||
|
// } else if (value >= 1e3) {
|
||||||
|
// return '${(value / 1e3).toStringAsFixed(2)} K'; // Thousands
|
||||||
|
// }
|
||||||
|
// return value.toStringAsFixed(2); // Default to two decimal places
|
||||||
|
// }
|
||||||
|
|
||||||
String formatNumber(double value) {
|
String formatNumber(double value) {
|
||||||
if (value >= 1e12) {
|
if (value >= 1e9) {
|
||||||
return '${(value / 1e12).toStringAsFixed(2)} T'; // Trillions
|
|
||||||
} else if (value >= 1e9) {
|
|
||||||
return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions
|
return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions
|
||||||
} else if (value >= 1e6) {
|
} else if (value >= 1e6) {
|
||||||
return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions
|
return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions
|
||||||
} else if (value >= 1e5) {
|
|
||||||
return '${(value / 1e5).toStringAsFixed(2)} L'; // Lakhs
|
|
||||||
} else if (value >= 1e3) {
|
|
||||||
return '${(value / 1e3).toStringAsFixed(2)} K'; // Thousands
|
|
||||||
}
|
}
|
||||||
return value.toStringAsFixed(2); // Default to two decimal places
|
return value
|
||||||
|
.toStringAsFixed(2); // Default to two decimal places for smaller numbers
|
||||||
}
|
}
|
||||||
|
|||||||
328
lib/presentation/Screens/demo_home2.dart
Normal file
328
lib/presentation/Screens/demo_home2.dart
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
runApp(MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: ChartPage2(dataSets: ''),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChartPage2 extends StatefulWidget {
|
||||||
|
final String dataSets;
|
||||||
|
const ChartPage2({Key? key, required this.dataSets});
|
||||||
|
@override
|
||||||
|
ChartPageState createState() => ChartPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChartPageState extends State<ChartPage2> {
|
||||||
|
List<dynamic> chartsData = [];
|
||||||
|
bool isLoading = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
fetchChartData(widget.dataSets);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fetchChartData(dataSets) async {
|
||||||
|
const baseUrl =
|
||||||
|
'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL
|
||||||
|
final url = Uri.parse('$baseUrl?dataset=$dataSets');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.get(url);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
setState(() {
|
||||||
|
chartsData = jsonDecode(response.body);
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load data');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setState(() {
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
print('Error fetching data: $error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChartData> parseLineChartData(List<dynamic> response) {
|
||||||
|
return response.map((entry) {
|
||||||
|
// Attempt to fetch the TIMEPERIOD
|
||||||
|
final rawTimePeriod =
|
||||||
|
entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD'];
|
||||||
|
final formattedTimePeriod = rawTimePeriod != null
|
||||||
|
? rawTimePeriod.toString() // Use as-is if valid
|
||||||
|
: 'Unknown'; // Fallback value if null
|
||||||
|
|
||||||
|
// Parse the value or fallback to 0.0
|
||||||
|
final value =
|
||||||
|
double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ??
|
||||||
|
0.0;
|
||||||
|
|
||||||
|
return ChartData(
|
||||||
|
timePeriod: formattedTimePeriod,
|
||||||
|
value: value,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChartData> parseBarChartData(List<dynamic> response) {
|
||||||
|
return response
|
||||||
|
.asMap()
|
||||||
|
.entries
|
||||||
|
.map((entry) => ChartData(
|
||||||
|
timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ??
|
||||||
|
'Unknown', // Fallback to 'Unknown' if null
|
||||||
|
value: double.tryParse(
|
||||||
|
entry.value['ObsValue']['Value'].toString()) ??
|
||||||
|
0.0, // Handle null/invalid value
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update parseColumnChartData for column chart
|
||||||
|
List<ChartData> parseColumnChartData(List<dynamic> response) {
|
||||||
|
return response.map((entry) {
|
||||||
|
// Extract TIME_PERIOD as x
|
||||||
|
final x =
|
||||||
|
int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0;
|
||||||
|
// Extract Value as y
|
||||||
|
final y =
|
||||||
|
double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ??
|
||||||
|
0.0;
|
||||||
|
return ChartData(xInt: x, y: y);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update parseScatterChartData for scatter chart
|
||||||
|
List<ChartData> parseScatterChartData(List<dynamic> response) {
|
||||||
|
return response.map((entry) {
|
||||||
|
// Parse TIME_PERIOD into DateTime
|
||||||
|
final timePeriod = entry['ObsKey']?['TIME_PERIOD'];
|
||||||
|
final x = timePeriod != null
|
||||||
|
? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime
|
||||||
|
: DateTime.now(); // Fallback to current date if null
|
||||||
|
|
||||||
|
// Parse Value into double
|
||||||
|
final y =
|
||||||
|
double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ??
|
||||||
|
0.0;
|
||||||
|
|
||||||
|
return ChartData(xDateTime: x, y: y);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildChart(dynamic chartData) {
|
||||||
|
switch (chartData['chart_type']) {
|
||||||
|
case 'scatter':
|
||||||
|
return SfCartesianChart(
|
||||||
|
primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis
|
||||||
|
tooltipBehavior: TooltipBehavior(enable: true),
|
||||||
|
title: ChartTitle(text: 'Divorces'),
|
||||||
|
series: <CartesianSeries>[
|
||||||
|
ScatterSeries<ChartData, DateTime>(
|
||||||
|
dataSource: parseScatterChartData(chartData['response']),
|
||||||
|
xValueMapper: (ChartData data, _) =>
|
||||||
|
data.xDateTime ?? DateTime.now(),
|
||||||
|
yValueMapper: (ChartData data, _) => data.y,
|
||||||
|
name: chartData['dataset'],
|
||||||
|
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
case 'column':
|
||||||
|
return SfCartesianChart(
|
||||||
|
primaryXAxis: NumericAxis(
|
||||||
|
title: AxisTitle(text: 'Year'),
|
||||||
|
interval: 1, // Ensure no fractional intervals
|
||||||
|
),
|
||||||
|
title: ChartTitle(text: 'Marriages'),
|
||||||
|
series: <CartesianSeries<ChartData, int>>[
|
||||||
|
ColumnSeries<ChartData, int>(
|
||||||
|
dataSource: parseColumnChartData(chartData['response']),
|
||||||
|
xValueMapper: (ChartData data, _) => data.xInt ?? 0,
|
||||||
|
yValueMapper: (ChartData data, _) => data.y,
|
||||||
|
name: chartData['dataset'],
|
||||||
|
color: Color(0xFF7DAFBC),
|
||||||
|
width: 0.8,
|
||||||
|
spacing: 0.2,
|
||||||
|
dataLabelSettings:
|
||||||
|
DataLabelSettings(isVisible: true), // Show data labels
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'line':
|
||||||
|
return SfCartesianChart(
|
||||||
|
primaryXAxis: CategoryAxis(),
|
||||||
|
title: ChartTitle(text: 'Line Chart'),
|
||||||
|
legend: Legend(isVisible: true),
|
||||||
|
tooltipBehavior: TooltipBehavior(enable: true),
|
||||||
|
series: <CartesianSeries<ChartData, String>>[
|
||||||
|
LineSeries<ChartData, String>(
|
||||||
|
dataSource: parseLineChartData(chartData['response']),
|
||||||
|
xValueMapper: (ChartData data, _) => data.timePeriod ?? '',
|
||||||
|
yValueMapper: (ChartData data, _) => data.value ?? 0.0,
|
||||||
|
name: 'Sales',
|
||||||
|
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
case 'bar':
|
||||||
|
return SfCartesianChart(
|
||||||
|
primaryXAxis: CategoryAxis(),
|
||||||
|
title: ChartTitle(text: 'Bar Chart'),
|
||||||
|
tooltipBehavior: TooltipBehavior(enable: true),
|
||||||
|
series: <CartesianSeries<ChartData, String>>[
|
||||||
|
BarSeries<ChartData, String>(
|
||||||
|
dataSource: parseBarChartData(chartData['response']),
|
||||||
|
xValueMapper: (ChartData data, _) => data.timePeriod ?? '',
|
||||||
|
yValueMapper: (ChartData data, _) => data.value ?? 0.0,
|
||||||
|
name: 'Gold',
|
||||||
|
color: Color.fromRGBO(8, 142, 255, 1),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Center(child: Text('Unknown chart type'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFF7DAFBC),
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Color(0xFF7DAFBC),
|
||||||
|
elevation: 0,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: Icon(Icons.arrow_back_ios_new, color: Colors.white),
|
||||||
|
onPressed: () {
|
||||||
|
context.go('/myhomepage');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Charts',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: isLoading
|
||||||
|
? Center(child: CircularProgressIndicator())
|
||||||
|
: Column(
|
||||||
|
children: [
|
||||||
|
// Row for two cards
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
// First Card
|
||||||
|
Expanded(
|
||||||
|
flex: 6,
|
||||||
|
child: Card(
|
||||||
|
margin: EdgeInsets.all(10),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Card 1',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text('Content for Card 1 goes here.'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Second Card
|
||||||
|
Expanded(
|
||||||
|
flex: 6,
|
||||||
|
child: Card(
|
||||||
|
margin: EdgeInsets.all(10),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Card 2',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text('Content for Card 2 goes here.'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// List of charts
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: chartsData.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Card(
|
||||||
|
margin: EdgeInsets.all(10),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Container(
|
||||||
|
height: 300,
|
||||||
|
child: buildChart(chartsData[index]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChartData {
|
||||||
|
final int? xInt; // For column and other charts, using int for x
|
||||||
|
final DateTime? xDateTime; // For scatter charts, using DateTime for x
|
||||||
|
final double y; // For column and other charts
|
||||||
|
final String? timePeriod; // For line and bar charts
|
||||||
|
final double? value; // For line and bar charts
|
||||||
|
final double? y2; // For secondary data (stacked column chart)
|
||||||
|
final double? y3; // For tertiary data (stacked column chart)
|
||||||
|
final double? y4; // For quaternary data (stacked column chart)
|
||||||
|
|
||||||
|
// Constructor that handles all chart cases
|
||||||
|
ChartData({
|
||||||
|
this.xInt,
|
||||||
|
this.xDateTime,
|
||||||
|
this.y = 0.0,
|
||||||
|
this.timePeriod,
|
||||||
|
this.value,
|
||||||
|
this.y2,
|
||||||
|
this.y3,
|
||||||
|
this.y4,
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -171,6 +171,20 @@ class MyHomePage extends StatefulWidget {
|
|||||||
State<MyHomePage> createState() => _MyHomePageState();
|
State<MyHomePage> createState() => _MyHomePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleInfoCardClick(BuildContext context, String data) {
|
||||||
|
// Handle navigation and pass dynamic data
|
||||||
|
print(data);
|
||||||
|
final dataSets = data;
|
||||||
|
print(dataSets);
|
||||||
|
if (dataSets == 'hotels') {
|
||||||
|
context.go('/Chart/$dataSets');
|
||||||
|
} else if (dataSets == 'divorces') {
|
||||||
|
context.go('/Chart/$dataSets');
|
||||||
|
} else if (dataSets == 'marriages') {
|
||||||
|
context.go('/Chart/$dataSets');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -226,6 +240,7 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '1.62T',
|
value: '1.62T',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () => handleInfoCardClick(context, 'Inflation'),
|
||||||
),
|
),
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Inflation Rate',
|
title: 'Inflation Rate',
|
||||||
@ -233,6 +248,7 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '4.82%',
|
value: '4.82%',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () => handleInfoCardClick(context, 'Inflation'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -247,6 +263,8 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '215.4B',
|
value: '215.4B',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'commodities'),
|
||||||
),
|
),
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Hotel Guests',
|
title: 'Hotel Guests',
|
||||||
@ -254,6 +272,7 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '25.21M',
|
value: '25.21M',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () => handleInfoCardClick(context, 'hotels'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -280,18 +299,22 @@ class EconomyStats extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Population',
|
title: 'Divorces',
|
||||||
subtitle: '(2022) (AED)',
|
subtitle: '(2022)',
|
||||||
value: '1.62T',
|
value: '0',
|
||||||
bordercolor: Colors.brown[200]!,
|
bordercolor: Colors.brown[200]!,
|
||||||
textcolor: Colors.brown[200]!,
|
textcolor: Colors.brown[200]!,
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'divorces'),
|
||||||
),
|
),
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Labor Force',
|
title: 'Marriages',
|
||||||
subtitle: '(2022)',
|
subtitle: '(2022)',
|
||||||
value: '4.82%',
|
value: '0',
|
||||||
bordercolor: Colors.brown[200]!,
|
bordercolor: Colors.brown[200]!,
|
||||||
textcolor: Colors.brown[200]!,
|
textcolor: Colors.brown[200]!,
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'marriages'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -301,11 +324,13 @@ class EconomyStats extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Hospitals (Gov )',
|
title: 'Hospitals (Gov)',
|
||||||
subtitle: '(Jan - Jan 2024) - AED',
|
subtitle: '(Jan - Jan 2024) - AED',
|
||||||
value: '215.4B',
|
value: '215.4B',
|
||||||
bordercolor: Colors.brown[200]!,
|
bordercolor: Colors.brown[200]!,
|
||||||
textcolor: Colors.brown[200]!,
|
textcolor: Colors.brown[200]!,
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'Hospitals'),
|
||||||
),
|
),
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Schools',
|
title: 'Schools',
|
||||||
@ -313,6 +338,8 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '25.21M',
|
value: '25.21M',
|
||||||
bordercolor: Colors.brown[200]!,
|
bordercolor: Colors.brown[200]!,
|
||||||
textcolor: Colors.brown[200]!,
|
textcolor: Colors.brown[200]!,
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'Schools'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -345,6 +372,8 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '1.62T',
|
value: '1.62T',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () => handleInfoCardClick(
|
||||||
|
context, 'Electricity'),
|
||||||
),
|
),
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Cruid oil',
|
title: 'Cruid oil',
|
||||||
@ -352,6 +381,8 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '4.82%',
|
value: '4.82%',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'Cruid'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -367,6 +398,8 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '215.4B',
|
value: '215.4B',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () =>
|
||||||
|
handleInfoCardClick(context, 'Export'),
|
||||||
),
|
),
|
||||||
InfoCard(
|
InfoCard(
|
||||||
title: 'Desalinated water',
|
title: 'Desalinated water',
|
||||||
@ -374,6 +407,8 @@ class EconomyStats extends StatelessWidget {
|
|||||||
value: '25.21M',
|
value: '25.21M',
|
||||||
bordercolor: Color(0xFF7DAFBC),
|
bordercolor: Color(0xFF7DAFBC),
|
||||||
textcolor: Color(0xFF7DAFBC),
|
textcolor: Color(0xFF7DAFBC),
|
||||||
|
onTap: () => handleInfoCardClick(
|
||||||
|
context, 'Desalinated'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -433,6 +468,7 @@ class InfoCard extends StatelessWidget {
|
|||||||
final String value;
|
final String value;
|
||||||
final Color bordercolor;
|
final Color bordercolor;
|
||||||
final Color? textcolor;
|
final Color? textcolor;
|
||||||
|
final VoidCallback onTap; // New callback parameter
|
||||||
|
|
||||||
const InfoCard({
|
const InfoCard({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -441,6 +477,7 @@ class InfoCard extends StatelessWidget {
|
|||||||
required this.value,
|
required this.value,
|
||||||
required this.bordercolor,
|
required this.bordercolor,
|
||||||
this.textcolor,
|
this.textcolor,
|
||||||
|
required this.onTap, // Initialize in constructor
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -450,9 +487,7 @@ class InfoCard extends StatelessWidget {
|
|||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: onTap, // Use callback for handling clicks
|
||||||
context.go('/DemoHome');
|
|
||||||
},
|
|
||||||
child: Container(
|
child: Container(
|
||||||
height: myheight / 9,
|
height: myheight / 9,
|
||||||
width: mywidth / 4,
|
width: mywidth / 4,
|
||||||
|
|||||||
@ -20,7 +20,7 @@ dependencies:
|
|||||||
injectable: ^2.3.2
|
injectable: ^2.3.2
|
||||||
riverpod_annotation: ^2.3.3
|
riverpod_annotation: ^2.3.3
|
||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
fl_chart: ^0.69.0
|
fl_chart: ^0.69.2
|
||||||
marquee: ^2.2.3
|
marquee: ^2.2.3
|
||||||
# dynamic_layouts:
|
# dynamic_layouts:
|
||||||
# git:
|
# git:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user