App Tour Bug and Bookmark Frontend added
@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) {
|
|||||||
|
|
||||||
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
||||||
if (flutterVersionCode == null) {
|
if (flutterVersionCode == null) {
|
||||||
flutterVersionCode = "3"
|
flutterVersionCode = "6"
|
||||||
}
|
}
|
||||||
|
|
||||||
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
||||||
if (flutterVersionName == null) {
|
if (flutterVersionName == null) {
|
||||||
flutterVersionName = "1.0.2"
|
flutterVersionName = "1.0.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
def keystorePropertiesFile = rootProject.file("key.properties")
|
def keystorePropertiesFile = rootProject.file("key.properties")
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/uae_numbers/bookmarks.png
Normal file
|
After Width: | Height: | Size: 325 B |
BIN
assets/icons/uae_numbers/share.png
Normal file
|
After Width: | Height: | Size: 375 B |
|
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
@ -414,7 +414,9 @@ final GoRouter router = GoRouter(
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final userId = state.pathParameters['userId']!;
|
final userId = state.pathParameters['userId']!;
|
||||||
final email = state.pathParameters['email']!;
|
final email = state.pathParameters['email']!;
|
||||||
return CreateNewPw(userId: userId, email: email);
|
final key = state.uri.queryParameters['key'] ?? '';
|
||||||
|
|
||||||
|
return CreateNewPw(userId: userId, email: email, keyParam: key);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
abstract class UaeNumbersAssetPath {
|
||||||
|
static const _basePath = 'assets/icons/uae_numbers';
|
||||||
|
static const bookmarksUae = '$_basePath/bookmarks.png';
|
||||||
|
static const shareUae = '$_basePath/share.png';
|
||||||
|
}
|
||||||
@ -13,7 +13,9 @@ import '../../../config/my_theme.dart';
|
|||||||
class CreateNewPw extends StatefulWidget {
|
class CreateNewPw extends StatefulWidget {
|
||||||
final String userId;
|
final String userId;
|
||||||
final String email;
|
final String email;
|
||||||
const CreateNewPw({Key? key, required this.userId, required this.email});
|
final String? keyParam;
|
||||||
|
|
||||||
|
const CreateNewPw({Key? key, required this.userId, required this.email, required this.keyParam});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CreateNewPw> createState() => _CreateNewPwState();
|
State<CreateNewPw> createState() => _CreateNewPwState();
|
||||||
@ -210,7 +212,14 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
alignment: Alignment.topRight,
|
alignment: Alignment.topRight,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.go('/editProfile');
|
|
||||||
|
if (widget.keyParam == 'editProfile') {
|
||||||
|
context.go('/editProfile');
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
context.go('/profile/${widget.userId}');
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.only(top: 16,left: 16,bottom: 16,right: 1), // Add margin for positioning
|
margin: EdgeInsets.only(top: 16,left: 16,bottom: 16,right: 1), // Add margin for positioning
|
||||||
@ -351,8 +360,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
|||||||
SizedBox(height: screenHeight / 5),
|
SizedBox(height: screenHeight / 5),
|
||||||
Center(
|
Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: screenHeight / 8,
|
height: screenHeight / 12,
|
||||||
width: screenWidth / 2,
|
width: screenWidth / 2.5,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: AssetImage("assets/splash_screen/logo.png"),
|
image: AssetImage("assets/splash_screen/logo.png"),
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
String? _password;
|
String? _password;
|
||||||
bool registrationSuccess = false;
|
bool registrationSuccess = false;
|
||||||
bool registrationFailed = false;
|
bool registrationFailed = false;
|
||||||
|
bool isRegistering = false;
|
||||||
dynamic userID;
|
dynamic userID;
|
||||||
|
|
||||||
final pb = PocketBase('https://pb.venbait.in');
|
final pb = PocketBase('https://pb.venbait.in');
|
||||||
@ -144,6 +145,12 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
final regex = RegExp(
|
final regex = RegExp(
|
||||||
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
|
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
|
||||||
|
|
||||||
|
// Define regular expressions for password complexity requirements
|
||||||
|
final hasUppercase = RegExp(r'[A-Z]');
|
||||||
|
final hasLowercase = RegExp(r'[a-z]');
|
||||||
|
final hasDigit = RegExp(r'\d');
|
||||||
|
final hasSpecialCharacter = RegExp(r'[~!@#$%^&*()_+=[\]{}|;:,.<>?/-]');
|
||||||
|
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Required';
|
return 'Required';
|
||||||
} else if (value.length < 8) {
|
} else if (value.length < 8) {
|
||||||
@ -151,7 +158,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the length constraint
|
// Check the length constraint
|
||||||
if (value.length < 8 || value.length > 40) {
|
if (value.length < 8 || value.length > 64) {
|
||||||
return 'Password must be between 8 and 64 characters';
|
return 'Password must be between 8 and 64 characters';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +167,27 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
return 'Password contains invalid characters';
|
return 'Password contains invalid characters';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track missing constraints
|
||||||
|
List<String> missingConstraints = [];
|
||||||
|
|
||||||
|
if (!hasUppercase.hasMatch(value)) {
|
||||||
|
missingConstraints.add('uppercase letter');
|
||||||
|
}
|
||||||
|
if (!hasLowercase.hasMatch(value)) {
|
||||||
|
missingConstraints.add('lowercase letter');
|
||||||
|
}
|
||||||
|
if (!hasDigit.hasMatch(value)) {
|
||||||
|
missingConstraints.add('numeric digit');
|
||||||
|
}
|
||||||
|
if (!hasSpecialCharacter.hasMatch(value)) {
|
||||||
|
missingConstraints.add('special character');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are missing constraints, return a consolidated message
|
||||||
|
if (missingConstraints.isNotEmpty) {
|
||||||
|
return 'At least one ${missingConstraints.join(', ')}';
|
||||||
|
}
|
||||||
|
|
||||||
_password = value; // Store the password for confirm password validation
|
_password = value; // Store the password for confirm password validation
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -185,12 +213,15 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
Future<void> _registerUser() async {
|
Future<void> _registerUser() async {
|
||||||
if (_formKey.currentState?.validate() ?? false) {
|
if (_formKey.currentState?.validate() ?? false) {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
|
setState(() {
|
||||||
|
isRegistering = true; // Disable the button
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
final adminAuth = await pb.admins
|
final adminAuth = await pb.admins
|
||||||
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
|
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
|
||||||
|
|
||||||
final adminToken = adminAuth.token;
|
final adminToken = adminAuth.token;
|
||||||
print('adminToken- ${adminToken}');
|
print('adminTokenREgistration- ${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: {
|
||||||
'uname': _usernameController.text,
|
'uname': _usernameController.text,
|
||||||
@ -211,6 +242,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
userID = response.id;
|
userID = response.id;
|
||||||
registrationSuccess = true;
|
registrationSuccess = true;
|
||||||
registrationFailed = false; // Show success message on success
|
registrationFailed = false; // Show success message on success
|
||||||
|
isRegistering = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Navigate to ProfileScreen after successful registration
|
// Navigate to ProfileScreen after successful registration
|
||||||
@ -249,6 +281,9 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
registrationFailed = true;
|
registrationFailed = true;
|
||||||
registrationSuccess = false;
|
registrationSuccess = false;
|
||||||
});
|
});
|
||||||
|
setState(() {
|
||||||
|
isRegistering = false; // Re-enable the button after error
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -330,7 +365,9 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
buildIconContainer(Icons.report, Color(0xFF7DAFBC)),
|
buildIconContainer(Icons.report, Color(0xFF7DAFBC)),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
"Your registration is pending for verification.",
|
context.translate(
|
||||||
|
'Your registration is pending for verification.',
|
||||||
|
'تسجيلك في انتظار التحقق.'),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@ -339,7 +376,9 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
"Kindly verify your mail to proceed further.",
|
context.translate(
|
||||||
|
'Kindly verify your mail to proceed further.',
|
||||||
|
'يرجى التحقق من البريد الخاص بك للمضي قدما.'),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -350,14 +389,14 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () => {context.go('/')},
|
onPressed: () => {context.go('/')},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Go to Login',
|
context.translate('Go to Login', 'اذهب إلى تسجيل الدخول'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: screenheight / 5),
|
SizedBox(height: screenheight / 5),
|
||||||
Center(
|
Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: screenheight / 8,
|
height: screenheight / 16,
|
||||||
width: screenwidth / 2,
|
width: screenwidth / 2.5,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: AssetImage(
|
image: AssetImage(
|
||||||
@ -379,7 +418,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
buildIconContainer(Icons.report, Colors.red),
|
buildIconContainer(Icons.report, Colors.red),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
"Sorry ${_usernameController.text}!",
|
context.translate('Sorry ${_usernameController.text}!',
|
||||||
|
'آسف ${_usernameController.text}!'),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@ -388,7 +428,9 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
"Your registration process failed. For further assistance, please contact support.",
|
context.translate(
|
||||||
|
'Your registration process failed. For further assistance, please contact support.',
|
||||||
|
'فشلت عملية التسجيل الخاصة بك. لمزيد من المساعدة، يرجى الاتصال بالدعم.'),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -409,14 +451,14 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Retry',
|
context.translate('Retry', 'أعد المحاولة'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: screenheight / 5),
|
SizedBox(height: screenheight / 5),
|
||||||
Center(
|
Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: screenheight / 8,
|
height: screenheight / 16,
|
||||||
width: screenwidth / 2,
|
width: screenwidth / 2.5,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: AssetImage(
|
image: AssetImage(
|
||||||
@ -475,7 +517,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
// hintText: 'Enter your email',
|
// hintText: 'Enter your email',
|
||||||
hintText: _showHints[1]
|
hintText: _showHints[1]
|
||||||
? AppLocalizations.of(context)!.enter_your_email
|
? AppLocalizations.of(context)!
|
||||||
|
.enter_your_email
|
||||||
: null,
|
: null,
|
||||||
// _showHints[1] ? 'Enter your email' : null,
|
// _showHints[1] ? 'Enter your email' : null,
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
@ -500,7 +543,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
obscureText: _obscurePassword,
|
obscureText: _obscurePassword,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: _showHints[2]
|
hintText: _showHints[2]
|
||||||
? AppLocalizations.of(context)!.enter_your_password
|
? AppLocalizations.of(context)!
|
||||||
|
.enter_your_password
|
||||||
: null,
|
: null,
|
||||||
// _showHints[2] ? 'Enter your password' : null,
|
// _showHints[2] ? 'Enter your password' : null,
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
@ -510,8 +554,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscurePassword
|
_obscurePassword
|
||||||
? Icons.visibility
|
? Icons.visibility_off
|
||||||
: Icons.visibility_off,
|
: Icons.visibility,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -545,8 +589,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscureConfirmPassword
|
_obscureConfirmPassword
|
||||||
? Icons.visibility
|
? Icons.visibility_off
|
||||||
: Icons.visibility_off,
|
: Icons.visibility,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -632,7 +676,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: screenwidth / 1.3,
|
width: screenwidth / 1.3,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _registerUser,
|
onPressed: isRegistering ? null : _registerUser,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Color(
|
backgroundColor: Color(
|
||||||
0xFFA7887A), // Brownish color for Register
|
0xFFA7887A), // Brownish color for Register
|
||||||
@ -719,8 +763,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
|||||||
),
|
),
|
||||||
Center(
|
Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: screenheight / 8,
|
height: screenheight / 16,
|
||||||
width: screenwidth / 2,
|
width: screenwidth / 2.5,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: AssetImage(
|
image: AssetImage(
|
||||||
|
|||||||
@ -4,9 +4,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
import 'package:uae_stat/domain/use_cases/language.dart';
|
import 'package:uae_stat/domain/use_cases/language.dart';
|
||||||
|
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/uae_numbers_asset_path.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/charts/services/api_service.dart';
|
import 'package:uae_stat/presentation/Screens/charts/services/api_service.dart';
|
||||||
import 'package:uae_stat/presentation/Screens/charts/widgets/chart_widget.dart';
|
import 'package:uae_stat/presentation/Screens/charts/widgets/chart_widget.dart';
|
||||||
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
|
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
|
||||||
|
import 'package:uae_stat/presentation/components/my_toggle.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:uae_stat/presentation/Screens/app_tour/Target_content.dart';
|
import 'package:uae_stat/presentation/Screens/app_tour/Target_content.dart';
|
||||||
@ -761,8 +763,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
filterDataSet = filterData.entries
|
filterDataSet = filterData.entries
|
||||||
.map((entry) => {'key': entry.key, 'value': entry.value})
|
.map((entry) => {'key': entry.key, 'value': entry.value})
|
||||||
.toList();
|
.toList();
|
||||||
// print("filterDataf1:- $filterData");
|
print("filterDataf1:- $filterData");
|
||||||
// print("filterDataf11:- $filterDataSet");
|
print("filterDataf11:- $filterDataSet");
|
||||||
} else {
|
} else {
|
||||||
filterDataSet = data['filterData'] ?? [];
|
filterDataSet = data['filterData'] ?? [];
|
||||||
print('filterData not found!');
|
print('filterData not found!');
|
||||||
@ -1081,53 +1083,139 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Button Section
|
// Button Section
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.all(16.0),
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// ElevatedButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// // Clear all selected filters
|
||||||
|
// selectedFilters.forEach((filter) {
|
||||||
|
// filter["filter_data"].clear();
|
||||||
|
// });
|
||||||
|
// setState(() {
|
||||||
|
// chartsData = List.from(originalTabChartsData);
|
||||||
|
// cardData = List.from(originalTabCardData);
|
||||||
|
// });
|
||||||
|
// // Reset the selectedFiltersStorage to empty when clearing
|
||||||
|
// selectedFiltersStorage.clear();
|
||||||
|
// Navigator.pop(context);
|
||||||
|
// },
|
||||||
|
// child: Text(context.translate(
|
||||||
|
// 'Clear',
|
||||||
|
// 'واضح',
|
||||||
|
// )),
|
||||||
|
// style: ElevatedButton.styleFrom(
|
||||||
|
// backgroundColor: Colors.grey,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ElevatedButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// print(
|
||||||
|
// "Selected Filters before applying: $selectedFilters");
|
||||||
|
// setState(() {
|
||||||
|
// chartsData = originalTabChartsData;
|
||||||
|
// cardData = originalTabCardData;
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// applyFilters(context, filters, chartsData, cardData,
|
||||||
|
// selectedFilters);
|
||||||
|
// // Save the selected filters to storage after applying
|
||||||
|
// selectedFiltersStorage = List.from(selectedFilters);
|
||||||
|
// },
|
||||||
|
// child: Text(context.translate(
|
||||||
|
// 'Apply Filter',
|
||||||
|
// 'تطبيق الفلتر',
|
||||||
|
// )),
|
||||||
|
// style: ElevatedButton.styleFrom(
|
||||||
|
// backgroundColor: Colors.blue,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton(
|
Expanded(
|
||||||
onPressed: () {
|
child: ElevatedButton(
|
||||||
// Clear all selected filters
|
onPressed: () {
|
||||||
selectedFilters.forEach((filter) {
|
selectedFilters.forEach((filter) {
|
||||||
filter["filter_data"].clear();
|
filter["filter_data"].clear();
|
||||||
});
|
});
|
||||||
setState(() {
|
setState(() {
|
||||||
chartsData = List.from(originalTabChartsData);
|
chartsData = List.from(originalTabChartsData);
|
||||||
cardData = List.from(originalTabCardData);
|
cardData = List.from(originalTabCardData);
|
||||||
});
|
});
|
||||||
// Reset the selectedFiltersStorage to empty when clearing
|
selectedFiltersStorage.clear();
|
||||||
selectedFiltersStorage.clear();
|
Navigator.pop(context);
|
||||||
Navigator.pop(context);
|
},
|
||||||
},
|
child: Padding(
|
||||||
child: Text(context.translate(
|
padding: const EdgeInsets.symmetric(
|
||||||
'Clear',
|
vertical: 12), // Added padding
|
||||||
'واضح',
|
child: Text(
|
||||||
)),
|
context.translate('Clear', 'واضح'),
|
||||||
style: ElevatedButton.styleFrom(
|
style: TextStyle(
|
||||||
backgroundColor: Colors.grey,
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
overflow:
|
||||||
|
TextOverflow.ellipsis, // Prevents wrapping
|
||||||
|
maxLines: 1, // Ensures single line
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Color(0xFF92722A),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
SizedBox(width: 16),
|
||||||
onPressed: () {
|
Expanded(
|
||||||
print(
|
child: ElevatedButton(
|
||||||
"Selected Filters before applying: $selectedFilters");
|
onPressed: () {
|
||||||
setState(() {
|
print(
|
||||||
chartsData = originalTabChartsData;
|
"Selected Filters before applying: $selectedFilters");
|
||||||
cardData = originalTabCardData;
|
setState(() {
|
||||||
});
|
chartsData = originalTabChartsData;
|
||||||
|
cardData = originalTabCardData;
|
||||||
|
});
|
||||||
|
|
||||||
applyFilters(context, filters, chartsData, cardData,
|
applyFilters(context, filters, chartsData, cardData,
|
||||||
selectedFilters);
|
selectedFilters);
|
||||||
// Save the selected filters to storage after applying
|
selectedFiltersStorage = List.from(selectedFilters);
|
||||||
selectedFiltersStorage = List.from(selectedFilters);
|
},
|
||||||
},
|
child: Padding(
|
||||||
child: Text(context.translate(
|
padding: const EdgeInsets.symmetric(
|
||||||
'Apply Filter',
|
vertical: 12), // Added padding
|
||||||
'تطبيق الفلتر',
|
child: FittedBox(
|
||||||
)),
|
fit: BoxFit
|
||||||
style: ElevatedButton.styleFrom(
|
.scaleDown, // Ensures text resizes if necessary
|
||||||
backgroundColor: Colors.blue,
|
child: Text(
|
||||||
|
context.translate(
|
||||||
|
'Apply Filter', 'تطبيق الفلتر'),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
overflow:
|
||||||
|
TextOverflow.ellipsis, // Prevents wrapping
|
||||||
|
maxLines: 1, // Ensures single line
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Color(0xFF92722A),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1235,9 +1323,18 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final locale = ref.watch(localeProvider);
|
||||||
|
final localeNotifier = ref.read(localeProvider.notifier);
|
||||||
ref.listen<Locale?>(localeProvider, (previous, next) {
|
ref.listen<Locale?>(localeProvider, (previous, next) {
|
||||||
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
|
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
|
||||||
fetchChartData(widget.dataSets, localeCode);
|
// fetchChartData(widget.dataSets, localeCode);
|
||||||
|
|
||||||
|
fetchChartData(widget.dataSets, localeCode).then((_) {
|
||||||
|
if (_tabsData.isNotEmpty) {
|
||||||
|
// Call onTabSelected for the first tab
|
||||||
|
onTabSelected(_tabsData[0]['id']);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
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;
|
||||||
@ -1249,6 +1346,23 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: color,
|
backgroundColor: color,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
|
actions: [
|
||||||
|
// IconButton(
|
||||||
|
// onPressed: () {},
|
||||||
|
// icon: const Icon(Icons.toggle_off_outlined),
|
||||||
|
// ),
|
||||||
|
MyToggle(
|
||||||
|
// key: toggleKey,
|
||||||
|
isOn: locale?.languageCode == 'en',
|
||||||
|
knobTextWhenOn: 'ع',
|
||||||
|
knobTextWhenOff: 'EN',
|
||||||
|
pathColorWhenOn: Colors.grey.shade300,
|
||||||
|
pathColorWhenOff: Colors.grey.shade300,
|
||||||
|
onTap: () {
|
||||||
|
ref.read(localeProvider.notifier).toggleLocale();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
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: () {
|
||||||
@ -1343,8 +1457,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 5),
|
SizedBox(width: 5),
|
||||||
Icon(Icons.bookmarks_outlined,
|
Image.asset(
|
||||||
color: Colors.white, size: 18),
|
UaeNumbersAssetPath.bookmarksUae,
|
||||||
|
color: Colors.white,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
@ -1361,8 +1479,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 5),
|
SizedBox(width: 5),
|
||||||
Icon(Icons.share_sharp,
|
Image.asset(
|
||||||
color: Colors.white, size: 18),
|
UaeNumbersAssetPath.shareUae,
|
||||||
|
color: Colors.white,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -1492,10 +1614,13 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
Flexible(
|
Flexible(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
// fit: BoxFit.contain,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'${chart_heading ?? 'NA'}',
|
'${chart_heading ?? 'NA'}',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2, // Limit to 2 lines
|
||||||
|
softWrap:
|
||||||
|
true, // Enable soft wrapping
|
||||||
|
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -1584,19 +1709,28 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
Text(
|
Flexible(
|
||||||
'${chart_heading ?? 'NA'}',
|
fit: FlexFit.loose,
|
||||||
textAlign: TextAlign.center,
|
child: FittedBox(
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
fontSize: 11,
|
'${chart_heading ?? 'NA'}',
|
||||||
fontWeight: FontWeight.w400,
|
textAlign: TextAlign.center,
|
||||||
color: Colors.black87,
|
maxLines: 2, // Limit to 2 lines
|
||||||
|
softWrap:
|
||||||
|
true, // Enable soft wrapping
|
||||||
|
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})',
|
'(${data['firstYear'] ?? 'NA'} - ${data['lastYear'] ?? 'NA'})',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 11, color: Colors.grey),
|
fontSize: 10, color: Colors.grey),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
@ -1640,10 +1774,13 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
Flexible(
|
Flexible(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
// fit: BoxFit.contain,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'${chart_heading ?? 'NA'}',
|
'${chart_heading ?? 'NA'}',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2, // Limit to 2 lines
|
||||||
|
softWrap:
|
||||||
|
true, // Enable soft wrapping
|
||||||
|
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -1715,14 +1852,17 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
|||||||
Flexible(
|
Flexible(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.contain,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
apiService.formatAmount(
|
'${chart_heading ?? 'NA'}',
|
||||||
data['lastYearValue']),
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
maxLines: 2, // Limit to 2 lines
|
||||||
fontSize: 22,
|
softWrap:
|
||||||
fontWeight: FontWeight.w900,
|
true, // Enable soft wrapping
|
||||||
color: Color(0xFF90B0D5),
|
// overflow: TextOverflow.ellipsis, // Handle overflow gracefully
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -72,27 +72,34 @@ class ChartWidget extends StatelessWidget {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> generateIndicators(dynamic chartData, groupByValue) {
|
List<Widget> generateIndicators(dynamic chartData, String groupByValue) {
|
||||||
return chartData['response'].asMap().entries.map<Widget>((entry) {
|
return chartData['response'].asMap().entries.map<Widget>((entry) {
|
||||||
int index = entry.key;
|
int index = entry.key;
|
||||||
var data = entry.value;
|
var data = entry.value;
|
||||||
Color color = Colors.primaries[index % Colors.primaries.length];
|
Color color = Colors.primaries[index % Colors.primaries.length];
|
||||||
String title = data['ObsKey'][groupByValue] ?? '';
|
String title = data['ObsKey'][groupByValue] ?? '';
|
||||||
|
String shortTitle =
|
||||||
|
title.length > 10 ? '${title.substring(0, 10)}…' : title;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 16,
|
width: 10,
|
||||||
height: 16,
|
height: 10,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: color,
|
color: color,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(
|
Tooltip(
|
||||||
title,
|
message: title, // Full text on hover
|
||||||
style: TextStyle(fontSize: 14),
|
child: Text(
|
||||||
|
shortTitle,
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
overflow: TextOverflow.ellipsis, // Ensures text doesn't overflow
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -299,7 +306,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
touchTooltipData: BarTouchTooltipData(
|
touchTooltipData: BarTouchTooltipData(
|
||||||
// tooltipBgColor: Colors.black.withOpacity(0.8),
|
// tooltipBgColor: Colors.black.withOpacity(0.8),
|
||||||
fitInsideHorizontally: true,
|
fitInsideHorizontally: true,
|
||||||
fitInsideVertically: false,
|
fitInsideVertically: true,
|
||||||
tooltipPadding: const EdgeInsets.all(8),
|
tooltipPadding: const EdgeInsets.all(8),
|
||||||
tooltipMargin: 16,
|
tooltipMargin: 16,
|
||||||
getTooltipItem:
|
getTooltipItem:
|
||||||
@ -541,11 +548,21 @@ class ChartWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
case 'line_trend_2':
|
case 'line_trend_population':
|
||||||
|
final List<Color> uniqueColorsLine_trend_2 = [
|
||||||
|
Color(0xFF6097CD),
|
||||||
|
Color(0xFFD086A7),
|
||||||
|
Color(0xFF98BCE5),
|
||||||
|
Color(0xFFA7B5C5),
|
||||||
|
Color(0xFFBED3EC),
|
||||||
|
Color(0xFFD4E3F4),
|
||||||
|
];
|
||||||
|
Set<int> selectedYears = {1970, 1980, 1990, 2000, 2010, 2020};
|
||||||
Map<String, Color> groupColorMap = {};
|
Map<String, Color> groupColorMap = {};
|
||||||
int colorIndex = 0;
|
int colorIndex = 0;
|
||||||
for (String group in groupByValues) {
|
for (String group in groupByValues) {
|
||||||
groupColorMap[group] = uniqueColors[colorIndex % uniqueColors.length];
|
groupColorMap[group] = uniqueColorsLine_trend_2[
|
||||||
|
colorIndex % uniqueColorsLine_trend_2.length];
|
||||||
colorIndex++;
|
colorIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,15 +582,17 @@ class ChartWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the maximum year and calculate the range for the last 5 years
|
if (years.isNotEmpty) {
|
||||||
int maxYear = years.reduce((a, b) => a > b ? a : b);
|
// Find the latest available year
|
||||||
int minYear = maxYear - 5;
|
int latestYear = years.reduce((a, b) => a > b ? a : b);
|
||||||
|
selectedYears.add(latestYear); // Include the latest year in selection
|
||||||
|
}
|
||||||
|
|
||||||
// Filter chart data to only include entries within the last 5 years
|
// Filter chart data to include only the selected years
|
||||||
List<dynamic> filteredData =
|
List<dynamic> filteredData =
|
||||||
(chartData['response'] as List<dynamic>).where((entry) {
|
(chartData['response'] as List<dynamic>).where((entry) {
|
||||||
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
||||||
return year >= minYear && year <= maxYear;
|
return selectedYears.contains(year);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
Set<double> uniqueXValues = filteredData
|
Set<double> uniqueXValues = filteredData
|
||||||
@ -583,7 +602,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
|
|
||||||
// Generate line bars for the chart
|
// Generate line bars for the chart
|
||||||
List<LineChartBarData> lineBars =
|
List<LineChartBarData> lineBars =
|
||||||
lineBarsData2(filteredData, groupByValues, groupByKey);
|
lineBarsData(filteredData, groupByValues, groupByKey);
|
||||||
|
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
Text(
|
Text(
|
||||||
@ -600,12 +619,124 @@ class ChartWidget extends StatelessWidget {
|
|||||||
child: LineChart(LineChartData(
|
child: LineChart(LineChartData(
|
||||||
lineTouchData: lineTouchData1(),
|
lineTouchData: lineTouchData1(),
|
||||||
gridData: gridData(),
|
gridData: gridData(),
|
||||||
titlesData: titlesData2(uniqueXValues),
|
titlesData: titlesData1(uniqueXValues),
|
||||||
borderData: borderData(),
|
borderData: borderData(),
|
||||||
lineBarsData: lineBars,
|
lineBarsData: lineBars,
|
||||||
minX: uniqueXValues.reduce((a, b) => a < b ? a : b),
|
minX: uniqueXValues.reduce((a, b) => a < b ? a : b),
|
||||||
maxX: uniqueXValues.reduce((a, b) => a > b ? a : b),
|
maxX: uniqueXValues.reduce((a, b) => a > b ? a : b),
|
||||||
))),
|
))),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 12,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: groupByValues.map((group) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 12,
|
||||||
|
height: 12,
|
||||||
|
color: groupColorMap[group],
|
||||||
|
),
|
||||||
|
SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
group,
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
case 'line_trend_2':
|
||||||
|
final List<Color> uniqueColorsLine_trend_2 = [
|
||||||
|
Color(0xFF6097CD),
|
||||||
|
Color(0xFFD086A7),
|
||||||
|
Color(0xFF98BCE5),
|
||||||
|
Color(0xFFA7B5C5),
|
||||||
|
Color(0xFFBED3EC),
|
||||||
|
Color(0xFFD4E3F4),
|
||||||
|
];
|
||||||
|
Set<int> selectedYears = {1970, 1980, 1990, 2000, 2010, 2020};
|
||||||
|
Map<String, Color> groupColorMap = {};
|
||||||
|
int colorIndex = 0;
|
||||||
|
for (String group in groupByValues) {
|
||||||
|
groupColorMap[group] = uniqueColorsLine_trend_2[
|
||||||
|
colorIndex % uniqueColorsLine_trend_2.length];
|
||||||
|
colorIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract all years from the chart data
|
||||||
|
List<int> years = (chartData['response'] as List<dynamic>)
|
||||||
|
.map<int>((entry) =>
|
||||||
|
int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (years.isEmpty) {
|
||||||
|
// Return an empty chart if no data
|
||||||
|
return LineChart(
|
||||||
|
LineChartData(
|
||||||
|
titlesData: FlTitlesData(show: false),
|
||||||
|
lineBarsData: [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (years.isNotEmpty) {
|
||||||
|
// Find the latest available year
|
||||||
|
int latestYear = years.reduce((a, b) => a > b ? a : b);
|
||||||
|
selectedYears.add(latestYear); // Include the latest year in selection
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter chart data to include only the selected years
|
||||||
|
List<dynamic> filteredData =
|
||||||
|
(chartData['response'] as List<dynamic>).where((entry) {
|
||||||
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'] ?? '0') ?? 0;
|
||||||
|
return selectedYears.contains(year);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
Set<double> uniqueXValues = filteredData
|
||||||
|
.map<double>(
|
||||||
|
(entry) => double.parse(entry['ObsKey']['TIME_PERIOD']))
|
||||||
|
.toSet();
|
||||||
|
|
||||||
|
// Generate line bars for the chart
|
||||||
|
List<LineChartBarData> lineBars = lineBarsData2(filteredData);
|
||||||
|
|
||||||
|
return Column(children: [
|
||||||
|
Text(
|
||||||
|
chartData['chart_heading'] ?? '', // Chart title from data
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
// Chart
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal, // Enable horizontal scrolling
|
||||||
|
padding: const EdgeInsets.only(right: 40),
|
||||||
|
child: SizedBox(
|
||||||
|
width: (uniqueXValues.length * 80) +
|
||||||
|
80, // Adjust width dynamically
|
||||||
|
child: LineChart(
|
||||||
|
LineChartData(
|
||||||
|
lineTouchData: lineTouchData1(),
|
||||||
|
gridData: gridData(),
|
||||||
|
titlesData: titlesData1(uniqueXValues),
|
||||||
|
borderData: borderData(),
|
||||||
|
lineBarsData: lineBars,
|
||||||
|
minX: uniqueXValues.reduce((a, b) => a < b ? a : b),
|
||||||
|
maxX: uniqueXValues.reduce((a, b) => a > b ? a : b),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
case 'bar_chart':
|
case 'bar_chart':
|
||||||
// Extract groupBy values and their corresponding y-axis values
|
// Extract groupBy values and their corresponding y-axis values
|
||||||
@ -697,6 +828,106 @@ class ChartWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
))
|
))
|
||||||
]);
|
]);
|
||||||
|
case 'bar_chart_horizontal':
|
||||||
|
// Extract groupBy values and their corresponding y-axis values
|
||||||
|
List<String> xAxisData = [];
|
||||||
|
List<double> yAxisData = [];
|
||||||
|
|
||||||
|
for (var entry in chartData['response']) {
|
||||||
|
var xValue = entry['ObsKey'][groupByKey];
|
||||||
|
var yValue = entry['ObsValue']['Value'];
|
||||||
|
if (xValue != null && yValue != null) {
|
||||||
|
xAxisData.add(xValue.toString());
|
||||||
|
yAxisData.add(double.tryParse(yValue.toString()) ?? 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int rotationTurns = 1;
|
||||||
|
return Column(children: [
|
||||||
|
Text(
|
||||||
|
chartData['chart_heading'] ?? '', // Chart title from data
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
// Chart
|
||||||
|
Expanded(
|
||||||
|
child: BarChart(
|
||||||
|
BarChartData(
|
||||||
|
alignment: BarChartAlignment.spaceAround,
|
||||||
|
maxY: yAxisData.isNotEmpty
|
||||||
|
? yAxisData.reduce((a, b) => a > b ? a : b) * 1.2
|
||||||
|
: 10,
|
||||||
|
rotationQuarterTurns: rotationTurns,
|
||||||
|
barTouchData: BarTouchData(enabled: true),
|
||||||
|
titlesData: FlTitlesData(
|
||||||
|
leftTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: false,
|
||||||
|
interval: (yAxisData.isNotEmpty
|
||||||
|
? yAxisData.reduce((a, b) => a > b ? a : b) / 5
|
||||||
|
: 1),
|
||||||
|
getTitlesWidget: (value, meta) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: Text('${value.toInt()}'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
reservedSize: 60,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: true,
|
||||||
|
getTitlesWidget: (value, meta) {
|
||||||
|
if (value.toInt() < xAxisData.length) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Transform.rotate(
|
||||||
|
angle: -45 *
|
||||||
|
(3.1415927 / 180), // Rotating by -45 degrees
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
xAxisData[value.toInt()],
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
reservedSize: 60,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
topTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(showTitles: false), // Hide top titles
|
||||||
|
),
|
||||||
|
rightTitles: AxisTitles(
|
||||||
|
sideTitles:
|
||||||
|
SideTitles(showTitles: false), // Hide right titles
|
||||||
|
),
|
||||||
|
),
|
||||||
|
gridData: FlGridData(show: false),
|
||||||
|
borderData: FlBorderData(show: false),
|
||||||
|
barGroups: List.generate(
|
||||||
|
xAxisData.length,
|
||||||
|
(index) => BarChartGroupData(
|
||||||
|
x: index,
|
||||||
|
barRods: [
|
||||||
|
BarChartRodData(
|
||||||
|
toY: yAxisData[index],
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
]);
|
||||||
case 'fl_multi_bar':
|
case 'fl_multi_bar':
|
||||||
double _calculateChartWidth(dynamic chartData) {
|
double _calculateChartWidth(dynamic chartData) {
|
||||||
int totalBars = chartData['response']?.length ?? 0;
|
int totalBars = chartData['response']?.length ?? 0;
|
||||||
@ -712,6 +943,15 @@ class ChartWidget extends StatelessWidget {
|
|||||||
if (chartData['dataset'] == 'health_services') {
|
if (chartData['dataset'] == 'health_services') {
|
||||||
crop = item['ObsKey']['SECTOR'];
|
crop = item['ObsKey']['SECTOR'];
|
||||||
cropType = item['ObsKey'][groupByKey];
|
cropType = item['ObsKey'][groupByKey];
|
||||||
|
} else if (chartData['dataset'] == 'general_education') {
|
||||||
|
crop = item['ObsKey']['GENDER'];
|
||||||
|
cropType = item['ObsKey'][groupByKey];
|
||||||
|
} else if (chartData['dataset'] == 'higher_education') {
|
||||||
|
crop = item['ObsKey']['GENDER'];
|
||||||
|
cropType = item['ObsKey'][groupByKey];
|
||||||
|
} else if (chartData['dataset'] == 'labour_force') {
|
||||||
|
crop = item['ObsKey']['GENDER'];
|
||||||
|
cropType = item['ObsKey'][groupByKey];
|
||||||
} else {
|
} else {
|
||||||
crop = item['ObsKey']['CROP'];
|
crop = item['ObsKey']['CROP'];
|
||||||
cropType = item['ObsKey'][groupByKey];
|
cropType = item['ObsKey'][groupByKey];
|
||||||
@ -781,6 +1021,12 @@ class ChartWidget extends StatelessWidget {
|
|||||||
barTouchData: BarTouchData(
|
barTouchData: BarTouchData(
|
||||||
touchTooltipData: BarTouchTooltipData(
|
touchTooltipData: BarTouchTooltipData(
|
||||||
tooltipHorizontalAlignment: FLHorizontalAlignment.center,
|
tooltipHorizontalAlignment: FLHorizontalAlignment.center,
|
||||||
|
tooltipRoundedRadius: 8,
|
||||||
|
fitInsideHorizontally:
|
||||||
|
true, // Ensure it fits within the screen
|
||||||
|
fitInsideVertically: true,
|
||||||
|
tooltipPadding: EdgeInsets.all(8),
|
||||||
|
tooltipMargin: 16,
|
||||||
// Only show tooltip when touched
|
// Only show tooltip when touched
|
||||||
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
||||||
if (rod.toY == 0 || touchedGroupIndex == -1) {
|
if (rod.toY == 0 || touchedGroupIndex == -1) {
|
||||||
@ -873,8 +1119,14 @@ class ChartWidget extends StatelessWidget {
|
|||||||
|
|
||||||
// Iterate over the chartData to group crops by CROP_TYPE
|
// Iterate over the chartData to group crops by CROP_TYPE
|
||||||
for (var item in chartData['response']) {
|
for (var item in chartData['response']) {
|
||||||
String crop = item['ObsKey']['CROP'];
|
String crop, cropType;
|
||||||
String cropType = item['ObsKey']['CROP_TYPE'];
|
if (chartData['dataset'] == 'natural_reserves') {
|
||||||
|
crop = item['ObsKey']['NR_TYPE'];
|
||||||
|
cropType = item['ObsKey'][groupByKey];
|
||||||
|
} else {
|
||||||
|
crop = item['ObsKey']['CROP'];
|
||||||
|
cropType = item['ObsKey'][groupByKey];
|
||||||
|
}
|
||||||
|
|
||||||
if (groupedCrops.containsKey(cropType)) {
|
if (groupedCrops.containsKey(cropType)) {
|
||||||
groupedCrops[cropType]!.add(crop);
|
groupedCrops[cropType]!.add(crop);
|
||||||
@ -985,15 +1237,22 @@ class ChartWidget extends StatelessWidget {
|
|||||||
bottomTitles: AxisTitles(
|
bottomTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: true,
|
showTitles: true,
|
||||||
reservedSize: 20, // Added space for rotated titles
|
reservedSize: 80, // Added space for rotated titles
|
||||||
getTitlesWidget: (value, meta) {
|
getTitlesWidget: (value, meta) {
|
||||||
if (value < groupByValues.length) {
|
if (value < groupByValues.length) {
|
||||||
String title = groupByValues.elementAt(value.toInt());
|
String title = groupByValues.elementAt(value.toInt());
|
||||||
return Transform.rotate(
|
return Transform.rotate(
|
||||||
angle: -0.5, // Rotation in radians (~ -30 degrees)
|
angle: -1.58, // Rotation in radians (~ -30 degrees)
|
||||||
child: Text(
|
child: Center(
|
||||||
title,
|
child: SizedBox(
|
||||||
style: const TextStyle(fontSize: 12),
|
width: 80,
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
softWrap: true,
|
||||||
|
maxLines: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1010,7 +1269,7 @@ class ChartWidget extends StatelessWidget {
|
|||||||
show: true,
|
show: true,
|
||||||
border: const Border(
|
border: const Border(
|
||||||
// left: BorderSide(color: Colors.grey),
|
// left: BorderSide(color: Colors.grey),
|
||||||
bottom: BorderSide(color: Colors.grey),
|
bottom: BorderSide(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
gridData: FlGridData(
|
gridData: FlGridData(
|
||||||
@ -1084,47 +1343,25 @@ class ChartWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<LineChartBarData> lineBarsData2(List<dynamic> filteredData,
|
List<LineChartBarData> lineBarsData2(List<dynamic> filteredData) {
|
||||||
Set<String> groupByValues, String groupByKey) {
|
|
||||||
List<LineChartBarData> lineBars = [];
|
List<LineChartBarData> lineBars = [];
|
||||||
print('filteredData $filteredData');
|
|
||||||
print('filteredData222 $groupByValues');
|
|
||||||
final List<Color> uniqueColors = [
|
|
||||||
Color(0xFF648CBA),
|
|
||||||
Color(0xFF90B0D5),
|
|
||||||
Color(0xFF98BCE5),
|
|
||||||
Color(0xFFA7B5C5),
|
|
||||||
Color(0xFFBED3EC),
|
|
||||||
Color(0xFFD4E3F4),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Create a map to assign colors to each group in order
|
// Create a map to store population values by year and gender
|
||||||
Map<String, Color> groupColorMap = {};
|
|
||||||
int colorIndex = 0;
|
|
||||||
for (String group in groupByValues) {
|
|
||||||
groupColorMap[group] = uniqueColors[colorIndex % uniqueColors.length];
|
|
||||||
colorIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
print('Group-Color Map: $groupColorMap');
|
|
||||||
|
|
||||||
// Create a map to store the values by year and gender (M and F)
|
|
||||||
Map<int, Map<String, double>> yearGenderMap = {};
|
Map<int, Map<String, double>> yearGenderMap = {};
|
||||||
|
|
||||||
// Populate the yearGenderMap with male and female values
|
|
||||||
for (var entry in filteredData) {
|
for (var entry in filteredData) {
|
||||||
int year = int.parse(entry['ObsKey']['TIME_PERIOD']);
|
int year = int.tryParse(entry['ObsKey']['TIME_PERIOD'].toString()) ?? 0;
|
||||||
String gender = entry['ObsKey']['GENDER'];
|
String gender = entry['ObsKey']['GENDER'];
|
||||||
double value = double.parse(entry['ObsValue']['Value'].toString());
|
double value =
|
||||||
|
double.tryParse(entry['ObsValue']['Value'].toString()) ?? 0.0;
|
||||||
|
|
||||||
if (!yearGenderMap.containsKey(year)) {
|
if (!yearGenderMap.containsKey(year)) {
|
||||||
yearGenderMap[year] = {'M': 0.0, 'F': 0.0};
|
yearGenderMap[year] = {'M': 0.0, 'F': 0.0};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign value based on gender
|
if (gender == 'Male') {
|
||||||
if (gender == 'M') {
|
|
||||||
yearGenderMap[year]!['M'] = value;
|
yearGenderMap[year]!['M'] = value;
|
||||||
} else if (gender == 'F') {
|
} else if (gender == 'Female') {
|
||||||
yearGenderMap[year]!['F'] = value;
|
yearGenderMap[year]!['F'] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1205,7 +1442,14 @@ class ChartWidget extends StatelessWidget {
|
|||||||
// Helper functions for chart styles
|
// Helper functions for chart styles
|
||||||
LineTouchData lineTouchData1() {
|
LineTouchData lineTouchData1() {
|
||||||
return LineTouchData(
|
return LineTouchData(
|
||||||
touchTooltipData: LineTouchTooltipData(),
|
touchTooltipData: LineTouchTooltipData(
|
||||||
|
// tooltipBgColor: Colors.black.withOpacity(0.7), // Tooltip background
|
||||||
|
tooltipRoundedRadius: 8,
|
||||||
|
fitInsideHorizontally: true, // Ensure it fits within the screen
|
||||||
|
fitInsideVertically: true,
|
||||||
|
tooltipPadding: EdgeInsets.all(8),
|
||||||
|
tooltipMargin: 16, // Adds margin to prevent clipping
|
||||||
|
),
|
||||||
handleBuiltInTouches: true,
|
handleBuiltInTouches: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1534,6 +1778,12 @@ class ChartWidget extends StatelessWidget {
|
|||||||
toY: value, // Use the parsed value
|
toY: value, // Use the parsed value
|
||||||
color: barColor, // Dynamic color
|
color: barColor, // Dynamic color
|
||||||
width: 20,
|
width: 20,
|
||||||
|
// backDrawRodData: BackgroundBarChartRodData(
|
||||||
|
// show: true,
|
||||||
|
// toY: 400000,
|
||||||
|
// color: Colors.grey.shade300,
|
||||||
|
// ),
|
||||||
|
//
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
|||||||
@ -451,7 +451,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
controller: _usernameController,
|
controller: _usernameController,
|
||||||
focusNode: _focusNodes[0],
|
focusNode: _focusNodes[0],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: _showHints[0] ? 'Enter the User Name' : null,
|
// hintText: _showHints[0] ? 'Enter the User Name' : null,
|
||||||
hintStyle: TextStyle(color: Colors.grey),
|
hintStyle: TextStyle(color: Colors.grey),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
@ -477,8 +477,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
focusNode: _focusNodes[1],
|
focusNode: _focusNodes[1],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText:
|
// hintText:
|
||||||
_showHints[1] ? 'mohammad.hassan@fcsc.gov.ae' : null,
|
// _showHints[1] ? 'mohammad.hassan@fcsc.gov.ae' : null,
|
||||||
hintStyle: TextStyle(color: Colors.grey),
|
hintStyle: TextStyle(color: Colors.grey),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
|||||||
@ -354,14 +354,22 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
'Email',
|
'Email',
|
||||||
'بريد إلكتروني',
|
'بريد إلكتروني',
|
||||||
),
|
),
|
||||||
validator: FieldValidator.email(),
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return context.translate('Required', 'مطلوب');
|
||||||
|
}
|
||||||
|
return FieldValidator.email()(value);
|
||||||
|
},
|
||||||
imgPath: MiscIconAssetPath.person,
|
imgPath: MiscIconAssetPath.person,
|
||||||
controller: emailCtl,
|
controller: emailCtl,
|
||||||
),
|
),
|
||||||
15.verticalSpace,
|
15.verticalSpace,
|
||||||
ThemedFormField(
|
ThemedFormField(
|
||||||
validator: (text) {
|
validator: (text) {
|
||||||
if (text!.length < 8) {
|
if (text == null || text.isEmpty) {
|
||||||
|
return context.translate('Required', 'مطلوب');
|
||||||
|
}
|
||||||
|
else if (text.length < 8) {
|
||||||
return 'The password must be at least 8 characters';
|
return 'The password must be at least 8 characters';
|
||||||
}
|
}
|
||||||
return FieldValidator.password(minLength: 8)(text);
|
return FieldValidator.password(minLength: 8)(text);
|
||||||
@ -462,16 +470,16 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
prefs.clear();
|
prefs.clear();
|
||||||
final userId = 'guest';
|
final userId = 'guest';
|
||||||
if (userId.isNotEmpty) {
|
if (userId.isNotEmpty) {
|
||||||
await saveUserId(userId);
|
await saveUserId(userId);
|
||||||
}
|
}
|
||||||
context.go('/myhomepage');
|
context.go('/myhomepage');
|
||||||
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
||||||
},
|
},
|
||||||
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
shape: WidgetStatePropertyAll(
|
shape: WidgetStatePropertyAll(
|
||||||
RoundedRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
@ -515,7 +523,7 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
final fcscBanner = Image.asset(
|
final fcscBanner = Image.asset(
|
||||||
BannerAssetPath.fcsc,
|
BannerAssetPath.fcsc,
|
||||||
height: 56,
|
height: 40,
|
||||||
);
|
);
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
final listViewHorizontalPadding =
|
final listViewHorizontalPadding =
|
||||||
@ -528,14 +536,16 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
36.verticalSpace,
|
36.verticalSpace,
|
||||||
Align(
|
Align(
|
||||||
alignment: AlignmentDirectional.topEnd,
|
alignment: AlignmentDirectional.topEnd,
|
||||||
child: MyToggle(isOn: locale?.languageCode == 'en',
|
child: MyToggle(
|
||||||
|
isOn: locale?.languageCode == 'en',
|
||||||
knobTextWhenOn: 'ع',
|
knobTextWhenOn: 'ع',
|
||||||
knobTextWhenOff: 'EN',
|
knobTextWhenOff: 'EN',
|
||||||
pathColorWhenOn: Colors.grey.shade300,
|
pathColorWhenOn: Colors.grey.shade300,
|
||||||
pathColorWhenOff: Colors.grey.shade300,
|
pathColorWhenOff: Colors.grey.shade300,
|
||||||
onTap: (){
|
onTap: () {
|
||||||
ref.read(localeProvider.notifier).toggleLocale();
|
ref.read(localeProvider.notifier).toggleLocale();
|
||||||
},),
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
16.verticalSpace,
|
16.verticalSpace,
|
||||||
helloAndPleaseLoginTexts,
|
helloAndPleaseLoginTexts,
|
||||||
@ -543,9 +553,9 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
form,
|
form,
|
||||||
20.verticalSpace,
|
20.verticalSpace,
|
||||||
dontHaveAnAccountRegisterBtn,
|
dontHaveAnAccountRegisterBtn,
|
||||||
36.verticalSpace,
|
20.verticalSpace,
|
||||||
continueAsGuestBtn,
|
continueAsGuestBtn,
|
||||||
72.verticalSpace,
|
25.verticalSpace,
|
||||||
fcscBanner,
|
fcscBanner,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -753,14 +753,31 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.book),
|
leading: Icon(Icons.book),
|
||||||
title: const Text('User Guide'),
|
// title: const Text('User Guide'),
|
||||||
|
title: Text(AppLocalizations.of(context)!.guide_title),
|
||||||
onTap: () => context.go('/user-guide'),
|
onTap: () => context.go('/user-guide'),
|
||||||
),
|
),
|
||||||
ListTile(
|
if (userId != 'guest')
|
||||||
leading: Icon(Icons.logout),
|
ListTile(
|
||||||
title: const Text('Logout'),
|
leading: Icon(Icons.logout),
|
||||||
onTap: () => logout(),
|
// title: const Text('Logout'),
|
||||||
),
|
title: Text(AppLocalizations.of(context)!.logout),
|
||||||
|
onTap: () => logout(),
|
||||||
|
),
|
||||||
|
if (userId == 'guest')
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.login),
|
||||||
|
// title: const Text('Login'),
|
||||||
|
title: Text(AppLocalizations.of(context)!.login_title),
|
||||||
|
onTap: () => context.go('/login'),
|
||||||
|
),
|
||||||
|
if (userId == 'guest')
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(Icons.app_registration),
|
||||||
|
// title: const Text('Register'),
|
||||||
|
title: Text(AppLocalizations.of(context)!.register_title),
|
||||||
|
onTap: () => context.go('/register'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ name: uae_stat
|
|||||||
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
|
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
#version: 0.5.10
|
#version: 0.5.10
|
||||||
version: 1.0.2+3
|
version: 1.0.5+6
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.2.3 <4.0.0"
|
sdk: ">=3.2.3 <4.0.0"
|
||||||
@ -115,6 +115,8 @@ flutter:
|
|||||||
- assets/edit_profile/
|
- assets/edit_profile/
|
||||||
- assets/splash_screen/
|
- assets/splash_screen/
|
||||||
- assets/app_tour/
|
- assets/app_tour/
|
||||||
|
- assets/icons/uae_numbers/bookmarks.png
|
||||||
|
- assets/icons/uae_numbers/share.png
|
||||||
|
|
||||||
fonts:
|
fonts:
|
||||||
- family: Segoe
|
- family: Segoe
|
||||||
|
|||||||