chart flow , Home and Uae number added

This commit is contained in:
venbaittech 2025-01-16 17:12:37 +05:30
parent d77725601e
commit e1bc780f50
17 changed files with 2932 additions and 2806 deletions

View File

@ -327,7 +327,7 @@ final GoRouter router = GoRouter(
GoRoute( GoRoute(
path: '/', path: '/',
//builder: (context, state) => LoginRoute(), //builder: (context, state) => LoginRoute(),
builder: (context, state) => MyHomePage(), builder: (context, state) => LoginRoute(),
), ),
GoRoute( GoRoute(
path: '/login', path: '/login',
@ -342,29 +342,39 @@ final GoRouter router = GoRouter(
path: '/register', path: '/register',
builder: (context, state) => RegisterScreen(), builder: (context, state) => RegisterScreen(),
), ),
GoRoute( // GoRoute(
path: '/DemoHome/:dataSets', // path: '/DemoHome/:dataSets',
builder: (context, state) { // builder: (context, state) {
final dataSets = state.pathParameters['dataSets']!; // final dataSets = state.pathParameters['dataSets']!;
print('Router $dataSets'); // print('Router $dataSets');
return ChartPage(dataSets: dataSets); // return ChartPage(dataSets: dataSets);
}, // },
), // ),
GoRoute( // GoRoute(
path: '/Chart/:dataSets', // path: '/Chart/:dataSets',
builder: (context, state) { // builder: (context, state) {
final dataSets = state.pathParameters['dataSets']!; // final dataSets = state.pathParameters['dataSets']!;
print('Router $dataSets'); // print('Router $dataSets');
return ChartScreen(dataSets: dataSets); // return ChartScreen(dataSets: dataSets);
}, // },
), // ),
GoRoute( GoRoute(
path: '/chartScreen/:dataSets', path: '/chartScreen/:dataSets',
builder: (context, state) { builder: (context, state) {
// Retrieve path parameter
final dataSets = state.pathParameters['dataSets']!; final dataSets = state.pathParameters['dataSets']!;
print('Router $dataSets'); // Retrieve query parameter
// return ChartScreen(dataSets: dataSets); final bgColor = state.uri.queryParameters['bgColor'] ??
return ChartScreen1(dataSets: dataSets); '0xFFFFFFFF'; // Default white
print('Router dataSets: $dataSets');
print('Router bgColor: $bgColor');
// Pass both values to the screen
return ChartScreen1(
dataSets: dataSets,
bgColor: bgColor,
);
}, },
), ),
GoRoute( GoRoute(
@ -417,19 +427,20 @@ final GoRouter router = GoRouter(
path: '/user-guide', path: '/user-guide',
builder: (context, state) => UserGuide(), builder: (context, state) => UserGuide(),
routes: <RouteBase>[ routes: <RouteBase>[
GoRoute(path: '/features', GoRoute(
name: 'features', path: '/features',
builder: (context, state) => UsingFeatures(), name: 'features',
builder: (context, state) => UsingFeatures(),
), ),
GoRoute(
GoRoute(path: '/faq', path: '/faq',
name: 'faq', name: 'faq',
builder: (context, state) => FAQPage(), builder: (context, state) => FAQPage(),
), ),
GoRoute(
GoRoute(path: '/gettingStarted', path: '/gettingStarted',
name: 'gettingStarted', name: 'gettingStarted',
builder: (context, state) => GettingStarted(), builder: (context, state) => GettingStarted(),
), ),
], ],
), ),
@ -455,10 +466,7 @@ final GoRouter router = GoRouter(
// path: '/uaenumbers', // path: '/uaenumbers',
// builder: (context, state) => UaeNumbers(), // builder: (context, state) => UaeNumbers(),
// ), // ),
GoRoute( GoRoute(path: '/uaenumbers', builder: (context, state) => UaeNumbers()),
path: '/uaenumbers',
builder: (context,state) => UaeNumbers()
),
GoRoute( GoRoute(
path: '/competitiveness', path: '/competitiveness',

View File

@ -1,8 +1,11 @@
import 'dart:convert';
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/routes/bottom_bar_routes/tab_routes/home_route.dart'; import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.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 'package:uae_stat/presentation/components/constant/constant.dart'; import 'package:uae_stat/presentation/components/constant/constant.dart';
import 'package:http/http.dart' as http;
class UaeNumbers extends StatelessWidget { class UaeNumbers extends StatelessWidget {
const UaeNumbers({super.key}); const UaeNumbers({super.key});
@ -20,13 +23,49 @@ class UaeNumbers extends StatelessWidget {
} }
} }
class uaenumberWidget extends StatelessWidget { class uaenumberWidget extends StatefulWidget {
const uaenumberWidget({super.key}); const uaenumberWidget({super.key});
@override @override
_UaenumberWidgetState createState() => _UaenumberWidgetState();
}
class _UaenumberWidgetState extends State<uaenumberWidget> {
@override
List<dynamic> homePageData = [];
bool isLoading = true;
@override
void initState() {
fetchData();
}
Future<void> fetchData() async {
// const baseUrl = 'https://pb.venbait.in/api/getHomePageData';
const baseUrl = 'https://pb.venbait.in/api/getUAENumbersData';
try {
final response = await http.get(Uri.parse(baseUrl));
if (response.statusCode == 200) {
setState(() {
homePageData = json.decode(response.body);
// print("HomeDAta $homePageData");
isLoading = false;
});
} else {
throw Exception('Failed to load data');
}
} catch (e) {
setState(() {
isLoading = false;
});
print('Error fetching data: $e');
}
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: ListView( child: ListView(
@ -49,153 +88,112 @@ class uaenumberWidget extends StatelessWidget {
SizedBox( SizedBox(
height: myheight / 35, height: myheight / 35,
), ),
CustomExpandableTile( ...homePageData.map<Widget>((mainTopic) {
title: 'ECONOMY', String colorPattern = mainTopic['color_pattern'];
titleBackgroundColor: economyColor, print('colorPattern $colorPattern');
children: [ Color backgroundColor = Color(int.parse(colorPattern));
buildCategoryTitle('National Accounts', economyColor), print('backgroundColor $backgroundColor');
buildCardRow([ Color borderColor = backgroundColor;
buildCard(context, 'GDP (Constant)', '1.62T', '2022 (AED)', int index = homePageData.indexOf(mainTopic);
economyColor, economyColor, mywidth / 2.5), bool isFirstTile = index == 0;
buildCard(context, 'FDI', '1.45T', '2021 (AED)', economyColor,
economyColor, mywidth / 2.5), return CustomExpandableTile(
]), index: index,
buildCategoryTitle('International Trade', economyColor), isExpanded: isFirstTile,
buildCardRow([ title: mainTopic['main_topic'],
buildCard( titleBackgroundColor: backgroundColor,
context, children: _buildSubTopics(
'Total Trade', mainTopic['sub_topics'] ?? [],
'669.9B', mywidth,
'Jan - Mar 2024 (AED)', borderColor,
economyColor, colorPattern,
economyColor, ),
mywidth / 2.5), );
buildCard( }),
context,
'Total Import',
'686B',
'Jan - Mar 2024 (AED)',
economyColor,
economyColor,
mywidth / 2.5),
]),
buildCardRow([
buildCard(
context,
'Total Export',
'669.9B',
'Jan - Mar 2024 (AED)',
economyColor,
economyColor,
mywidth / 2.5),
buildCard(
context,
'Total ReExport',
'686B',
'Jan - Mar 2024 (AED)',
economyColor,
economyColor,
mywidth / 2.5),
]),
buildCategoryTitle('Prices', economyColor),
buildCardRow([
buildCard(
context,
'Total Export',
'669.9B',
'Jan - Mar 2024 (AED)',
economyColor,
economyColor,
mywidth / 1.2),
]),
],
),
CustomExpandableTile(
title: 'SOCIAL',
titleBackgroundColor: socialColor,
children: [
buildCategoryTitle('Population', socialColor),
buildCardRow([
InkWell(
onTap: () {},
child: buildCard(context, 'Population', '9.89M', '2024',
socialColor, socialColor, mywidth / 2.5)),
buildCard(context, 'Population Growth', '2.1%', '2023',
socialColor, socialColor, mywidth / 2.5),
]),
buildCategoryTitle('Vital Statistics', socialColor),
buildCardRow([
InkWell(onTap : (){
context.go('/marriages');
},child: buildCard(context,'Marriages', '96%', '2023',socialColor,socialColor,mywidth/2.5)),
InkWell(onTap : (){},child: buildCard(context,'Divorces', '1.2K', '2024',socialColor,socialColor,mywidth/2.5)),
]),
buildCategoryTitle('Education', socialColor),
buildCardRow([
buildCard(context, 'General Education', '96%', '2023',
socialColor, socialColor, mywidth / 2.5),
buildCard(context, 'Higher Education', '1.2K', '2024',
socialColor, socialColor, mywidth / 2.5),
]),
buildCategoryTitle('Health', socialColor),
buildCardRow([
buildCard(context, 'Hospital', '96%', '2023', socialColor,
socialColor, mywidth / 2.5),
buildCard(context, 'Clinic and Centres', '1.2K', '2024',
socialColor, socialColor, mywidth / 2.5),
]),
],
),
CustomExpandableTile(
title: 'ENVIRONMENT',
titleBackgroundColor: environmentColor,
children: [
buildCategoryTitle('Agriculture', environmentColor),
buildCardRow([
buildCard(context, 'Crops - Total Area', '27°C', 'Average 2024',
environmentColor, environmentColor, mywidth / 2.5),
buildCard(context, 'Livestock', '120mm', '2024',
environmentColor, environmentColor, mywidth / 2.5),
]),
buildCategoryTitle('Environment', environmentColor),
buildCardRow([
buildCard(context, 'Climate - Max Temp', '15%', '2024',
environmentColor, environmentColor, mywidth / 2.5),
buildCard(context, 'Climate - Min Temp', '30%', '2023',
environmentColor, environmentColor, mywidth / 2.5),
]),
buildCardRow([
buildCard(context, 'Desalinated Produced Water', '15%', '2024',
environmentColor, environmentColor, mywidth / 2.5),
buildCard(context, 'Area of Natural Reserves', '30%', '2023',
environmentColor, environmentColor, mywidth / 2.5),
]),
buildCategoryTitle('Energy', environmentColor),
buildCardRow([
buildCard(context, 'Electricity Production', '15%', '2024',
environmentColor, environmentColor, mywidth / 2.5),
buildCard(context, 'Renewable Energy Production', '30%', '2023',
environmentColor, environmentColor, mywidth / 2.5),
]),
],
),
], ],
), ),
); );
} }
List<Widget> _buildSubTopics(List<dynamic> subTopics, double myWidth,
Color borderColor, String colorPattern) {
print('colorPattern123 $borderColor');
// Sort sub-topics based on `sub_topic_list_order`
subTopics.sort((a, b) => (a['sub_topic_list_order'] ?? 0)
.compareTo(b['sub_topic_list_order'] ?? 0));
return subTopics
.map<Widget>((subTopic) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildCategoryTitle(subTopic['sub_topic'], borderColor),
..._buildDataSetCards(subTopic['tile_data'] ?? [], myWidth,
borderColor, colorPattern),
],
))
.toList();
}
List<Widget> _buildDataSetCards(
List<dynamic> tileData, double myWidth, Color borderColor, colorPattern) {
// Sort datasets based on `data_set_list_order`
tileData.sort((a, b) => (a['data_set_list_order'] ?? 0)
.compareTo(b['data_set_list_order'] ?? 0));
List<Widget> rows = [];
for (int i = 0; i < tileData.length; i += 2) {
// Take 1 or 2 items for the row
final rowItems = tileData.sublist(
i,
i + 2 > tileData.length ? tileData.length : i + 2,
);
rows.add(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: rowItems.map<Widget>((data) {
// Calculate width: full width for one item, half for two items
final cardWidth = rowItems.length == 1
? myWidth
: (myWidth - 16) / 2; // Subtract spacing for padding
return Expanded(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 5.0), // Add spacing
child: buildCard(
context,
data['data_set_tile_heading'] ?? '',
data['value'] ?? '',
data['value_source'] ?? '',
data['data_set'] ?? '',
borderColor,
borderColor,
colorPattern,
cardWidth, // Pass the calculated width
),
),
);
}).toList(),
),
);
}
return rows;
}
Widget buildCategoryTitle(String title, Color color) { Widget buildCategoryTitle(String title, Color color) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0), padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text( child: Center(
title, child: Text(
style: TextStyle( title,
fontSize: 16, style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16,
color: color, fontWeight: FontWeight.bold,
), color: color,
), ),
); ),
));
} }
Widget buildCardRow(List<Widget> cards) { Widget buildCardRow(List<Widget> cards) {
@ -212,43 +210,58 @@ class uaenumberWidget extends StatelessWidget {
); );
} }
Widget buildCard(BuildContext context, String title, String value, Widget buildCard(
String subtitle, Color bordercolor, boldColor, double mywidth) { BuildContext context,
// double myheight = MediaQuery.of(context).size.height; String title,
// double mywidth = MediaQuery.of(context).size.width; String value,
return Card( String subtitle,
elevation: 2, String data_set,
child: Container( Color bordercolor,
width: mywidth, Color boldColor,
decoration: BoxDecoration( colorPattern,
color: Colors.white, // Background color double mywidth,
border: Border.all( ) {
color: bordercolor, // Border color return GestureDetector(
width: 2, // Border width onTap: () {
print(colorPattern);
context.go('/chartScreen/$data_set?bgColor=$colorPattern');
// context.go('/chartScreen/$data_set');
},
child: Card(
elevation: 1,
child: Container(
width: mywidth,
decoration: BoxDecoration(
color: Colors.white, // Background color
border: Border.all(
color: bordercolor, // Border color
width: 2, // Border width
),
borderRadius:
BorderRadius.circular(12), // Optional: Rounded corners
), ),
borderRadius: BorderRadius.circular(12), // Optional: Rounded corners padding: const EdgeInsets.all(3.0),
), child: Column(
padding: const EdgeInsets.all(16.0), mainAxisAlignment: MainAxisAlignment.center,
child: Column( children: [
mainAxisAlignment: MainAxisAlignment.center, Text(
children: [ title,
Text( textAlign: TextAlign.center,
title, style: robotoRegular11,
textAlign: TextAlign.center,
style: robotoRegular11,
),
SizedBox(height: 8),
Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle),
SizedBox(height: 8),
Text(
value,
style: TextStyle(
fontSize: 26,
color: boldColor,
fontWeight: FontWeight.bold,
), ),
), SizedBox(height: 0.2),
], Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle),
SizedBox(height: 0.7),
Text(
value,
style: TextStyle(
fontSize: 24,
color: boldColor,
fontWeight: FontWeight.bold,
),
),
],
),
), ),
), ),
); );
@ -259,11 +272,15 @@ class CustomExpandableTile extends StatefulWidget {
final String title; final String title;
final Color titleBackgroundColor; final Color titleBackgroundColor;
final List<Widget> children; final List<Widget> children;
final int index;
final bool isExpanded;
const CustomExpandableTile({ const CustomExpandableTile({
required this.title, required this.title,
required this.titleBackgroundColor, required this.titleBackgroundColor,
required this.children, required this.children,
required this.index,
required this.isExpanded,
}); });
@override @override
@ -271,13 +288,21 @@ class CustomExpandableTile extends StatefulWidget {
} }
class _CustomExpandableTileState extends State<CustomExpandableTile> { class _CustomExpandableTileState extends State<CustomExpandableTile> {
bool isExpanded = false; // bool isExpanded = false;
late bool isExpanded;
@override
void initState() {
super.initState();
isExpanded =
widget.isExpanded; // Initialize isExpanded based on widget's property
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
return Card( return Card(
elevation: 4, elevation: 0,
child: Column( child: Column(
children: [ children: [
GestureDetector( GestureDetector(
@ -289,8 +314,9 @@ class _CustomExpandableTileState extends State<CustomExpandableTile> {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: widget.titleBackgroundColor, color: widget.titleBackgroundColor,
borderRadius: BorderRadius.all(Radius.circular(12))), borderRadius: BorderRadius.all(Radius.circular(35))),
padding: const EdgeInsets.all(12), padding: const EdgeInsets.only(
left: 16, bottom: 10, top: 10, right: 10),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -307,6 +333,7 @@ class _CustomExpandableTileState extends State<CustomExpandableTile> {
? Icons.keyboard_arrow_up ? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down, : Icons.keyboard_arrow_down,
color: Colors.white, color: Colors.white,
size: 28.0,
), ),
], ],
), ),
@ -317,14 +344,15 @@ class _CustomExpandableTileState extends State<CustomExpandableTile> {
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeInOut, curve: Curves.easeInOut,
width: double.infinity, width: double.infinity,
height: isExpanded ? myheight * 0.52 : 0,
child: isExpanded child: isExpanded
? SingleChildScrollView( ? SingleChildScrollView(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
borderRadius: // borderRadius: BorderRadius.all(Radius.circular(20))
BorderRadius.all(Radius.circular(20))), ),
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(1),
child: Column( child: Column(
children: widget.children, children: widget.children,
), ),

View File

@ -189,11 +189,12 @@ class _RegisterScreenState extends State<RegisterScreen> {
print('adminToken- ${adminToken}'); print('adminToken- ${adminToken}');
// Create user in PocketBase // Create user in PocketBase
final response = await pb.collection('users').create(body: { final response = await pb.collection('users').create(body: {
'username': _usernameController.text, 'uname': _usernameController.text,
'email': _emailController.text, 'email': _emailController.text,
'password': _passwordController.text, 'password': _passwordController.text,
'passwordConfirm': _passwordController.text, 'passwordConfirm': _passwordController.text,
'status': 'Pending', 'status': 'Pending',
'role': 'user',
}, headers: { }, headers: {
'Authorization': adminToken 'Authorization': adminToken
}); });
@ -316,15 +317,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
ElevatedButton( ElevatedButton(
onPressed: () => { onPressed: () => {context.go('/')},
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => LoginRoute()
//ProfileScreen(userId: userID)
),
),
},
child: Text( child: Text(
'Go to Login', 'Go to Login',
), ),

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,10 @@ import '../filters/search_filter_helper.dart';
class ChartScreen1 extends StatefulWidget { class ChartScreen1 extends StatefulWidget {
final String dataSets; final String dataSets;
const ChartScreen1({Key? key, required this.dataSets}); final String bgColor;
const ChartScreen1(
{Key? key, required this.dataSets, required String this.bgColor});
@override @override
_ChartScreen1State createState() => _ChartScreen1State(); _ChartScreen1State createState() => _ChartScreen1State();
} }
@ -24,10 +27,13 @@ class _ChartScreen1State extends State<ChartScreen1> {
List<dynamic> cardData = []; List<dynamic> cardData = [];
List<dynamic> originalChartsData = []; List<dynamic> originalChartsData = [];
List<dynamic> originalCardData = []; List<dynamic> originalCardData = [];
late Color backgroundColor;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final String bgColor = widget.bgColor;
print(' bgColor $bgColor');
fetchChartData(widget.dataSets); fetchChartData(widget.dataSets);
} }
@ -368,11 +374,13 @@ class _ChartScreen1State extends State<ChartScreen1> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final color =
Color(int.parse(widget.bgColor.replaceFirst('0x', ''), radix: 16));
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
backgroundColor: Colors.brown[200]!, backgroundColor: color,
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.brown[200]!, backgroundColor: color,
elevation: 0, elevation: 0,
leading: IconButton( leading: IconButton(
icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), icon: Icon(Icons.arrow_back_ios_new, color: Colors.white),
@ -451,8 +459,8 @@ class _ChartScreen1State extends State<ChartScreen1> {
crossAxisCount: 2, // 2 cards per row crossAxisCount: 2, // 2 cards per row
crossAxisSpacing: 10, crossAxisSpacing: 10,
mainAxisSpacing: 10, mainAxisSpacing: 10,
childAspectRatio: 177.5 / childAspectRatio: 190.5 /
180, // Adjusted to maintain width and fixed height 200, // Adjusted to maintain width and fixed height
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = cardData[index]; final item = cardData[index];
@ -470,49 +478,56 @@ class _ChartScreen1State extends State<ChartScreen1> {
), ),
elevation: 4, elevation: 4,
child: Padding( child: Padding(
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(10.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Icon(Icons.public, const Icon(Icons.public,
color: Color(0xFF90B0D5), size: 22), color: Color(0xFF90B0D5), size: 30),
const SizedBox(height: 5), const SizedBox(height: 3),
Text( Text(
'${chart_heading ?? 'NA'}', '${chart_heading ?? 'NA'}',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 11,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w400,
color: Colors.black87, color: Colors.black87,
), ),
), ),
Text( Text(
'(${data['lastYear'] ?? 'NA'})', '(${data['lastYear'] ?? 'NA'})',
style: const TextStyle( style: const TextStyle(
fontSize: 10, color: Colors.grey), fontSize: 11, color: Colors.grey),
), ),
Text( Text(
'${data['lastYearValue'] ?? 'NA'}', apiService
.formatAmount(data['lastYearValue']),
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Color(0xFF90B0D5), color: Color(0xFF90B0D5),
), ),
), ),
const Divider( SizedBox(
color: Colors.grey, thickness: 1), height: 5, // Height of the divider
child: Divider(
color: Colors.grey,
thickness: 1, // Divider line thickness
),
),
Text( Text(
'${data['secondLastYearValue'] ?? 'NA'}', apiService.formatAmount(
data['secondLastYearValue']),
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w600,
color: Color(0xFF90B0D5), color: Color(0xFFD83731),
), ),
), ),
Text( Text(
'(${data['secondLastYear'] ?? 'NA'})', '(${data['secondLastYear'] ?? 'NA'})',
style: const TextStyle( style: const TextStyle(
fontSize: 10, color: Colors.grey), fontSize: 11, color: Colors.grey),
), ),
], ],
), ),
@ -531,28 +546,28 @@ class _ChartScreen1State extends State<ChartScreen1> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Icon(Icons.analytics, const Icon(Icons.analytics,
color: Color(0xFF90B0D5), size: 22), color: Color(0xFF90B0D5), size: 30),
const SizedBox(height: 5), const SizedBox(height: 5),
Text( Text(
'${chart_heading ?? 'NA'}', '${chart_heading ?? 'NA'}',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 11,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w400,
color: Colors.black87, color: Colors.black87,
), ),
), ),
Text( Text(
'(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})', '(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})',
style: const TextStyle( style: const TextStyle(
fontSize: 10, color: Colors.grey), fontSize: 11, color: Colors.grey),
), ),
Text( Text(
'${data['roundedAverage'] ?? 'NA'}', '${data['roundedAverage'] ?? 'NA'}',
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 26,
fontWeight: FontWeight.bold, fontWeight: FontWeight.w900,
color: Color(0xFF90B0D5), color: Color(0xFF11AF22),
), ),
), ),
], ],

View File

@ -56,45 +56,6 @@ class ApiService {
} }
} }
/// Fetch chart data and categorize it into chart and non-chart data
// Future<void> fetchChartData(String dataSets) async {
// final url = Uri.parse('$baseUrl?dataset=$dataSets');
//
// List<dynamic> isChartData = [];
// List<dynamic> nonChartData = [];
// List<dynamic> originalChartsData = [];
// List<dynamic> originalCardData = [];
//
// try {
// final response = await http.get(url);
//
// if (response.statusCode == 200) {
// final List<dynamic> data = jsonDecode(response.body);
//
// for (var item in data) {
// if (item['is_chart'] == 'true') {
// isChartData.add(item);
// } else if (item['is_chart'] == 'false') {
// nonChartData.add(item);
// }
// }
//
// print('Chart Data: $isChartData');
// print('Non-Chart Data: $nonChartData');
//
// originalChartsData = List.from(isChartData);
// originalCardData = List.from(nonChartData);
//
// print('chartsData $isChartData');
// print('cardData $nonChartData');
// } else {
// throw Exception('Failed to load data');
// }
// } catch (error) {
// print('Error fetching data: $error');
// }
// }
/// Process non-chart data by extracting and calculating values /// Process non-chart data by extracting and calculating values
Map<String, dynamic> processNonChartData(dynamic item) { Map<String, dynamic> processNonChartData(dynamic item) {
print('Processing non-chart data...'); print('Processing non-chart data...');
@ -181,4 +142,22 @@ class ApiService {
); );
}).toList(); }).toList();
} }
String formatAmount(dynamic value) {
// Handle null or non-numeric values
if (value == null || num.tryParse(value.toString()) == null) {
return 'NA';
}
num amount = num.tryParse(value.toString())!;
// Check if the amount is in millions or thousands
if (amount >= 1000000) {
return '${(amount / 1000000).toStringAsFixed(2)}M';
} else if (amount >= 1000) {
return '${(amount / 1000).toStringAsFixed(2)}K';
} else {
return '$amount';
}
}
} }

View File

@ -2,7 +2,7 @@ import 'dart:math';
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; // import 'package:syncfusion_flutter_charts/charts.dart';
class ChartWidget extends StatelessWidget { class ChartWidget extends StatelessWidget {
final dynamic chartData; final dynamic chartData;
@ -121,80 +121,80 @@ class ChartWidget extends StatelessWidget {
print('groupByValues $groupByValues'); print('groupByValues $groupByValues');
switch (chartData['chart_type']) { switch (chartData['chart_type']) {
case 'stacked_bar': // case 'stacked_bar':
String chartTitle = // String chartTitle =
capitalizeAndSplit(chartData['chart_heading'] ?? ''); // capitalizeAndSplit(chartData['chart_heading'] ?? '');
// Define a list of colors // // Define a list of colors
final List<Color> uniqueColors = [ // final List<Color> uniqueColors = [
Color(0xFF648CBA), // Color(0xFF648CBA),
Color(0xFF90B0D5), // Color(0xFF90B0D5),
Color(0xFF98BCE5), // Color(0xFF98BCE5),
Color(0xFFA7B5C5), // Color(0xFFA7B5C5),
Color(0xFFBED3EC), // Color(0xFFBED3EC),
Color(0xFFD4E3F4), // Color(0xFFD4E3F4),
]; // ];
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: CategoryAxis(), // primaryXAxis: CategoryAxis(),
title: ChartTitle(text: chartData['chart_heading']), // title: ChartTitle(text: chartData['chart_heading']),
legend: Legend( // legend: Legend(
isVisible: true, // isVisible: true,
position: LegendPosition.bottom, // position: LegendPosition.bottom,
overflowMode: LegendItemOverflowMode.scroll, // overflowMode: LegendItemOverflowMode.scroll,
), // ),
tooltipBehavior: TooltipBehavior( // tooltipBehavior: TooltipBehavior(
enable: true, // Enable tooltips // enable: true, // Enable tooltips
format: 'point.x : point.y', // Custom tooltip format // format: 'point.x : point.y', // Custom tooltip format
), // ),
series: <StackedBarSeries<ChartData, String>>[ // series: <StackedBarSeries<ChartData, String>>[
for (int i = 0; i < groupByValues.length; i++) // for (int i = 0; i < groupByValues.length; i++)
StackedBarSeries<ChartData, String>( // StackedBarSeries<ChartData, String>(
dataSource: parseStackedBarChartData( // dataSource: parseStackedBarChartData(
chartData, groupByKey, groupByValues.elementAt(i)), // chartData, groupByKey, groupByValues.elementAt(i)),
xValueMapper: (ChartData data, _) => data.x ?? '', // xValueMapper: (ChartData data, _) => data.x ?? '',
yValueMapper: (ChartData data, _) => data.y, // yValueMapper: (ChartData data, _) => data.y,
name: groupByValues.elementAt(i), // name: groupByValues.elementAt(i),
color: uniqueColors[i % uniqueColors.length], // color: uniqueColors[i % uniqueColors.length],
enableTooltip: true, // enableTooltip: true,
), // ),
], // ],
); // );
case 'stacked_column': // case 'stacked_column':
String chartTitle = // String chartTitle =
capitalizeAndSplit(chartData['chart_heading'] ?? ''); // capitalizeAndSplit(chartData['chart_heading'] ?? '');
// Define a list of colors // // Define a list of colors
final List<Color> uniqueColors = [ // final List<Color> uniqueColors = [
Color(0xFF648CBA), // Color(0xFF648CBA),
Color(0xFF90B0D5), // Color(0xFF90B0D5),
Color(0xFF98BCE5), // Color(0xFF98BCE5),
Color(0xFFA7B5C5), // Color(0xFFA7B5C5),
Color(0xFFBED3EC), // Color(0xFFBED3EC),
Color(0xFFD4E3F4), // Color(0xFFD4E3F4),
]; // ];
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: CategoryAxis(), // primaryXAxis: CategoryAxis(),
title: ChartTitle(text: chartData['chart_heading']), // title: ChartTitle(text: chartData['chart_heading']),
legend: Legend( // legend: Legend(
isVisible: true, // isVisible: true,
position: LegendPosition.bottom, // position: LegendPosition.bottom,
overflowMode: LegendItemOverflowMode.scroll, // overflowMode: LegendItemOverflowMode.scroll,
), // ),
tooltipBehavior: TooltipBehavior( // tooltipBehavior: TooltipBehavior(
enable: true, // Enable tooltips // enable: true, // Enable tooltips
format: 'point.x : point.y', // Custom tooltip format // format: 'point.x : point.y', // Custom tooltip format
), // ),
series: <CartesianSeries<ChartData, String>>[ // series: <CartesianSeries<ChartData, String>>[
for (int i = 0; i < groupByValues.length; i++) // for (int i = 0; i < groupByValues.length; i++)
StackedColumnSeries<ChartData, String>( // StackedColumnSeries<ChartData, String>(
dataSource: parseStackedBarChartData( // dataSource: parseStackedBarChartData(
chartData, groupByKey, groupByValues.elementAt(i)), // chartData, groupByKey, groupByValues.elementAt(i)),
xValueMapper: (ChartData data, _) => data.x ?? '', // xValueMapper: (ChartData data, _) => data.x ?? '',
yValueMapper: (ChartData data, _) => data.y, // yValueMapper: (ChartData data, _) => data.y,
name: groupByValues.elementAt(i), // name: groupByValues.elementAt(i),
color: uniqueColors[i % uniqueColors.length], // color: uniqueColors[i % uniqueColors.length],
enableTooltip: true, // enableTooltip: true,
), // ),
], // ],
); // );
case 'column_chart': // Case 3 for fl_chart column chart case 'column_chart': // Case 3 for fl_chart column chart
return BarChart( return BarChart(
BarChartData( BarChartData(
@ -369,42 +369,37 @@ class ChartWidget extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(5.0),
child: Wrap( child: Wrap(
spacing: 5, spacing: 10, // Horizontal spacing between items
runSpacing: 5, runSpacing: 5, // Vertical spacing between rows
children: chunkedGroupByValues.map((chunk) { children: chunkedGroupByValues.expand((chunk) {
return Row( return chunk.map((group) {
mainAxisAlignment: MainAxisAlignment.center, List<String> groupByValuesList = groupByValues.toList();
children: chunk.map((group) { int index = groupByValuesList.indexOf(group);
List<String> groupByValuesList = groupByValues.toList(); Color groupColor = _getColorForGroup(index);
int index = groupByValuesList.indexOf(group);
Color groupColor = _getColorForGroup(index); return Row(
return Padding( mainAxisSize: MainAxisSize.min,
padding: const EdgeInsets.symmetric(horizontal: 5.0), children: [
child: Row( Container(
mainAxisSize: MainAxisSize.min, width: 10,
children: [ height: 10,
Container( decoration: BoxDecoration(
width: 10, color: groupColor,
height: 10, shape: BoxShape.circle,
decoration: BoxDecoration( ),
color: groupColor,
shape: BoxShape.circle,
),
),
SizedBox(width: 3),
Text(
group,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 11),
),
],
), ),
); SizedBox(width: 5),
}).toList(), Text(
); group,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 11),
),
],
);
}).toList();
}).toList(), }).toList(),
), ),
), )
], ],
); );
case 'fl_multi_bar': case 'fl_multi_bar':

View File

@ -1,424 +1,424 @@
import 'dart:convert'; // import 'dart:convert';
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:intl/intl.dart'; // import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package // import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package
import 'package:http/http.dart' as http; // import 'package:http/http.dart' as http;
//
void main() { // void main() {
runApp(MyApp()); // runApp(MyApp());
} // }
//
class MyApp extends StatelessWidget { // class MyApp extends StatelessWidget {
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return MaterialApp( // return MaterialApp(
home: ChartPage(dataSets: ''), // home: ChartPage(dataSets: ''),
); // );
} // }
} // }
//
class ChartPage extends StatefulWidget { // class ChartPage extends StatefulWidget {
final String dataSets; // final String dataSets;
const ChartPage({Key? key, required this.dataSets}); // const ChartPage({Key? key, required this.dataSets});
//
@override // @override
ChartPageState createState() => ChartPageState(); // ChartPageState createState() => ChartPageState();
} // }
//
class ChartPageState extends State<ChartPage> { // class ChartPageState extends State<ChartPage> {
List<dynamic> chartsData = []; // List<dynamic> chartsData = [];
bool isLoading = true; // bool isLoading = true;
//
@override // @override
void initState() { // void initState() {
super.initState(); // super.initState();
fetchChartData(widget.dataSets); // fetchChartData(widget.dataSets);
} // }
//
Future<void> fetchChartData(datasets) 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=$datasets'); // final url = Uri.parse('$baseUrl?dataset=$datasets');
//
try { // try {
final response = await http.get(url); // final response = await http.get(url);
if (response.statusCode == 200) { // if (response.statusCode == 200) {
setState(() { // setState(() {
chartsData = jsonDecode(response.body); // chartsData = jsonDecode(response.body);
isLoading = false; // isLoading = false;
}); // });
} else { // } else {
throw Exception('Failed to load data'); // throw Exception('Failed to load data');
} // }
} catch (error) { // } catch (error) {
setState(() { // setState(() {
isLoading = false; // isLoading = false;
}); // });
print('Error fetching data: $error'); // print('Error fetching data: $error');
} // }
} // }
//
List<ChartData> parseLineChartData(List<dynamic> response) { // List<ChartData> parseLineChartData(List<dynamic> response) {
// Group by timePeriod (year) and sum the values // // Group by timePeriod (year) and sum the values
Map<String, double> groupedData = {}; // Map<String, double> groupedData = {};
//
response.forEach((entry) { // response.forEach((entry) {
final year = entry['ObsKey']['TIME_PERIOD']?.toString() ?? 'Unknown'; // 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;
//
// Add the value to the existing year (if exists) or initialize it // // Add the value to the existing year (if exists) or initialize it
if (groupedData.containsKey(year)) { // if (groupedData.containsKey(year)) {
groupedData[year] = groupedData[year]! + value; // groupedData[year] = groupedData[year]! + value;
} else { // } else {
groupedData[year] = value; // groupedData[year] = value;
} // }
}); // });
//
// Sort the grouped data by year in ascending order // // Sort the grouped data by year in ascending order
var sortedEntries = groupedData.entries.toList() // var sortedEntries = groupedData.entries.toList()
..sort((a, b) => int.parse(a.key).compareTo(int.parse(b.key))); // ..sort((a, b) => int.parse(a.key).compareTo(int.parse(b.key)));
//
// Convert the sorted data to a list of ChartData // // Convert the sorted data to a list of ChartData
return sortedEntries // return sortedEntries
.map((entry) => ChartData( // .map((entry) => ChartData(
timePeriod: entry.key, // timePeriod: entry.key,
value: entry.value, // value: entry.value,
value1: 0.0)) // Add value1 as 0.0 // value1: 0.0)) // Add value1 as 0.0
.toList(); // .toList();
} // }
//
List<ChartData> parseBarChartData(List<dynamic> response) { // List<ChartData> parseBarChartData(List<dynamic> response) {
return response // return response
.asMap() // .asMap()
.entries // .entries
.map((entry) => ChartData( // .map((entry) => ChartData(
timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? 'Unknown', // timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? 'Unknown',
value: double.tryParse( // value: double.tryParse(
entry.value['ObsValue']['Value'].toString()) ?? // entry.value['ObsValue']['Value'].toString()) ??
0.0, // 0.0,
value1: 0.0, // Ensure value1 is passed as well // value1: 0.0, // Ensure value1 is passed as well
)) // ))
.toList(); // .toList();
} // }
//
List<ChartData> parseColumnChartData(List<dynamic> response) { // List<ChartData> parseColumnChartData(List<dynamic> response) {
List<ChartData> chartDataList = []; // List<ChartData> chartDataList = [];
//
// Temporary map to store values by TIME_PERIOD // // Temporary map to store values by TIME_PERIOD
Map<String, ChartData> timePeriodMap = {}; // Map<String, ChartData> timePeriodMap = {};
//
for (var entry in response) { // for (var entry in response) {
String timePeriod = entry['ObsKey']['TIME_PERIOD'].toString(); // String timePeriod = entry['ObsKey']['TIME_PERIOD'].toString();
double value = // double value =
double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ?? // double.tryParse(entry['ObsValue']['Value']?.toString() ?? '0.0') ??
0.0; // 0.0;
String indicator = entry['ObsKey']['H_INDICATOR']; // String indicator = entry['ObsKey']['H_INDICATOR'];
//
// If the entry is for TOR, map it to 'value' // // If the entry is for TOR, map it to 'value'
if (indicator == 'TOR') { // if (indicator == 'TOR') {
if (timePeriodMap.containsKey(timePeriod)) { // if (timePeriodMap.containsKey(timePeriod)) {
// Update the value by creating a new ChartData object // // Update the value by creating a new ChartData object
timePeriodMap[timePeriod] = ChartData( // timePeriodMap[timePeriod] = ChartData(
timePeriod: timePeriod, // timePeriod: timePeriod,
value: value, // Set the new value // value: value, // Set the new value
value1: timePeriodMap[timePeriod]?.value1 ?? 0.0, // value1: timePeriodMap[timePeriod]?.value1 ?? 0.0,
); // );
} else { // } else {
timePeriodMap[timePeriod] = ChartData( // timePeriodMap[timePeriod] = ChartData(
timePeriod: timePeriod, // timePeriod: timePeriod,
value: value, // value: value,
value1: 0.0, // value1: 0.0,
); // );
} // }
} // }
//
// If the entry is for TAR, map it to 'value1' // // If the entry is for TAR, map it to 'value1'
if (indicator == 'TAR') { // if (indicator == 'TAR') {
if (timePeriodMap.containsKey(timePeriod)) { // if (timePeriodMap.containsKey(timePeriod)) {
// Create a new ChartData object with the updated value1 // // Create a new ChartData object with the updated value1
timePeriodMap[timePeriod] = ChartData( // timePeriodMap[timePeriod] = ChartData(
timePeriod: timePeriod, // timePeriod: timePeriod,
value: timePeriodMap[timePeriod]?.value ?? // value: timePeriodMap[timePeriod]?.value ??
0.0, // Retain the current value // 0.0, // Retain the current value
value1: value, // Update the value1 // value1: value, // Update the value1
); // );
} else { // } else {
timePeriodMap[timePeriod] = ChartData( // timePeriodMap[timePeriod] = ChartData(
timePeriod: timePeriod, // timePeriod: timePeriod,
value: 0.0, // value: 0.0,
value1: value, // value1: value,
); // );
} // }
} // }
} // }
//
// Convert the map to a list // // Convert the map to a list
chartDataList = timePeriodMap.values.toList(); // chartDataList = timePeriodMap.values.toList();
//
return chartDataList; // 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 'area': // 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'), // title: ChartTitle(text: 'Hotel Estabhlishments'),
legend: Legend(isVisible: true), // legend: Legend(isVisible: true),
tooltipBehavior: TooltipBehavior( // tooltipBehavior: TooltipBehavior(
enable: true, // enable: true,
builder: (dynamic data, dynamic point, dynamic series, // builder: (dynamic data, dynamic point, dynamic series,
int pointIndex, int seriesIndex) { // int pointIndex, int seriesIndex) {
return Container( // return Container(
padding: const EdgeInsets.all(8), // padding: const EdgeInsets.all(8),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
borderRadius: BorderRadius.circular(5), // borderRadius: BorderRadius.circular(5),
), // ),
child: Text( // child: Text(
'${data.timePeriod}: ${formatNumber(data.value)}', // '${data.timePeriod}: ${formatNumber(data.value)}',
style: const TextStyle(color: Colors.black), // style: const TextStyle(color: Colors.black),
), // ),
); // );
}, // },
), // ),
series: <CartesianSeries>[ // series: <CartesianSeries>[
// AreaSeries for the area chart // // AreaSeries for the area chart
AreaSeries<ChartData, String>( // AreaSeries<ChartData, String>(
dataSource: parseLineChartData( // dataSource: parseLineChartData(
chartData['response']), // your chart data // chartData['response']), // your chart data
color: Color(0xFF7DAFBC), // Area color // color: Color(0xFF7DAFBC), // Area color
borderDrawMode: BorderDrawMode // borderDrawMode: BorderDrawMode
.excludeBottom, // Optional, adjust border settings // .excludeBottom, // Optional, adjust border settings
borderColor: Colors.green, // Border color // borderColor: Colors.green, // Border color
borderWidth: 2, // Border width // borderWidth: 2, // Border width
xValueMapper: (ChartData data, _) => // xValueMapper: (ChartData data, _) =>
data.timePeriod, // Map x to DateTime // data.timePeriod, // Map x to DateTime
yValueMapper: (ChartData data, _) => data.value, // yValueMapper: (ChartData data, _) => data.value,
// name: chartData['dataset'], // // name: chartData['dataset'],
name: 'Hotels', // name: 'Hotels',
dataLabelSettings: DataLabelSettings( // dataLabelSettings: DataLabelSettings(
isVisible: true, // isVisible: true,
builder: (dynamic data, dynamic point, dynamic series, // builder: (dynamic data, dynamic point, dynamic series,
int pointIndex, int seriesIndex) { // int pointIndex, int seriesIndex) {
return Text( // return Text(
formatNumber(data.value), // formatNumber(data.value),
style: const TextStyle(fontSize: 12, color: Colors.black), // style: const TextStyle(fontSize: 12, color: Colors.black),
); // );
}, // },
), // Map y to numerical value // ), // Map y to numerical value
) // )
]); // ]);
case 'bar': // case 'bar':
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: CategoryAxis(), // primaryXAxis: CategoryAxis(),
title: ChartTitle(text: 'Hotel Occupancy Rate'), // title: ChartTitle(text: 'Hotel Occupancy Rate'),
tooltipBehavior: TooltipBehavior( // tooltipBehavior: TooltipBehavior(
enable: true, // enable: true,
builder: (dynamic data, dynamic point, dynamic series, // builder: (dynamic data, dynamic point, dynamic series,
int pointIndex, int seriesIndex) { // int pointIndex, int seriesIndex) {
return Container( // return Container(
padding: const EdgeInsets.all(8), // padding: const EdgeInsets.all(8),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
borderRadius: BorderRadius.circular(5), // borderRadius: BorderRadius.circular(5),
), // ),
child: Text( // child: Text(
'${data.timePeriod}: ${formatNumber(data.value)}', // '${data.timePeriod}: ${formatNumber(data.value)}',
style: const TextStyle(color: Colors.black), // style: const TextStyle(color: Colors.black),
), // ),
); // );
}, // },
), // ),
series: <CartesianSeries<ChartData, String>>[ // series: <CartesianSeries<ChartData, String>>[
BarSeries<ChartData, String>( // BarSeries<ChartData, String>(
dataSource: parseBarChartData(chartData['response']), // dataSource: parseBarChartData(chartData['response']),
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: Color(0xFF7DAFBC), // 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,
int pointIndex, int seriesIndex) { // int pointIndex, int seriesIndex) {
return Text( // return Text(
formatNumber(data.value), // formatNumber(data.value),
style: const TextStyle(fontSize: 12, color: Colors.black), // style: const TextStyle(fontSize: 12, color: Colors.black),
); // );
}, // },
), // ),
// isTrackVisible: true, // // isTrackVisible: true,
// trackColor: Colors.red // // trackColor: Colors.red
), // ),
], // ],
); // );
case 'column': // case 'column':
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
), // ),
primaryYAxis: NumericAxis( // primaryYAxis: NumericAxis(
title: AxisTitle(text: 'No of rooms'), // title: AxisTitle(text: 'No of rooms'),
), // ),
legend: Legend(isVisible: true), // legend: Legend(isVisible: true),
title: ChartTitle(text: 'Hotel Occupancy Rate'), // title: ChartTitle(text: 'Hotel Occupancy Rate'),
enableSideBySideSeriesPlacement: true, // enableSideBySideSeriesPlacement: true,
tooltipBehavior: TooltipBehavior(enable: true), // tooltipBehavior: TooltipBehavior(enable: true),
series: <CartesianSeries<ChartData, int>>[ // series: <CartesianSeries<ChartData, int>>[
// First Series (value) // // First Series (value)
//
ColumnSeries<ChartData, int>( // ColumnSeries<ChartData, int>(
name: 'Available Rooms', // name: 'Available Rooms',
// opacity: 0.9, // // opacity: 0.9,
// width: 0.4, // // width: 0.4,
color: Color(0xFF587BA3), // color: Color(0xFF587BA3),
dataSource: parseColumnChartData(chartData['response']), // dataSource: parseColumnChartData(chartData['response']),
xValueMapper: (ChartData data, _) => int.parse(data.timePeriod), // xValueMapper: (ChartData data, _) => int.parse(data.timePeriod),
yValueMapper: (ChartData data, _) => data.value1, // yValueMapper: (ChartData data, _) => data.value1,
), // ),
// Second Series (value1) // // Second Series (value1)
ColumnSeries<ChartData, int>( // ColumnSeries<ChartData, int>(
color: Color(0xFF90B0D5), // color: Color(0xFF90B0D5),
name: 'Occupied Rooms', // name: 'Occupied Rooms',
dataSource: parseColumnChartData(chartData['response']), // dataSource: parseColumnChartData(chartData['response']),
xValueMapper: (ChartData data, _) => int.parse(data.timePeriod), // xValueMapper: (ChartData data, _) => int.parse(data.timePeriod),
yValueMapper: (ChartData data, _) => data.value, // yValueMapper: (ChartData data, _) => data.value,
), // ),
], // Numeric Y-axis to plot the values // ], // Numeric Y-axis to plot the values
); // );
default: // default:
return Center(child: Text('Unknown chart type')); // return Center(child: Text('Unknown chart type'));
} // }
} // }
//
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return Scaffold( // return Scaffold(
backgroundColor: const Color(0xFF7DAFBC), // backgroundColor: const Color(0xFF7DAFBC),
appBar: AppBar( // appBar: AppBar(
backgroundColor: const Color(0xFF7DAFBC), // backgroundColor: const Color(0xFF7DAFBC),
elevation: 0, // elevation: 0,
leading: IconButton( // leading: IconButton(
icon: const 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: const Text( // title: const Text(
'Charts', // 'Charts',
style: TextStyle(color: Colors.white), // style: TextStyle(color: Colors.white),
), // ),
), // ),
body: isLoading // body: isLoading
? const Center(child: CircularProgressIndicator()) // ? const Center(child: CircularProgressIndicator())
: Column( // : Column(
children: [ // children: [
Card( // Card(
margin: const EdgeInsets.all(10), // margin: const EdgeInsets.all(10),
color: Colors.white, // 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: const [ // children: const [
Text( // Text(
'Card 1 Title', // 'Card 1 Title',
style: TextStyle( // style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold), // fontSize: 18, fontWeight: FontWeight.bold),
), // ),
SizedBox(height: 10), // SizedBox(height: 10),
Text('Content for the first card goes here.'), // Text('Content for the first card goes here.'),
], // ],
), // ),
), // ),
), // ),
Card( // Card(
margin: const EdgeInsets.all(10), // margin: const EdgeInsets.all(10),
color: Colors.white, // 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: const [ // children: const [
Text( // Text(
'Card 2 Title', // 'Card 2 Title',
style: TextStyle( // style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold), // fontSize: 18, fontWeight: FontWeight.bold),
), // ),
SizedBox(height: 10), // SizedBox(height: 10),
Text('Content for the second card goes here.'), // Text('Content for the second card goes here.'),
], // ],
), // ),
), // ),
), // ),
Expanded( // Expanded(
child: ListView.builder( // child: ListView.builder(
itemCount: chartsData.length, // itemCount: chartsData.length,
itemBuilder: (context, index) { // itemBuilder: (context, index) {
return Card( // return Card(
margin: const EdgeInsets.all(10), // margin: const EdgeInsets.all(10),
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: [
Container( // Container(
height: 300, // height: 300,
child: buildChart(chartsData[index]), // child: buildChart(chartsData[index]),
), // ),
], // ],
), // ),
), // ),
); // );
}, // },
), // ),
), // ),
], // ],
), // ),
); // );
} // }
} // }
//
class ChartData { // class ChartData {
final String timePeriod; // final String timePeriod;
final double value; // final double value;
final double value1; // final double value1;
final String formattedValue; // final String formattedValue;
//
ChartData( // ChartData(
{required this.timePeriod, required this.value, required this.value1}) // {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
// } // }
String formatNumber(double value) {
if (value >= 1e9) {
return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions
} else if (value >= 1e6) {
return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions
}
return value
.toStringAsFixed(2); // Default to two decimal places for smaller numbers
}

View File

@ -1,328 +1,328 @@
import 'dart:convert'; // import 'dart:convert';
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:intl/intl.dart'; // import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package // import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package
import 'package:http/http.dart' as http; // import 'package:http/http.dart' as http;
//
void main() { // void main() {
runApp(MyApp()); // runApp(MyApp());
} // }
//
class MyApp extends StatelessWidget { // class MyApp extends StatelessWidget {
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return MaterialApp( // return MaterialApp(
home: ChartPage2(dataSets: ''), // home: ChartPage2(dataSets: ''),
); // );
} // }
} // }
//
class ChartPage2 extends StatefulWidget { // class ChartPage2 extends StatefulWidget {
final String dataSets; // final String dataSets;
const ChartPage2({Key? key, required this.dataSets}); // const ChartPage2({Key? key, required this.dataSets});
@override // @override
ChartPageState createState() => ChartPageState(); // ChartPageState createState() => ChartPageState();
} // }
//
class ChartPageState extends State<ChartPage2> { // class ChartPageState extends State<ChartPage2> {
List<dynamic> chartsData = []; // List<dynamic> chartsData = [];
bool isLoading = true; // bool isLoading = true;
//
@override // @override
void initState() { // void initState() {
super.initState(); // super.initState();
fetchChartData(widget.dataSets); // fetchChartData(widget.dataSets);
} // }
//
Future<void> fetchChartData(dataSets) 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=$dataSets'); // final url = Uri.parse('$baseUrl?dataset=$dataSets');
//
try { // try {
final response = await http.get(url); // final response = await http.get(url);
if (response.statusCode == 200) { // if (response.statusCode == 200) {
setState(() { // setState(() {
chartsData = jsonDecode(response.body); // chartsData = jsonDecode(response.body);
isLoading = false; // isLoading = false;
}); // });
} else { // } else {
throw Exception('Failed to load data'); // throw Exception('Failed to load data');
} // }
} catch (error) { // } catch (error) {
setState(() { // setState(() {
isLoading = false; // isLoading = false;
}); // });
print('Error fetching data: $error'); // print('Error fetching data: $error');
} // }
} // }
//
List<ChartData> parseLineChartData(List<dynamic> response) { // List<ChartData> parseLineChartData(List<dynamic> response) {
return response.map((entry) { // return response.map((entry) {
// Attempt to fetch the TIMEPERIOD // // Attempt to fetch the TIMEPERIOD
final rawTimePeriod = // final rawTimePeriod =
entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD']; // entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD'];
final formattedTimePeriod = rawTimePeriod != null // final formattedTimePeriod = rawTimePeriod != null
? rawTimePeriod.toString() // Use as-is if valid // ? rawTimePeriod.toString() // Use as-is if valid
: 'Unknown'; // Fallback value if null // : 'Unknown'; // Fallback value if null
//
// Parse the value or fallback to 0.0 // // Parse the value or fallback to 0.0
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( // return ChartData(
timePeriod: formattedTimePeriod, // timePeriod: formattedTimePeriod,
value: value, // value: value,
); // );
}).toList(); // }).toList();
} // }
//
List<ChartData> parseBarChartData(List<dynamic> response) { // List<ChartData> parseBarChartData(List<dynamic> response) {
return response // return response
.asMap() // .asMap()
.entries // .entries
.map((entry) => ChartData( // .map((entry) => ChartData(
timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? // timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ??
'Unknown', // Fallback to 'Unknown' if null // '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, // Handle null/invalid value
)) // ))
.toList(); // .toList();
} // }
//
// Update parseColumnChartData for column chart // // Update parseColumnChartData for column chart
List<ChartData> parseColumnChartData(List<dynamic> response) { // List<ChartData> parseColumnChartData(List<dynamic> response) {
return response.map((entry) { // return response.map((entry) {
// Extract TIME_PERIOD as x // // Extract TIME_PERIOD as x
final x = // final x =
int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0; // int.tryParse(entry['ObsKey']?['TIME_PERIOD']?.toString() ?? '0') ?? 0;
// Extract Value as y // // Extract Value as y
final y = // final y =
double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? // double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ??
0.0; // 0.0;
return ChartData(xInt: x, y: y); // return ChartData(xInt: x, y: y);
}).toList(); // }).toList();
} // }
//
// Update parseScatterChartData for scatter chart // // Update parseScatterChartData for scatter chart
List<ChartData> parseScatterChartData(List<dynamic> response) { // List<ChartData> parseScatterChartData(List<dynamic> response) {
return response.map((entry) { // return response.map((entry) {
// Parse TIME_PERIOD into DateTime // // Parse TIME_PERIOD into DateTime
final timePeriod = entry['ObsKey']?['TIME_PERIOD']; // final timePeriod = entry['ObsKey']?['TIME_PERIOD'];
final x = timePeriod != null // final x = timePeriod != null
? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime // ? DateTime.tryParse('$timePeriod-01-01') // Convert year to DateTime
: DateTime.now(); // Fallback to current date if null // : DateTime.now(); // Fallback to current date if null
//
// Parse Value into double // // Parse Value into double
final y = // final y =
double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? // double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ??
0.0; // 0.0;
//
return ChartData(xDateTime: x, y: y); // return ChartData(xDateTime: x, y: y);
}).toList(); // }).toList();
} // }
//
Widget buildChart(dynamic chartData) { // Widget buildChart(dynamic chartData) {
switch (chartData['chart_type']) { // switch (chartData['chart_type']) {
case 'scatter': // case 'scatter':
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis // primaryXAxis: DateTimeAxis(), // Ensure it's DateTimeAxis
tooltipBehavior: TooltipBehavior(enable: true), // tooltipBehavior: TooltipBehavior(enable: true),
title: ChartTitle(text: 'Divorces'), // title: ChartTitle(text: 'Divorces'),
series: <CartesianSeries>[ // series: <CartesianSeries>[
ScatterSeries<ChartData, DateTime>( // ScatterSeries<ChartData, DateTime>(
dataSource: parseScatterChartData(chartData['response']), // dataSource: parseScatterChartData(chartData['response']),
xValueMapper: (ChartData data, _) => // xValueMapper: (ChartData data, _) =>
data.xDateTime ?? DateTime.now(), // data.xDateTime ?? DateTime.now(),
yValueMapper: (ChartData data, _) => data.y, // yValueMapper: (ChartData data, _) => data.y,
name: chartData['dataset'], // name: chartData['dataset'],
dataLabelSettings: DataLabelSettings(isVisible: true), // dataLabelSettings: DataLabelSettings(isVisible: true),
), // ),
], // ],
); // );
case 'column': // case 'column':
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: NumericAxis( // primaryXAxis: NumericAxis(
title: AxisTitle(text: 'Year'), // title: AxisTitle(text: 'Year'),
interval: 1, // Ensure no fractional intervals // interval: 1, // Ensure no fractional intervals
), // ),
title: ChartTitle(text: 'Marriages'), // title: ChartTitle(text: 'Marriages'),
series: <CartesianSeries<ChartData, int>>[ // series: <CartesianSeries<ChartData, int>>[
ColumnSeries<ChartData, int>( // ColumnSeries<ChartData, int>(
dataSource: parseColumnChartData(chartData['response']), // dataSource: parseColumnChartData(chartData['response']),
xValueMapper: (ChartData data, _) => data.xInt ?? 0, // xValueMapper: (ChartData data, _) => data.xInt ?? 0,
yValueMapper: (ChartData data, _) => data.y, // yValueMapper: (ChartData data, _) => data.y,
name: chartData['dataset'], // name: chartData['dataset'],
color: Color(0xFF7DAFBC), // color: Color(0xFF7DAFBC),
width: 0.8, // width: 0.8,
spacing: 0.2, // spacing: 0.2,
dataLabelSettings: // dataLabelSettings:
DataLabelSettings(isVisible: true), // Show data labels // DataLabelSettings(isVisible: true), // Show data labels
), // ),
], // ],
); // );
//
case 'line': // case 'line':
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: CategoryAxis(), // primaryXAxis: CategoryAxis(),
title: ChartTitle(text: 'Line Chart'), // title: ChartTitle(text: 'Line Chart'),
legend: Legend(isVisible: true), // legend: Legend(isVisible: true),
tooltipBehavior: TooltipBehavior(enable: true), // tooltipBehavior: TooltipBehavior(enable: true),
series: <CartesianSeries<ChartData, String>>[ // series: <CartesianSeries<ChartData, String>>[
LineSeries<ChartData, String>( // LineSeries<ChartData, String>(
dataSource: parseLineChartData(chartData['response']), // dataSource: parseLineChartData(chartData['response']),
xValueMapper: (ChartData data, _) => data.timePeriod ?? '', // xValueMapper: (ChartData data, _) => data.timePeriod ?? '',
yValueMapper: (ChartData data, _) => data.value ?? 0.0, // yValueMapper: (ChartData data, _) => data.value ?? 0.0,
name: 'Sales', // name: 'Sales',
dataLabelSettings: DataLabelSettings(isVisible: true), // dataLabelSettings: DataLabelSettings(isVisible: true),
), // ),
], // ],
); // );
case 'bar': // case 'bar':
return SfCartesianChart( // return SfCartesianChart(
primaryXAxis: CategoryAxis(), // primaryXAxis: CategoryAxis(),
title: ChartTitle(text: 'Bar Chart'), // title: ChartTitle(text: 'Bar Chart'),
tooltipBehavior: TooltipBehavior(enable: true), // tooltipBehavior: TooltipBehavior(enable: true),
series: <CartesianSeries<ChartData, String>>[ // series: <CartesianSeries<ChartData, String>>[
BarSeries<ChartData, String>( // BarSeries<ChartData, String>(
dataSource: parseBarChartData(chartData['response']), // dataSource: parseBarChartData(chartData['response']),
xValueMapper: (ChartData data, _) => data.timePeriod ?? '', // xValueMapper: (ChartData data, _) => data.timePeriod ?? '',
yValueMapper: (ChartData data, _) => data.value ?? 0.0, // yValueMapper: (ChartData data, _) => data.value ?? 0.0,
name: 'Gold', // name: 'Gold',
color: Color.fromRGBO(8, 142, 255, 1), // color: Color.fromRGBO(8, 142, 255, 1),
), // ),
], // ],
); // );
//
default: // default:
return Center(child: Text('Unknown chart type')); // return Center(child: Text('Unknown chart type'));
} // }
} // }
//
@override // @override
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return Scaffold( // return Scaffold(
backgroundColor: const Color(0xFF7DAFBC), // backgroundColor: const Color(0xFF7DAFBC),
appBar: AppBar( // appBar: AppBar(
backgroundColor: Color(0xFF7DAFBC), // backgroundColor: Color(0xFF7DAFBC),
elevation: 0, // elevation: 0,
leading: IconButton( // leading: IconButton(
icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), // icon: Icon(Icons.arrow_back_ios_new, color: Colors.white),
onPressed: () { // onPressed: () {
context.go('/myhomepage'); // context.go('/myhomepage');
}, // },
), // ),
title: Text( // title: Text(
'Charts', // 'Charts',
style: TextStyle(color: Colors.white), // style: TextStyle(color: Colors.white),
), // ),
), // ),
body: isLoading // body: isLoading
? Center(child: CircularProgressIndicator()) // ? Center(child: CircularProgressIndicator())
: Column( // : Column(
children: [ // children: [
// Row for two cards // // Row for two cards
Row( // Row(
children: [ // children: [
// First Card // // First Card
Expanded( // Expanded(
flex: 6, // flex: 6,
child: Card( // child: Card(
margin: EdgeInsets.all(10), // margin: EdgeInsets.all(10),
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: [
Text( // Text(
'Card 1', // 'Card 1',
style: TextStyle( // style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold), // fontSize: 18, fontWeight: FontWeight.bold),
), // ),
SizedBox(height: 10), // SizedBox(height: 10),
Text('Content for Card 1 goes here.'), // Text('Content for Card 1 goes here.'),
], // ],
), // ),
), // ),
), // ),
), // ),
// Second Card // // Second Card
Expanded( // Expanded(
flex: 6, // flex: 6,
child: Card( // child: Card(
margin: EdgeInsets.all(10), // margin: EdgeInsets.all(10),
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: [
Text( // Text(
'Card 2', // 'Card 2',
style: TextStyle( // style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold), // fontSize: 18, fontWeight: FontWeight.bold),
), // ),
SizedBox(height: 10), // SizedBox(height: 10),
Text('Content for Card 2 goes here.'), // Text('Content for Card 2 goes here.'),
], // ],
), // ),
), // ),
), // ),
), // ),
], // ],
), // ),
// List of charts // // List of charts
Expanded( // Expanded(
child: ListView.builder( // child: ListView.builder(
itemCount: chartsData.length, // itemCount: chartsData.length,
itemBuilder: (context, index) { // itemBuilder: (context, index) {
return Card( // return Card(
margin: EdgeInsets.all(10), // margin: EdgeInsets.all(10),
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: [
SizedBox(height: 10), // SizedBox(height: 10),
Container( // Container(
height: 300, // height: 300,
child: buildChart(chartsData[index]), // child: buildChart(chartsData[index]),
), // ),
], // ],
), // ),
), // ),
); // );
}, // },
), // ),
), // ),
], // ],
), // ),
); // );
} // }
} // }
//
class ChartData { // class ChartData {
final int? xInt; // For column and other charts, using int for x // final int? xInt; // For column and other charts, using int for x
final DateTime? xDateTime; // For scatter charts, using DateTime for x // final DateTime? xDateTime; // For scatter charts, using DateTime for x
final double y; // For column and other charts // final double y; // For column and other charts
final String? timePeriod; // For line and bar charts // final String? timePeriod; // For line and bar charts
final double? value; // For line and bar charts // final double? value; // For line and bar charts
final double? y2; // For secondary data (stacked column chart) // final double? y2; // For secondary data (stacked column chart)
final double? y3; // For tertiary data (stacked column chart) // final double? y3; // For tertiary data (stacked column chart)
final double? y4; // For quaternary data (stacked column chart) // final double? y4; // For quaternary data (stacked column chart)
//
// Constructor that handles all chart cases // // Constructor that handles all chart cases
ChartData({ // ChartData({
this.xInt, // this.xInt,
this.xDateTime, // this.xDateTime,
this.y = 0.0, // this.y = 0.0,
this.timePeriod, // this.timePeriod,
this.value, // this.value,
this.y2, // this.y2,
this.y3, // this.y3,
this.y4, // this.y4,
}); // });
} // }

View File

@ -37,6 +37,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
true true
]; // One for each TextField ]; // One for each TextField
bool _isLoading = false;
String _getControllerText(int index) { String _getControllerText(int index) {
if (index == 0) return _usernameController.text; if (index == 0) return _usernameController.text;
if (index == 1) return _emailController.text; if (index == 1) return _emailController.text;
@ -169,6 +171,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Function to open the date picker // Function to open the date picker
void _pickImage() async { void _pickImage() async {
setState(() {
_isLoading = true; // Start loading
});
final XFile? pickedFile = final XFile? pickedFile =
await _picker.pickImage(source: ImageSource.gallery); await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) { if (pickedFile != null) {
@ -179,6 +184,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
fileExtension == 'png' || fileExtension == 'png' ||
fileExtension == "heic") { fileExtension == "heic") {
setState(() { setState(() {
_isLoading = false;
_profileImage = File(pickedFile.path); _profileImage = File(pickedFile.path);
}); });
} else { } else {
@ -365,28 +371,68 @@ class _ProfileScreenState extends State<ProfileScreen> {
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: Column( child: Column(
children: [ children: [
CircleAvatar( // CircleAvatar(
radius: 50, // radius: 50,
backgroundImage: _profileImage != null // backgroundImage: _profileImage != null
? FileImage(_profileImage!) // ? FileImage(_profileImage!)
: AssetImage("assets/edit_profile/profile.png") // : AssetImage("assets/edit_profile/profile.png")
as ImageProvider, // as ImageProvider,
child: Align( // child: Align(
alignment: Alignment.bottomRight, // alignment: Alignment.bottomRight,
child: GestureDetector( // child: GestureDetector(
onTap: _pickImage, // Call `_pickImage` on tap // onTap: _pickImage, // Call `_pickImage` on tap
child: CircleAvatar( // child: CircleAvatar(
radius: 15, // radius: 15,
backgroundColor: Colors.white, // backgroundColor: Colors.white,
child: Icon( // child: Icon(
Icons.camera_alt, // Icons.camera_alt,
size: 15, // size: 15,
color: Colors.grey, // color: Colors.grey,
// ),
// ),
// ),
// ),
// ),
Stack(
alignment: Alignment.center,
children: [
// CircleAvatar with the profile image
CircleAvatar(
radius: 50,
backgroundImage: _profileImage != null
? FileImage(_profileImage!)
: AssetImage("assets/edit_profile/profile.png")
as ImageProvider,
child: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
onTap: _pickImage, // Call `_pickImage` on tap
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Icon(
Icons.camera_alt,
size: 15,
color: Colors.grey,
),
),
), ),
), ),
), ),
),
// Conditional loader that shows when _isLoading is true
if (_isLoading)
Positioned(
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(Colors.grey),
),
),
],
), ),
SizedBox(height: 20), SizedBox(height: 20),
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,

View File

@ -160,9 +160,13 @@
// ); // );
// } // }
// } // }
import 'dart:convert';
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 '../../drawer_routes/custom_drawer_routes.dart'; import '../../drawer_routes/custom_drawer_routes.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:http/http.dart' as http;
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
const MyHomePage({super.key}); const MyHomePage({super.key});
@ -171,18 +175,28 @@ class MyHomePage extends StatefulWidget {
State<MyHomePage> createState() => _MyHomePageState(); State<MyHomePage> createState() => _MyHomePageState();
} }
void handleInfoCardClick(BuildContext context, String data) { void handleInfoCardClick(BuildContext context, String data, Color color) {
// Handle navigation and pass dynamic data // Handle navigation and pass dynamic data
print(data); print(data);
final dataSets = data; final dataSets = data;
print(dataSets); if (dataSets != null) {
if (dataSets == 'hotels') { // Perform navigation
context.go('/chartScreen/$dataSets');
} else if (dataSets == 'divorces') {
context.go('/chartScreen/$dataSets');
} else if (dataSets == 'marriages') {
context.go('/chartScreen/$dataSets'); context.go('/chartScreen/$dataSets');
} else {
// Show error if dataSet is null
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('No dataset available')),
);
} }
// final dataSets = data;
// print(dataSets);
// if (dataSets == 'hotels') {
// context.go('/chartScreen/$dataSets');
// } else if (dataSets == 'divorces') {
// context.go('/chartScreen/$dataSets');
// } else if (dataSets == 'marriages') {
// context.go('/Chart/$dataSets');
// }
} }
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
@ -191,243 +205,242 @@ class _MyHomePageState extends State<MyHomePage> {
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
return BaseScaffold( return BaseScaffold(
mycenterTitle: true, title: Center(
title: SizedBox( child: SizedBox(
height: myheight / 5, height: myheight / 5,
width: mywidth / 3, width: mywidth / 3,
child: Image(image: AssetImage('assets/logos/uae_stat.png'))), child: Image(image: AssetImage('assets/logos/uae_stat.png')))),
body: EconomyStats(), body: EconomyStatsWidget(),
); );
} }
} }
class EconomyStats extends StatelessWidget { class EconomyStatsWidget extends StatefulWidget {
const EconomyStats({Key? key}) : super(key: key); const EconomyStatsWidget({super.key});
@override @override
EconomyStatsState createState() => EconomyStatsState();
}
class EconomyStatsState extends State<EconomyStatsWidget> {
List<dynamic> data = [];
bool isLoading = true;
void initState() {
fetchData();
}
Future<void> fetchData() async {
const baseUrl = 'https://pb.venbait.in/api/getHomePageData';
try {
final response = await http.get(Uri.parse(baseUrl));
if (response.statusCode == 200) {
setState(() {
data = json.decode(response.body);
print("HomeDAta $data");
isLoading = false;
});
} else {
throw Exception('Failed to load data');
}
} catch (e) {
setState(() {
isLoading = false;
});
print('Error fetching data: $e');
}
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( double myheight = MediaQuery.of(context).size.height;
child: Padding( double mywidth = MediaQuery.of(context).size.width;
padding: EdgeInsets.only(left: 10, right: 10),
child: Column(
children: [
// Header Section
RoundedCornerContainer(
text: 'ECONOMY',
backgroundColor: Color(0xFF7DAFBC),
textStyle: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
// Grid Section
// ECONOMY DETAILS return Expanded(
Padding( child: Container(
padding: const EdgeInsets.only( height: myheight,
top: 10, // color: Colors.cyan,
), child: Padding(
child: Column( padding: EdgeInsets.only(left: 10, right: 10),
children: [ child: Column(
// First Row children: data.map((mainTopic) {
Row( String colorPattern = mainTopic['color_pattern'];
mainAxisAlignment: MainAxisAlignment.spaceEvenly, Color backgroundColor = Color(int.parse(colorPattern));
Color borderColor =
backgroundColor; // Use the same color for the border
// final totalTiles = mainTopic['sub_topics']
// .expand((subTopic) => (subTopic['tile_data'] as List<dynamic>? ?? []))
// .length;
final totalTiles =
(mainTopic['tile_data'] as List<dynamic>?)?.length ?? 0;
// Compute crossAxisCount dynamically
final crossAxisCount =
(totalTiles / 2).ceil(); // Divide by 2 and round up
return Expanded(
child: Container(
// color: Colors.cyan,
height:
myheight, // Set the background color for the entire Column
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
InfoCard( RoundedCornerContainer(
title: 'GDP (Constant)', text: mainTopic['main_topic'],
subtitle: '(2022) (AED)', backgroundColor: backgroundColor,
value: '1.62T', textStyle: const TextStyle(
bordercolor: Color(0xFF7DAFBC), fontSize: 24,
textcolor: Color(0xFF7DAFBC), fontWeight: FontWeight.w500,
onTap: () => handleInfoCardClick(context, 'Inflation'), color: Colors.white,
),
), ),
InfoCard( SizedBox(
title: 'Inflation Rate', height: myheight / 4.8, // Set dynamic height
subtitle: '(2022)', child: Container(
value: '4.82%', // color: Colors.grey[200], // Set a background color for the scrollable container
bordercolor: Color(0xFF7DAFBC), child: ConstrainedBox(
textcolor: Color(0xFF7DAFBC), constraints: BoxConstraints(
onTap: () => handleInfoCardClick(context, 'Inflation'), maxWidth: MediaQuery.of(context).size.width * 2,
),
child: MasonryGridView.builder(
gridDelegate:
SliverSimpleGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
),
physics: const NeverScrollableScrollPhysics(),
itemCount: totalTiles,
itemBuilder: (context, index) {
final tileDataList = (mainTopic['tile_data']
as List<dynamic>?) ??
[];
final tileData = Map<String, String>.from(
tileDataList[index]);
return Container(
margin: const EdgeInsets.all(0),
height: myheight /
9.2, // Variable height for tiles
width: mywidth / 3,
padding:
const EdgeInsets.only(bottom: 3, top: 3),
// color: Colors.yellowAccent.shade100, // Tile background color
child: Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: _buildRows(
[tileData],
borderColor,
mainTopic['color_pattern']),
),
),
);
},
),
),
),
), ),
], ],
), ),
const SizedBox(height: 10), ),
// Second Row );
Row( }).toList(),
mainAxisAlignment: MainAxisAlignment.spaceEvenly, ),
children: [
InfoCard(
title: 'Trade Value',
subtitle: '(Jan - Jan 2024) - AED',
value: '215.4B',
bordercolor: Color(0xFF7DAFBC),
textcolor: Color(0xFF7DAFBC),
onTap: () =>
handleInfoCardClick(context, 'commodities'),
),
InfoCard(
title: 'Hotel Guests',
subtitle: '(2022)',
value: '25.21M',
bordercolor: Color(0xFF7DAFBC),
textcolor: Color(0xFF7DAFBC),
onTap: () => handleInfoCardClick(context, 'hotels'),
),
],
),
const SizedBox(height: 10),
RoundedCornerContainer(
text: 'SOCIAL',
backgroundColor: Colors.brown[200]!,
textStyle: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
// SOCIAL DETAILS
Padding(
padding: const EdgeInsets.only(
top: 10,
),
child: Column(
children: [
// First Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
InfoCard(
title: 'Divorces',
subtitle: '(2022)',
value: '0',
bordercolor: Colors.brown[200]!,
textcolor: Colors.brown[200]!,
onTap: () =>
handleInfoCardClick(context, 'divorces'),
),
InfoCard(
title: 'Marriages',
subtitle: '(2022)',
value: '0',
bordercolor: Colors.brown[200]!,
textcolor: Colors.brown[200]!,
onTap: () =>
handleInfoCardClick(context, 'marriages'),
),
],
),
const SizedBox(height: 10),
// Second Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
InfoCard(
title: 'Hospitals (Gov)',
subtitle: '(Jan - Jan 2024) - AED',
value: '215.4B',
bordercolor: Colors.brown[200]!,
textcolor: Colors.brown[200]!,
onTap: () =>
handleInfoCardClick(context, 'Hospitals'),
),
InfoCard(
title: 'Schools',
subtitle: '(2022)',
value: '25.21M',
bordercolor: Colors.brown[200]!,
textcolor: Colors.brown[200]!,
onTap: () =>
handleInfoCardClick(context, 'Schools'),
),
],
),
const SizedBox(height: 10),
RoundedCornerContainer(
text: 'ENVIRONMENT',
backgroundColor: Color(0xFF7DAFBC),
textStyle: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
// ENVIRONMENT DETAILS
Padding(
padding: const EdgeInsets.only(
top: 10,
),
child: Column(
children: [
// First Row
Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
InfoCard(
title: 'Electricity',
subtitle: '(2022) (AED)',
value: '1.62T',
bordercolor: Color(0xFF7DAFBC),
textcolor: Color(0xFF7DAFBC),
onTap: () => handleInfoCardClick(
context, 'Electricity'),
),
InfoCard(
title: 'Cruid oil',
subtitle: '(2022)',
value: '4.82%',
bordercolor: Color(0xFF7DAFBC),
textcolor: Color(0xFF7DAFBC),
onTap: () =>
handleInfoCardClick(context, 'Cruid'),
),
],
),
const SizedBox(height: 10),
// Second Row
Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
InfoCard(
title: 'Export of oil',
subtitle: '(Jan - Jan 2024) - AED',
value: '215.4B',
bordercolor: Color(0xFF7DAFBC),
textcolor: Color(0xFF7DAFBC),
onTap: () =>
handleInfoCardClick(context, 'Export'),
),
InfoCard(
title: 'Desalinated water',
subtitle: '(2022)',
value: '25.21M',
bordercolor: Color(0xFF7DAFBC),
textcolor: Color(0xFF7DAFBC),
onTap: () => handleInfoCardClick(
context, 'Desalinated'),
),
],
),
],
),
),
],
),
),
],
),
),
],
), ),
), ),
); );
} }
} }
//
// List<Widget> _buildRows(List<Map<String, String>> tileData, Color borderColor) {
//
//
// List<Widget> rows = [];
//
//
// for (int i = 0; i < tileData.length; i += 2) {
// // Adding a row for every two items
// rows.add(
// Container(
// // color: Colors.grey[200], // Set background color for the row
// // padding: EdgeInsets.symmetric(vertical: 7.0), // Optional padding
// padding: EdgeInsets.only(top:5, bottom:2),
// child: Expanded(
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// children: tileData
// .sublist(i, i + 2 > tileData.length ? tileData.length : i + 2)
// .map((tile) {
// return Expanded(
// child: InfoCard(
// title: tile['data_set_tile_heading']!,
// subtitle: tile['value_source']!,
// value: tile['value']!,
// dataset:tile['data_set']!,
// bordercolor: borderColor,
// textcolor: borderColor,
// backgroundColor: Colors.white, // Set background color for InfoCard
// onTap: () => {},
//
// ),
// );
// }).toList(),
// ),
// ),
// ),
// );
// // rows.add(SizedBox(height: 1)); // Add space between rows
// }
//
// return rows;
// }
List<Widget> _buildRows(
List<Map<String, dynamic>> tileData, Color borderColor, color_pattern) {
// Sort the tileData list based on 'data_set_list_order'
// tileData.sort((a, b) => a['data_set_list_order'].compareTo(b['data_set_list_order']));
tileData.sort((a, b) =>
(a['data_set_list_order'] ?? 0).compareTo(b['data_set_list_order'] ?? 0));
List<Widget> rows = [];
print('tileDataLength: $tileData.length');
for (int i = 0; i < tileData.length; i += 2) {
// Adding a row for every two items
rows.add(
Container(
padding: EdgeInsets.only(top: 5, bottom: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: tileData
.sublist(i, i + 2 > tileData.length ? tileData.length : i + 2)
.map((tile) {
return Expanded(
child: InfoCard(
title: tile['data_set_tile_heading']!,
subtitle: tile['value_source']!,
value: tile['value']!,
dataset: tile['data_set']!,
bordercolor: borderColor,
textcolor: borderColor,
backgroundColor:
Colors.white, // Set background color for InfoCard
onTap: () {},
),
);
}).toList(),
),
),
);
}
return rows;
}
class RoundedCornerContainer extends StatelessWidget { class RoundedCornerContainer extends StatelessWidget {
final String text; final String text;
final Color backgroundColor; final Color backgroundColor;
@ -445,7 +458,7 @@ class RoundedCornerContainer extends StatelessWidget {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: backgroundColor, color: backgroundColor,
borderRadius: BorderRadius.circular(12), // Rounded corners borderRadius: BorderRadius.circular(16), // Rounded corners
), ),
child: Center( child: Center(
child: Text( child: Text(
@ -466,18 +479,22 @@ class InfoCard extends StatelessWidget {
final String title; final String title;
final String subtitle; final String subtitle;
final String value; final String value;
final String dataset;
final Color bordercolor; final Color bordercolor;
final Color? textcolor; final Color? textcolor;
final VoidCallback onTap; // New callback parameter final VoidCallback onTap;
final Color backgroundColor;
const InfoCard({ const InfoCard({
Key? key, Key? key,
required this.title, required this.title,
required this.subtitle, required this.subtitle,
required this.value, required this.value,
required this.dataset,
required this.bordercolor, required this.bordercolor,
this.textcolor, this.textcolor,
required this.onTap, // Initialize in constructor required this.onTap,
required this.backgroundColor,
}) : super(key: key); }) : super(key: key);
@override @override
@ -485,50 +502,84 @@ class InfoCard extends StatelessWidget {
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
return Expanded( return GestureDetector(
child: GestureDetector( onTap: () {
onTap: onTap, // Use callback for handling clicks // Call handleInfoCardClick and pass the title and color
child: Container( handleInfoCardClick(
height: myheight / 9, context, dataset, bordercolor); // Pass 'title' to the function
width: mywidth / 4, },
margin: const EdgeInsets.symmetric(horizontal: 8), child: Container(
decoration: BoxDecoration( height: myheight / 12,
border: Border.all(color: bordercolor),
borderRadius: BorderRadius.circular(8), width: mywidth / 4,
),
child: Column( margin: const EdgeInsets.symmetric(horizontal: 8),
mainAxisSize: MainAxisSize.min, // padding: const EdgeInsets.all(10),
children: [ padding: const EdgeInsets.only(bottom: 1, top: 1, left: 10, right: 10),
Expanded( decoration: BoxDecoration(
child: Text( border: Border.all(color: bordercolor),
title, borderRadius: BorderRadius.circular(8),
style: const TextStyle( ),
fontSize: 16, child: Column(
fontWeight: FontWeight.bold, mainAxisSize: MainAxisSize.min,
color: Colors.black, mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain, // Adjust text to fit within the bounds
child: Padding(
// padding: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 4, bottom: 0),
child: Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black,
),
), ),
), ),
), ),
const SizedBox(height: 2), ),
Text( const SizedBox(height: 0.5),
subtitle,
textAlign: TextAlign.center, Flexible(
style: const TextStyle( fit: FlexFit.loose,
fontSize: 12, child: FittedBox(
color: Colors.grey, fit: BoxFit.contain,
child: Column(
children: [
Text(
subtitle,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 8,
color: Colors.grey,
),
),
],
), ),
), ),
const SizedBox(height: 2), ),
Text( const SizedBox(height: 1),
value,
style: TextStyle( // Flexible(
fontSize: 24, // fit: FlexFit.loose,
fontWeight: FontWeight.bold, // child: FittedBox(
color: textcolor ?? Colors.black, // fit: BoxFit.scaleDown,
), // child:
Text(
value,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: textcolor ?? Colors.black,
), ),
], ),
), // ),
// ),
],
), ),
), ),
); );

View File

@ -23,6 +23,7 @@ class _EditProfileState extends State<EditProfile> {
final _pb = PocketBase('https://pb.venbait.in'); final _pb = PocketBase('https://pb.venbait.in');
// final _pb = PocketBase('http://127.0.0.1:8090'); // final _pb = PocketBase('http://127.0.0.1:8090');
bool _isProfileCompleted = false; bool _isProfileCompleted = false;
bool _isLoading = false;
// Add focus nodes and hint states // Add focus nodes and hint states
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode()); final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
@ -207,16 +208,30 @@ class _EditProfileState extends State<EditProfile> {
// Function to open the date picker // Function to open the date picker
void _pickImage() async { void _pickImage() async {
// setState(() {
// _isLoading = true; // Show loader
// print("Im Loading");
// });
//
// // Simulate an image loading process or network request
// await Future.delayed(Duration(seconds: 8)); // Example delay
final XFile? pickedFile = final XFile? pickedFile =
await _picker.pickImage(source: ImageSource.gallery); await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) { if (pickedFile != null) {
setState(() {
_isLoading = true; // Start loading
});
print(pickedFile);
final String fileExtension = final String fileExtension =
pickedFile.path.split('.').last.toLowerCase(); pickedFile.path.split('.').last.toLowerCase();
print('fileExtension $fileExtension');
if (fileExtension == 'jpg' || if (fileExtension == 'jpg' ||
fileExtension == 'jpeg' || fileExtension == 'jpeg' ||
fileExtension == 'png' || fileExtension == 'png' ||
fileExtension == "heic") { fileExtension == "heic") {
setState(() { setState(() {
_isLoading = false;
_profileImage = File(pickedFile.path); _profileImage = File(pickedFile.path);
}); });
} else { } else {
@ -225,6 +240,10 @@ class _EditProfileState extends State<EditProfile> {
); );
} }
} }
setState(() {
_isLoading = false; // Hide loader
});
} }
Future<void> _pickDate() async { Future<void> _pickDate() async {
@ -369,6 +388,17 @@ class _EditProfileState extends State<EditProfile> {
}); });
} }
Future<void> _loadImage(String url) async {
try {
// Simulate a network delay of 2 seconds (this mimics loading an image from the internet)
// await Future.delayed(Duration(seconds: 3));
print("Image loaded from URL: $url");
} catch (e) {
print("Error loading image: $e");
throw Exception('Failed to load image');
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BaseScaffold( return BaseScaffold(
@ -385,34 +415,112 @@ class _EditProfileState extends State<EditProfile> {
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: Column( child: Column(
children: [ children: [
CircleAvatar( // CircleAvatar(
radius: 50, // radius: 50,
backgroundImage: _profileImage != null // backgroundImage: _profileImage != null
? FileImage( // ? FileImage(
_profileImage!) // If a local file is selected // _profileImage!) // If a local file is selected
: _avatarUrl.isNotEmpty // : _avatarUrl.isNotEmpty
? NetworkImage(_avatarUrl) // Load from URL // ? NetworkImage(_avatarUrl) // Load from URL
: AssetImage( // : AssetImage(
"assets/edit_profile/profile.png") // "assets/edit_profile/profile.png")
as ImageProvider, // as ImageProvider,
//
// //backgroundImage: NetworkImage(_avatarUrl) as ImageProvider,
//
// child:
// Align(
// alignment: Alignment.bottomRight,
// child: GestureDetector(
// onTap: _pickImage, // Call `_pickImage` on tap
// child: CircleAvatar(
// radius: 15,
// backgroundColor: Colors.white,
// child: Icon(
// Icons.camera_alt,
// size: 15,
// color: Colors.grey,
// ),
// ),
// ),
// ),
// ),
//backgroundImage: NetworkImage(_avatarUrl) as ImageProvider, Stack(
child: Align( alignment: Alignment.center,
alignment: Alignment.bottomRight, children: [
child: GestureDetector( CircleAvatar(
onTap: _pickImage, // Call `_pickImage` on tap radius: 50,
child: CircleAvatar( backgroundImage: _profileImage != null
radius: 15, ? FileImage(
backgroundColor: Colors.white, _profileImage!) // If a local file is selected
child: Icon( : _avatarUrl.isNotEmpty
Icons.camera_alt, ? NetworkImage(
size: 15, _avatarUrl) // Load from URL
color: Colors.grey, : AssetImage(
"assets/edit_profile/profile.png")
as ImageProvider,
child: _avatarUrl.isNotEmpty
? FutureBuilder(
future: _loadImage(_avatarUrl),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasError) {
return Center(
child: Icon(Icons.error),
);
} else {
return Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
onTap:
_pickImage, // Call `_pickImage` on tap
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Icon(
Icons.camera_alt,
size: 15,
color: Colors.grey,
),
),
),
);
}
},
)
: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
onTap:
_pickImage, // Call `_pickImage` on tap
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Icon(
Icons.camera_alt,
size: 15,
color: Colors.grey,
),
),
),
),
),
if (_isLoading)
Positioned(
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.grey),
), ),
), ),
), ],
),
), ),
SizedBox(height: 20), SizedBox(height: 20),
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,

View File

@ -527,7 +527,7 @@ class _FeedbackFormState extends State<FeedbackForm>
)), )),
RatingBar.builder( RatingBar.builder(
initialRating: rating, initialRating: rating,
minRating: 1, minRating: 0,
direction: Axis.horizontal, direction: Axis.horizontal,
allowHalfRating: true, allowHalfRating: true,
itemCount: 5, itemCount: 5,

View File

@ -54,7 +54,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
final formattedDate = DateFormat('dd/MM/yyyy').format(createdDate); final formattedDate = DateFormat('dd/MM/yyyy').format(createdDate);
return User( return User(
id: record.id, // Correctly passing the ID id: record.id, // Correctly passing the ID
userName: record.getStringValue('username'), userName: record.getStringValue('uname'),
emailId: record.getStringValue('email'), emailId: record.getStringValue('email'),
registrationDate: formattedDate, registrationDate: formattedDate,
status: record.getStringValue('status'), status: record.getStringValue('status'),

View File

@ -1,11 +1,13 @@
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:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
class BaseScaffold extends StatelessWidget { class BaseScaffold extends StatefulWidget {
final Widget body; final Widget body;
final Widget title; final Widget title;
final bool ? showBackButton; final bool? showBackButton;
final bool ? mycenterTitle; final bool? mycenterTitle;
final List<Widget>? actions; final List<Widget>? actions;
final Color? appbarColor, mytitleColor; final Color? appbarColor, mytitleColor;
@ -15,76 +17,126 @@ class BaseScaffold extends StatelessWidget {
required this.title, required this.title,
this.actions, this.actions,
this.showBackButton = false, this.showBackButton = false,
this.mycenterTitle = false, this.appbarColor, this.mytitleColor this.mycenterTitle = false,
this.appbarColor,
this.mytitleColor,
}) : super(key: key); }) : super(key: key);
// final Widget body;
// @override
// const BaseScaffold({required this.body}); _BaseScaffoldState createState() => _BaseScaffoldState();
}
class _BaseScaffoldState extends State<BaseScaffold> {
final _pb = PocketBase('https://pb.venbait.in');
String _avatarUrl = '';
dynamic userId;
String? userName;
String? userEmail;
String? userAvatar;
String? role;
@override
void initState() {
super.initState();
_checkUserId();
}
// Method to retrieve userId from SharedPreferences
Future<String?> getUserId() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('userId'); // Retrieve the userId
}
// Method to check if userId exists and update state
Future<void> _checkUserId() async {
String? fetchedUserId = await getUserId();
if (fetchedUserId != null && fetchedUserId.isNotEmpty) {
setState(() {
userId = fetchedUserId;
});
//print('NAVUser ID: $userId');
_fetchUserData();
} else {
print('No userId found');
// 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');
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Get the current route to highlight the active item
String currentRoute = GoRouterState.of(context).matchedLocation; String currentRoute = GoRouterState.of(context).matchedLocation;
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(title: title, backgroundColor : appbarColor,actions: [
IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)),
],
leading:
// Stack(
// children: [
// // Show the back button if showBackButton is true, otherwise show the drawer menu
// if (showBackButton == true)
// Positioned(
// left: 0,
// child: IconButton(
// color: Colors.white,
// icon: Icon(Icons.arrow_back_ios_new),
// onPressed: () {
// Navigator.of(context).pop();
// },
// ),
// ),
// // Show the drawer icon in all cases
// Positioned(
// right: 0,
// child: IconButton(
// color: (showBackButton == true)? Colors.white : Colors.black,
// icon: Icon(Icons.menu),
// onPressed: () {
// // Open the drawer using the Scaffold context
// Scaffold.of(context).openDrawer();
// },
// ),
// ),
// ],
// ),
Stack( return Scaffold(
appBar: AppBar(
title: widget.title,
backgroundColor: widget.appbarColor,
actions: widget.actions ??
[
IconButton(
onPressed: () {},
icon: const Icon(Icons.toggle_off_outlined),
),
],
leading: Stack(
children: [ children: [
// Show the back button if showBackButton is true if (widget.showBackButton == true)
if (showBackButton == true)
Positioned( Positioned(
left: 15, left: 15,
child: IconButton( child: IconButton(
color: Colors.white, color: Colors.white,
icon: Icon(Icons.arrow_back_ios_new), icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
), ),
// Show the drawer icon in all cases
Positioned( Positioned(
right: 10, right: 10,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
return IconButton( return IconButton(
color: (showBackButton == true) ? Colors.white : Colors.black, color: (widget.showBackButton == true)
icon: Icon(Icons.menu), ? Colors.white
: Colors.black,
icon: const Icon(Icons.menu),
onPressed: () { onPressed: () {
// Open the drawer using the Scaffold context
Scaffold.of(context).openDrawer(); Scaffold.of(context).openDrawer();
}, },
); );
@ -92,14 +144,12 @@ class BaseScaffold extends StatelessWidget {
), ),
), ),
], ],
) ),
), ),
drawer: Drawer( drawer: Drawer(
child: ListView( child: ListView(
children: [ children: [
DrawerHeader( DrawerHeader(
//decoration: BoxDecoration(color: Colors.blue),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -117,18 +167,39 @@ class BaseScaffold extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
SizedBox( SizedBox(
width: mywidth / 8, width: mywidth / 8,
child: Image( height: mywidth / 8,
image: AssetImage( child: ClipOval(
'assets/edit_profile/profile.png'))), child: _avatarUrl.isNotEmpty
? Image(
image: NetworkImage(_avatarUrl),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
)
: Image(
image: AssetImage(
'assets/edit_profile/profile.png'),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
//child: Image(image: AssetImage('assets/edit_profile/profile.png'))
),
SizedBox( SizedBox(
width: mywidth / 20, width: mywidth / 20,
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Mohammad'), // Text(userId ?? 'Loading user...'), // Display userId here
Text('Mohammad@fcsc.com') // Text('Mohammad@fcsc.com')
Text(userName ?? 'Loading...'),
Text(
userEmail ?? 'Loading...',
style: TextStyle(fontSize: 12),
),
], ],
) )
], ],
@ -138,33 +209,26 @@ class BaseScaffold extends StatelessWidget {
), ),
), ),
ListTile( ListTile(
leading: SizedBox( leading: Icon(Icons.feedback),
height: myheight / 15, title: const Text('Feedback'),
width: mywidth / 15,
child: Image(
image: AssetImage('assets/icons/drawer/message.png'))),
title: Text('Feedback'),
onTap: () => context.go('/feedback'), onTap: () => context.go('/feedback'),
), ),
if (role == 'admin')
ListTile(
leading: Icon(Icons.manage_accounts),
title: const Text('Manage User'),
onTap: () => context.go('/manageuser'),
),
ListTile( ListTile(
leading: SizedBox( leading: Icon(Icons.book),
height: myheight / 15, title: const Text('User Guide'),
width: mywidth / 15,
child: Image(
image: AssetImage('assets/icons/drawer/manageuser.png'))),
title: Text('Manage User'),
onTap: () => context.go('/manageuser'),
),
ListTile(
leading: SizedBox(
height: myheight / 15,
width: mywidth / 15,
child: Image(
image: AssetImage('assets/icons/drawer/book.png'))),
title: Text('User Guide'),
onTap: () => context.go('/user-guide'), onTap: () => context.go('/user-guide'),
), ),
ListTile(
leading: Icon(Icons.logout),
title: const Text('Logout'),
onTap: () => context.go('/'),
),
], ],
), ),
), ),
@ -174,49 +238,33 @@ class BaseScaffold extends StatelessWidget {
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
items: [ items: [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: SizedBox( icon: Icon(Icons.home),
height: myheight / 15,
width: mywidth / 15,
child: Image(
image: AssetImage('assets/icons/bottom_bar/home.png'))),
label: 'Home', label: 'Home',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: SizedBox( icon: Icon(Icons.map),
height: myheight / 15,
width: mywidth / 15,
child: Image(
image: AssetImage('assets/icons/bottom_bar/uae_map.png'))),
label: 'UAE Numbers', label: 'UAE Numbers',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: SizedBox( icon: Icon(Icons.bar_chart),
height: myheight / 15, label: 'Competitiveness',
width: mywidth / 15, ),
child: Image(
image:
AssetImage('assets/icons/bottom_bar/ranking.png'))),
label: 'Competitiveness'),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: SizedBox( icon: Icon(Icons.public),
height: myheight / 15, label: 'Country Profile',
width: mywidth / 15, ),
child: Image(
image: AssetImage('assets/icons/bottom_bar/globe.png'))),
label: 'Country Profile'),
], ],
selectedItemColor: Colors.black, selectedItemColor: Colors.black,
unselectedItemColor: Colors.grey, unselectedItemColor: Colors.grey,
showUnselectedLabels: true, showUnselectedLabels: true,
), ),
body: body, body: widget.body,
); );
} }
//Map the current route to the selected index
int _getSelectedIndex(String route) { int _getSelectedIndex(String route) {
switch (route) { switch (route) {
case '/': case '/myhomepage':
return 0; return 0;
case '/uaenumbers': case '/uaenumbers':
return 1; return 1;
@ -229,11 +277,10 @@ class BaseScaffold extends StatelessWidget {
} }
} }
//Handle navigation when an item is tapped
void _onItemTapped(BuildContext context, int index) { void _onItemTapped(BuildContext context, int index) {
switch (index) { switch (index) {
case 0: case 0:
context.go('/'); context.go('/myhomepage');
break; break;
case 1: case 1:
context.go('/uaenumbers'); context.go('/uaenumbers');

View File

@ -385,10 +385,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fl_chart name: fl_chart
sha256: "10ddaf334fe84d59333a12d153043e366f243e0bdfff2df0313e1e249f5bf926" sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.70.1" version: "0.69.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -440,7 +440,7 @@ packages:
source: hosted source: hosted
version: "2.4.4" version: "2.4.4"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: "direct main"
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
@ -467,10 +467,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_secure_storage name: flutter_secure_storage
sha256: "1913841ac4c7bf57cd2e05b717e1fbff7841b542962feff827b16525a781b3e4" sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.2.3" version: "9.2.4"
flutter_secure_storage_linux: flutter_secure_storage_linux:
dependency: transitive dependency: transitive
description: description:
@ -661,10 +661,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image_picker_android name: image_picker_android
sha256: aa6f1280b670861ac45220cc95adc59bb6ae130259d36f980ccb62220dc5e59f sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.12+19" version: "0.8.12+20"
image_picker_for_web: image_picker_for_web:
dependency: transitive dependency: transitive
description: description:
@ -1116,10 +1116,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d" sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "2.4.1"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
@ -1260,22 +1260,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
syncfusion_flutter_charts:
dependency: "direct main"
description:
name: syncfusion_flutter_charts
sha256: b2a9f0fd585ef96c081c37697b46d48d3b0f3fe6bddc5011a3542962814fafa8
url: "https://pub.dev"
source: hosted
version: "28.1.33"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: "12735505d616320aebe39a6fc90b6608a09116378d66aee9636b0eddf7b75971"
url: "https://pub.dev"
source: hosted
version: "28.1.38"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -1376,18 +1360,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.3" version: "2.4.0"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_windows name: url_launcher_windows
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.3" version: "3.1.4"
uuid: uuid:
dependency: transitive dependency: transitive
description: description:

View File

@ -21,7 +21,7 @@ dependencies:
riverpod_annotation: ^2.3.3 riverpod_annotation: ^2.3.3
cupertino_icons: ^1.0.6 cupertino_icons: ^1.0.6
fl_chart: ^0.70.1 fl_chart: ^0.69.2
marquee: ^2.2.3 marquee: ^2.2.3
url_launcher: ^6.3.1 url_launcher: ^6.3.1
@ -57,9 +57,9 @@ dependencies:
provider: ^6.1.2 provider: ^6.1.2
mailer: ^6.2.0 mailer: ^6.2.0
image_picker: ^1.1.2 image_picker: ^1.1.2
syncfusion_flutter_charts: 28.1.33
material_charts: ^0.0.23 material_charts: ^0.0.23
flutter_staggered_grid_view: ^0.7.0 flutter_staggered_grid_view: ^0.7.0
flutter_plugin_android_lifecycle: ^2.0.24
dependency_overrides: dependency_overrides:
fading_edge_scrollview: ^4.1.1 fading_edge_scrollview: ^4.1.1