Nottification and charts changes added

This commit is contained in:
venbaittech 2025-03-05 18:04:55 +05:30
parent de820662f7
commit 802a80a549
29 changed files with 2268 additions and 978 deletions

View File

@ -3,6 +3,7 @@ plugins {
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
id "com.google.gms.google-services"
}
def localProperties = new Properties()
@ -13,14 +14,18 @@ if (localPropertiesFile.exists()) {
}
}
if (project.hasProperty('google-services.json')) {
apply plugin: 'com.google.gms.google-services'
}
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "28"
flutterVersionCode = "31"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0.27"
flutterVersionName = "1.0.30"
}
def keystorePropertiesFile = rootProject.file("key.properties")
@ -46,7 +51,7 @@ android {
applicationId = "ae.gov.fcsc.frontend"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdk = flutter.minSdkVersion
minSdk = 23
targetSdk = flutter.targetSdkVersion
versionCode = flutterVersionCode.toInteger()
versionName = flutterVersionName
@ -75,3 +80,9 @@ android {
flutter {
source = "../.."
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
implementation 'com.google.firebase:firebase-messaging:22.0.0'
implementation("com.google.firebase:firebase-auth:23.0.0")
}

View File

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "62132243005",
"project_id": "fcsc-a161c",
"storage_bucket": "fcsc-a161c.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:62132243005:android:18b7ca94608afaeb7c7854",
"android_client_info": {
"package_name": "ae.gov.fcsc.frontend"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyB-QQbnq366f7rrKLVVFJKnSZgR9LcDWFI"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@ -63,4 +63,4 @@
<data android:mimeType="text/plain" />
</intent>
</queries>
</manifest>
</manifest>

View File

@ -1,3 +1,14 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0' // Update this if needed
classpath 'com.google.gms:google-services:4.3.10' // Required for Firebase
}
}
allprojects {
repositories {
google()

View File

@ -20,7 +20,7 @@ plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.2.1" apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
id("com.google.gms.google-services") version "4.4.2" apply false
}
include ":app"

BIN
assets/FCSC-GIF.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,3 +1,4 @@
// api_config.dart
// const String apiUrl = 'http://192.168.1.26:8090';
const String apiUrl = 'https://pbdev.venbait.in/';
// const String apiUrl = 'https://pbdev.venbait.in/';
const String apiUrl = 'https://pb.venbait.in/';

View File

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
class LoadingOverlay {
static final ValueNotifier<bool> _isLoading = ValueNotifier<bool>(false);
static void show() {
_isLoading.value = true;
}
static void hide() {
_isLoading.value = false;
}
static Widget buildLoader() {
return ValueListenableBuilder<bool>(
valueListenable: _isLoading,
builder: (context, isLoading, child) {
return isLoading
? Stack(
children: [
ModalBarrier(
color: Colors.black.withOpacity(0.5), dismissible: false),
Center(
child: Image.asset(
"assets/images/loading.gif", // Make sure to add the GIF in assets
width: 100,
height: 100,
),
),
],
)
: const SizedBox.shrink();
},
);
}
}

View File

@ -307,6 +307,7 @@ import 'package:uae_stat/presentation/Screens/charts/screens/chart_screen.dart';
import 'package:uae_stat/presentation/Screens/demo_home2.dart';
import 'package:uae_stat/presentation/Screens/online_offline_verification/internet_check.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/notification/notification.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/notification/notification_details.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/user_guide/AboutTheApp/AboutFCSC.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/user_guide/AboutTheApp/getStarted.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/user_guide/KeyFeatures/AppFeatures.dart';
@ -366,7 +367,6 @@ final GoRouter router = GoRouter(
path: '/',
//builder: (context, state) => LoginRoute(),
builder: (context, state) => SessionCheckScreen(),
),
// GoRoute(
// path: '/',
@ -426,8 +426,7 @@ final GoRouter router = GoRouter(
state.uri.queryParameters['filter_data']!.isNotEmpty) {
try {
filterData = List<Map<String, dynamic>>.from(
jsonDecode(state.uri.queryParameters['filter_data']!)
);
jsonDecode(state.uri.queryParameters['filter_data']!));
} catch (e) {
print('Error parsing filter_data: $e');
filterData = []; // Assign an empty list to prevent null issues
@ -436,8 +435,6 @@ final GoRouter router = GoRouter(
filterData = []; // Ensure it's a valid list
}
print('Router dataSets: $dataSets');
print('Router bgColor: $bgColor');
print('Router mainTopic: $mainTopic');
@ -521,6 +518,18 @@ final GoRouter router = GoRouter(
return NotificationPage();
},
),
GoRoute(
path: '/notification_details',
builder: (context, state) {
final Map<String, dynamic> data = state.extra as Map<String, dynamic>;
return NotificationDetails(
title: data['title'] ?? '',
message: data['message'] ?? '',
date: data['date'] ?? '',
category: data['category'] ?? '',
);
},
),
GoRoute(
path: '/user-guide',
builder: (context, state) => Userguide(),

View File

@ -51,6 +51,7 @@
"full_name": "الاسم الكامل",
"dob": "تاريخ الميلاد",
"region": "الدولة/المنطقة",
"preferredLang": "اللغة المفضلة",
"cancel": "إلغاء",
"confirm": "تأكيد",
"change_password": "تغيير كلمة المرور",

View File

@ -49,6 +49,7 @@
"full_name": "Full Name*",
"dob": "Date of Birth*",
"region": "Country/Region",
"preferredLang": "Preferred Language",
"cancel": "Cancel",
"confirm": "Confirm",
"change_password": "Change Password",

View File

@ -1,4 +1,6 @@
import 'package:external_repos/external_repos.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -16,8 +18,6 @@ import 'package:uae_stat/presentation/Screens/auth_verification/registration.dar
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
// void main() async {
// WidgetsFlutterBinding.ensureInitialized();
// // await (await SharedPreferences.getInstance()).clear();
@ -46,8 +46,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
// }
// }
// void main() async {
// WidgetsFlutterBinding.ensureInitialized();
// // await (await SharedPreferences.getInstance()).clear();
@ -91,10 +89,31 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
// }
// }
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// Handle background messages
print("Handling background message: ${message.messageId}");
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: const FirebaseOptions(
apiKey: 'AIzaSyB-QQbnq366f7rrKLVVFJKnSZgR9LcDWFI',
appId: '1:62132243005:android:18b7ca94608afaeb7c7854',
messagingSenderId: '62132243005',
projectId: 'fcsc-a161c'));
FirebaseMessaging messaging = FirebaseMessaging.instance;
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// Request permission for notifications
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
print('User granted permission: ${settings.authorizationStatus}');
configureDependencies();
runApp(
const ProviderScope(
@ -106,9 +125,6 @@ void main() async {
class MainApp extends ConsumerWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final locale = ref.watch(localeProvider);
@ -117,14 +133,13 @@ class MainApp extends ConsumerWidget {
return true; // Replace with actual logic
});
// ref.listen<bool>(connectivityProvider, (previous, hasInternet) {
// print('Previous Internet Status: $previous');
// print('Current Internet Status: $hasInternet');
// if (previous != null && hasInternet != previous) {
// handleConnectivityChange(context, hasInternet);
// }
// });
ref.listen<bool>(connectivityProvider, (previous, hasInternet) {
print('Previous Internet Status: $previous');
print('Current Internet Status: $hasInternet');
if (previous != null && hasInternet != previous) {
handleConnectivityChange(context, hasInternet);
}
});
return MaterialApp.router(
debugShowCheckedModeBanner: false,
@ -137,7 +152,8 @@ class MainApp extends ConsumerWidget {
void handleConnectivityChange(BuildContext context, bool hasInternet) {
//final currentPath = GoRouter.of(context).location;
final currentPath = GoRouter.of(context).routerDelegate.currentConfiguration.fullPath;
final currentPath =
GoRouter.of(context).routerDelegate.currentConfiguration.fullPath;
if (!hasInternet && currentPath != '/internetcheck') {
print("Status : Not connected");
context.go('/internetcheck');
@ -147,6 +163,3 @@ class MainApp extends ConsumerWidget {
}
}
}

View File

@ -12,7 +12,7 @@ import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.
import 'package:uae_stat/presentation/components/constant/constant.dart';
import 'package:http/http.dart' as http;
import 'package:uae_stat/config/api_config.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class UaeNumbers extends StatelessWidget {
const UaeNumbers({super.key});
@ -198,14 +198,17 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
value); // Call filter function directly on input change
},
decoration: InputDecoration(
hintText: "Search",
hintStyle: TextStyle(color: Color(0xFF898C81)),
prefixIconConstraints: BoxConstraints(maxWidth: 42, maxHeight: 42),
hintText: AppLocalizations.of(context)!.search,
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
prefixIconConstraints:
BoxConstraints(maxWidth: 42, maxHeight: 42),
prefixIcon: Container(
padding: EdgeInsets.only(right: 5),
padding: EdgeInsets.only(right: 5, left: 5),
child: SvgPicture.asset(
MiscIconAssetPath.Search,
semanticsLabel: 'Search',
colorFilter:
ColorFilter.mode(Color(0xFFAA8E83), BlendMode.srcIn),
),
),
@ -215,7 +218,7 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
// ),
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 18.0),
EdgeInsets.symmetric(vertical: 0.5, horizontal: 18.0),
),
),
),

View File

@ -54,7 +54,7 @@ class ChartScreen1 extends ConsumerStatefulWidget {
class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// final _pb = PocketBase('https://pb.venbait.in');
final _pb = PocketBase(apiUrl);
List<Map<String, dynamic>> selectedFiltersStorage = [];
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final ApiService apiService = ApiService();
bool isLoading = true;
@ -68,6 +68,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
List<dynamic> tabFilteredCardData = [];
List<dynamic> cardData = [];
List<Map<String, dynamic>> filteredAndSortedData = [];
List<Map<String, dynamic>> selectedFiltersStorage = [];
List<Map<String, dynamic>> selectedFiltersApi = [];
List<dynamic> originalChartsData = [];
List<dynamic> originalCardData = [];
List<dynamic> originalTabCardData = [];
@ -75,11 +77,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
late Color backgroundColor;
final ScrollController _scrollController = ScrollController();
int _activeTabIndex = 0;
dynamic tabWiseKpi=[];
dynamic tabFilteredKpi=[];
List<Map<String, dynamic>> formattedFilters=[];
dynamic tabWiseKpi = [];
dynamic tabFilteredKpi = [];
List<Map<String, dynamic>> formattedFilters = [];
dynamic _tabsData = [];
dynamic currentTab = [];
// List<Map<String, dynamic>> _tabsData = [];
late List<TargetFocus> marriageTargets;
late List<TargetFocus> previousMarriageTargets;
@ -90,6 +93,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
bool isBookmarked = false; // Track bookmark state
String? bookmarkId; // Stores the ID of the bookmark record in PocketBase
late final Locale locale;
late String mainTopic;
@override
void initState() {
@ -98,10 +102,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
print(' bgColor $bgColor');
checkIfBookmarked();
locale = ref.read(localeProvider) ?? const Locale('en');
print('locale-$locale');
fetchChartData(widget.dataSets, locale?.languageCode ?? 'en', widget.kpi, widget.filter_data)
.then((_) {
if(_tabsData.isNotEmpty) {
fetchChartData(widget.dataSets, locale?.languageCode ?? 'en', widget.kpi,
widget.filter_data)
.then((_) {
if (_tabsData.isNotEmpty) {
// Call onTabSelected for the first tab
onTabSelected(_tabsData[0]['id']);
}
@ -313,7 +319,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
backgroundColor: Color(0xFFAA8E83), // Set background color
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), // Set text color
borderRadius:
BorderRadius.circular(10.0), // Set text color
),
),
child: Text(
@ -324,7 +331,6 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
),
],
)
],
),
);
@ -371,29 +377,30 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ SizedBox(
width: 100, // Set the desired width
child: TextButton(
onPressed: () => Navigator.pop(context),
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
10.0), // Adjust the radius as needed
children: [
SizedBox(
width: 100, // Set the desired width
child: TextButton(
onPressed: () => Navigator.pop(context),
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
10.0), // Adjust the radius as needed
),
side: BorderSide(
color: Color(0xFFAA8E83), // Set the outline color
width: 1, // Set the border width
),
),
side: BorderSide(
color: Color(0xFFAA8E83), // Set the outline color
width: 1, // Set the border width
),
),
child: Text(
context.translate('No', 'لا'),
style: TextStyle(
color: Color(0xFFAA8E83),
fontSize: 16,
child: Text(
context.translate('No', 'لا'),
style: TextStyle(
color: Color(0xFFAA8E83),
fontSize: 16,
),
),
),
),
),
SizedBox(
width: 100, // Set the desired width
child: TextButton(
@ -405,7 +412,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
backgroundColor: Color(0xFFAA8E83), // Set background color
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), // Set text color
borderRadius:
BorderRadius.circular(10.0), // Set text color
),
),
child: Text(
@ -413,7 +421,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),],
),
],
),
],
),
@ -1268,13 +1277,28 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
});
}
Future<void> fetchChartData(String dataSets, locale, kpi, filter_data ) async {
var data = await apiService.fetchChartData(dataSets, locale,kpi,filter_data);
Future<void> fetchChartData(String dataSets, locale, kpi, filter_data) async {
var data =
await apiService.fetchChartData(dataSets, locale, kpi, filter_data);
tabFilteredKpi = kpi;
print('FETCH KPI- $kpi');
print('FETCH KFilter- $filter_data');
print('locale1 - $locale');
// print('locale11 - $loacleData');
// Store filter_data if it has a value
if (filter_data != null && filter_data is List && filter_data.isNotEmpty) {
selectedFiltersApi = filter_data.map<Map<String, dynamic>>((entry) {
if (entry is Map<dynamic, dynamic>) {
return entry.map<String, dynamic>(
(key, value) => MapEntry(key.toString(), value));
}
return {};
}).toList();
print('FETVCFILTEr: $selectedFiltersApi');
}
if (data.containsKey('filterData')) {
var filterData = data['filterData'];
@ -1316,7 +1340,6 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
void applyFilters(BuildContext context, List filters, List data,
List dataCard, List selectedFilters) {
print('applyFilters called');
print('Selected ApplyFilters: $selectedFilters');
@ -1332,37 +1355,38 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}
// Transform the selectedFilters list into the required format
formattedFilters = selectedFilters
.where((filter) => filter['filter_data'] != null && filter['filter_data'].isNotEmpty)
.map((filter){
return{
formattedFilters = selectedFilters
// .where((filter) => filter['filter_data'] != null && filter['filter_data'].isNotEmpty)
.map((filter) {
return {
'filter_key': filter['filter_key'],
'filter_data':filter['filter_data'].map((item)=> item.toString()).toList()
'filter_data':
filter['filter_data'].map((item) => item.toString()).toList()
};
}).toList();
print('Formatted Filters1: $formattedFilters');
// Convert to JSON format
String selectedFormatFilters = jsonEncode({
'kpi': tabWiseKpi,
'filter_data': formattedFilters
});
String selectedFormatFilters =
jsonEncode({'kpi': tabWiseKpi, 'filter_data': formattedFilters});
print('Formatted Filters2: $selectedFormatFilters');
final locale = ref.watch(localeProvider)?.languageCode ?? 'en';
// Call fetchChartData with correct parameters
print('locale2- $locale');
// Call fetchChartData with correct parameters
fetchChartData(
widget.dataSets,
locale.languageCode ?? 'en',
locale,
tabWiseKpi, // Ensure you are passing the correct KPI here
formattedFilters // Pass the formatted filter data here
);
);
Navigator.pop(context);
selectedFiltersStorage = List.from(selectedFilters);
print('selectedFiltersStoraged- $selectedFiltersStorage');
}
void applyFilters1(BuildContext context, List filters, List data,
@ -1503,7 +1527,6 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}
void showRightSideModal(BuildContext context, List filters, List data) {
print('selectedFiltersStoraged1- $selectedFiltersStorage');
// Initialize selected filters structure from the stored value, if exists
@ -1532,7 +1555,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// Header Section
Padding(
padding: const EdgeInsets.only(
top: 16.0, bottom: 0.0, left: 16.0, right: 16.0),
top: 26.0, bottom: 0.0, left: 16.0, right: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -1541,7 +1564,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
SvgPicture.asset(
UaeNumbersAssetPath.filterCharts,
semanticsLabel: 'Filter',
colorFilter:ColorFilter.mode(Color(0xFF8E8E8E),BlendMode.srcIn),
colorFilter: ColorFilter.mode(
Color(0xFF8E8E8E), BlendMode.srcIn),
width: 25,
height: 25,
),
@ -1617,6 +1641,7 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
builder: (context, dialogSetState) {
final locale =
ref.watch(localeProvider);
print('localelocale $locale');
return AlertDialog(
title: Text(
@ -1786,13 +1811,13 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
cardData = List.from(originalTabCardData);
});
selectedFiltersStorage.clear();
formattedFilters = [];
formattedFilters = [];
fetchChartData(
widget.dataSets,
locale.languageCode ?? 'en',
tabWiseKpi, // Ensure you are passing the correct KPI here
formattedFilters // Pass the formatted filter data here
);
);
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
@ -1877,9 +1902,14 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
void onTabSelected(String tabId) {
print('Selected Tab on: $tabId');
tabWiseKpi = tabId;
print('Selected Tab tabWiseKpi: $tabWiseKpi');
selectedFiltersStorage.clear();
if (selectedFiltersApi.isNotEmpty && tabWiseKpi == tabFilteredKpi) {
selectedFiltersStorage = List.from(selectedFiltersApi);
}
// selectedFiltersStorage.clear();
// Filter the filterDataSet
filterData = filterDataSet
.where((item) => item['key'] == tabId)
.map((item) => item['value'])
@ -1887,9 +1917,63 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
.expand((item) => item)
.toList();
print("FilteringDAtss START1 - $filterData");
print("FilteringDAtss START1d - $filterData");
print('TABId1 - $tabId');
Map<String, int> monthMap = {
'jan': 1,
'feb': 2,
'mar': 3,
'apr': 4,
'may': 5,
'jun': 6,
'jul': 7,
'aug': 8,
'sep': 9,
'oct': 10,
'nov': 11,
'dec': 12
};
for (var item in filterData) {
if (item['filter_key'] == 'TIME_PERIOD') {
List<String> timePeriods = List<String>.from(item['filter_data']);
timePeriods.sort((a, b) {
List<String> aParts = a.split(RegExp(r'[-_]'));
List<String> bParts = b.split(RegExp(r'[-_]'));
int yearA = int.parse(aParts[0]);
int yearB = int.parse(bParts[0]);
// if (yearA != yearB) return yearA.compareTo(yearB);
if (yearA != yearB)
return yearB.compareTo(yearA); // Sort years in descending order
if (aParts.length == 1) return -1; // Year-only comes first
if (bParts.length == 1) return 1; // Year-only comes first
int monthA =
int.tryParse(aParts[1]) ?? monthMap[aParts[1].toLowerCase()] ?? 0;
int monthB =
int.tryParse(bParts[1]) ?? monthMap[bParts[1].toLowerCase()] ?? 0;
return monthB.compareTo(
monthA); // Sort months in descending order within the same year
// return monthA.compareTo(monthB);
});
item['filter_data'] = timePeriods;
} else if (item['filter_key'] == 'REF_AREA') {
continue;
} else {
// Sort alphabetically for all other cases
List<String> otherFilters = List<String>.from(item['filter_data']);
otherFilters.sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
item['filter_data'] = otherFilters;
}
}
// for (var item in filterData) {
// if (item['filter_key'] == 'TIME_PERIOD') {
// // Convert the values to integers, sort them, and convert back to strings
@ -1914,7 +1998,6 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
}
void performActionForTab(String tabId) {
print('Selected Tab perform: $tabId');
// Filter the chartsData array based on the tabId
@ -2007,25 +2090,39 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Widget build(BuildContext context) {
final locale = ref.watch(localeProvider);
final localeNotifier = ref.read(localeProvider.notifier);
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
// fetchChartData(widget.dataSets, localeCode);
print('Saving currentTab: $tabWiseKpi before locale change');
print('localeCodeWgt- $localeCode');
currentTab = tabWiseKpi;
print('Saving currentTab: $currentTab After locale change');
final List<Map<String, dynamic>> safeFilterData = widget.filter_data ?? [];
final List<Map<String, dynamic>> safeFilterData =
widget.filter_data ?? [];
final String safeKpi = widget.kpi ?? '';
fetchChartData(widget.dataSets,localeCode, safeKpi, safeFilterData).then((_) {
fetchChartData(widget.dataSets, localeCode, safeKpi, safeFilterData)
.then((_) {
print('DEBUG KPI: $safeKpi');
if (_tabsData.isNotEmpty) {
print('TAB11: $currentTab');
if (currentTab.isNotEmpty) {
// Call onTabSelected for the first tab
onTabSelected(currentTab);
print('TAB1: $currentTab');
} else if (_tabsData.isNotEmpty) {
// Call onTabSelected for the first tab
print('TAB2: $_tabsData');
onTabSelected(_tabsData[0]['id']);
}
});
});
double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width;
mainTopic = chartScreenData['main_topic'] ?? '';
int crossAxisCount =
cardData.isNotEmpty ? (cardData.length / 2).ceil().clamp(1, 2) : 1;
@ -2046,8 +2143,10 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
(chartScreenData['body_color'] ?? '#898C81').replaceFirst('#', '0xff'),
),
);
final chartHeader = chartScreenData['main_topic'] ?? '';
print('ChartScrnBodyColor');
print('chartHeader - $chartHeader');
print(chartScreenData['body_color']);
print(
Color(int.parse((chartScreenData['body_color'] ?? '#898C81')
@ -2098,7 +2197,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
children: [
Text(
// widget.mainTopic ?? '',
chartScreenData['main_topic'] ?? '',
// chartScreenData['main_topic'] ?? '',
mainTopic,
style: TextStyle(
color: Colors.white,
fontSize: 26,
@ -2223,28 +2323,29 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Row(
children: [
GestureDetector(
onTap: () => shareCurrentPage(context),
child: Row(
onTap: () => shareCurrentPage(context),
child: Row(
children: [
Text(
context.translate(
'Share',
'يشارك',
Text(
context.translate(
'Share',
'يشارك',
),
style: const TextStyle(
fontSize: 16,
color: Colors.white,
),
),
style: const TextStyle(
fontSize: 16,
color: Colors.white,
),
),
SizedBox(width: 5),
SvgPicture.asset(
UaeNumbersAssetPath.share,
semanticsLabel: 'share',
width: 24,
height: 24,
)
],),),
SizedBox(width: 5),
SvgPicture.asset(
UaeNumbersAssetPath.share,
semanticsLabel: 'share',
width: 24,
height: 24,
)
],
),
),
],
),
SizedBox(
@ -2353,7 +2454,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// ),
// nonChartData Cards
Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.only(
top: 8.0, left: 1.0, right: 1.0),
child: LayoutBuilder(
builder: (context, constraints) {
List<Widget> rows = [];
@ -2431,23 +2533,32 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
children: [
// ConstrainedBox
Container(
height: (chartsData[index]
['chart_type'] ==
'pie_chart')
? 500
: (chartsData[index][
'chart_type'] ==
'bar_chart_horizontal')
? 370
: (chartsData[index]['chart_type'] == 'fl_stacked_bar')
? 390
: 350,
height: (chartsData[index]
['chart_type'] ==
'pie_chart')
? 500
: (chartsData[index][
'chart_type'] ==
'bar_chart_horizontal')
? 370
: (chartsData[index][
'chart_type'] ==
'horizontal_rotate')
? 385
: (chartsData[index]
[
'chart_type'] ==
'fl_stacked_bar')
? 390
: 350,
// child: buildChart(chartsData[index]),
child: ChartWidget(
chartData:
chartsData[index],
bodyColor: bodyColor))
// child: buildChart(chartsData[index]),
child: ChartWidget(
chartData:
chartsData[index],
bodyColor: bodyColor,
chartHeader: chartHeader),
)
],
),
),
@ -2595,16 +2706,14 @@ class CardWidget extends StatelessWidget {
final bodyColor = Color(
int.parse(
(chartScreenData['body_color'] ?? '#898C81').replaceFirst('#', '0xff'),
(chartScreenData['border_color'] ?? '#898C81')
.replaceFirst('#', '0xff'),
),
);
if(response.isEmpty)
{
return SizedBox.shrink();
}
else if (response.length == 1) {
if (response.isEmpty) {
return SizedBox.shrink();
} else if (response.length == 1) {
return Container(
margin: const EdgeInsets.all(10),
// width: card_full_length ? double.infinity : null,
@ -2626,7 +2735,7 @@ class CardWidget extends StatelessWidget {
elevation: 2,
child: Container(
// height: cardHeight,
height: 160,
height: 175,
padding: const EdgeInsets.only(
left: 16.0, right: 16.0, bottom: 2.0, top: 1.0),
decoration: BoxDecoration(
@ -2757,7 +2866,7 @@ class CardWidget extends StatelessWidget {
elevation: 0, // Remove shadow to keep only the outli
child: Container(
height: 160,
height: 175,
padding: const EdgeInsets.all(10.0),
// padding: const EdgeInsets.only(
// left: 10.0, right: 10.0, bottom: 5.0, top: 1.0),
@ -2767,7 +2876,8 @@ class CardWidget extends StatelessWidget {
BorderRadius.circular(12), // Ensure border radius is applied
),
child: Column(
mainAxisSize: MainAxisSize.min, // Adjust card height based on content
mainAxisSize:
MainAxisSize.min, // Adjust card height based on content
mainAxisAlignment: MainAxisAlignment.center,
children: [
// const Icon(Icons.public,
@ -2840,8 +2950,6 @@ class CardWidget extends StatelessWidget {
),
const SizedBox(height: 1),
Row(
mainAxisAlignment: MainAxisAlignment
.center, // Center-aligns the row contents
@ -2870,19 +2978,15 @@ class CardWidget extends StatelessWidget {
],
),
SizedBox(
height: 2, // Height of the divider
width: 100,
width: 100,
child: Divider(
color: Color(0xFFBBBCBD),
thickness: 1, // Divider line thickness
),
),
Row(
mainAxisAlignment: MainAxisAlignment
.center, // Center-aligns the row contents
@ -2897,7 +3001,8 @@ class CardWidget extends StatelessWidget {
: _getColorFromHex(response[1]['font_color']),
),
textAlign: TextAlign.center, // Ensure proper alignment
overflow: TextOverflow.ellipsis, // Truncate if text overflows
overflow:
TextOverflow.ellipsis, // Truncate if text overflows
),
const SizedBox(width: 1), // Space between text and icon
if (response[1]['font_color'] != '') ...[
@ -2911,7 +3016,6 @@ class CardWidget extends StatelessWidget {
],
),
Text(
// '(${response[1]['display_value'] ?? 'NA'})',
RegExp(r'\d').hasMatch(response[1]['display_value'] ?? '')

View File

@ -16,7 +16,7 @@ class ApiService {
// static const String baseUrl = 'https://pb.venbait.in/api/getDataSet';
static const String baseUrl = '$apiUrl/api/getDataSet';
Future<Map<String, dynamic>> fetchChartData(String dataSets, locale,kpi,
Future<Map<String, dynamic>> fetchChartData(String dataSets, locale, kpi,
List<Map<String, dynamic>> filterData) async {
List<dynamic> isChartData = [];
List<dynamic> nonChartData = [];
@ -28,14 +28,14 @@ class ApiService {
// '$baseUrl?dataset=$dataSets&language=$locale&kpi=$kpi&filter_data=${Uri.encodeComponent(jsonEncode(filterData))}'
// );
final url = Uri.parse(baseUrl); // No query parameters in URL for POST
final Map<String, dynamic> requestBody = {
'dataset': dataSets,
'language': locale,
'kpi': kpi.isNotEmpty ? kpi : null, // Avoid sending empty kpi
'filter_data': filterData.isNotEmpty ? filterData : null, // Avoid empty list
'filter_data':
filterData.isNotEmpty ? filterData : [], // Avoid empty list
};
// final url = Uri.https('$baseUrl?dataset=$dataSets&language=$locale');
@ -66,8 +66,9 @@ class ApiService {
nonChartData.add(item);
}
}
final Map<String, dynamic> chartScreenData = jsonData['screen_heading_and_color'];
final Map<String, dynamic> chartScreenData =
jsonData['screen_heading_and_color'];
// Save original data for reset
// originalChartsData = List.from(isChartData); // Store original data
// originalCardData = List.from(nonChartData); // Store original data
@ -77,7 +78,7 @@ class ApiService {
'isChartData': isChartData,
'nonChartData': nonChartData,
'filterData': jsonData['new_filter_data'],
'chartScreenData' :chartScreenData
'chartScreenData': chartScreenData
// 'filterData': jsonData['filter_data']
// 'originalChartsData': originalChartsData,
// 'originalCardData': originalCardData,
@ -195,4 +196,4 @@ class ApiService {
return '$amount';
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,9 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
'India',
'Canada'
];
final List<String> preferred_language = ['English', 'Arabic'];
String? _selectedCountry;
String? _selectedLanguage;
bool isChecked = false;
bool showError = false;
final _picker = ImagePicker();
@ -86,6 +88,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
late Future<RecordModel> userDetails;
bool _isHoveringDate = false;
bool _isHoveringDropdown = false;
bool _isHoveringPreferredLang = false;
@override
void initState() {
@ -187,10 +190,10 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
_isLoading = true; // Start loading
});
final XFile? pickedFile =
await _picker.pickImage(source: ImageSource.gallery);
await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
final String fileExtension =
pickedFile.path.split('.').last.toLowerCase();
pickedFile.path.split('.').last.toLowerCase();
if (fileExtension == 'jpg' ||
fileExtension == 'jpeg' ||
fileExtension == 'png' ||
@ -227,7 +230,8 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
builder: (context, child) {
return Theme(
data: Theme.of(context).copyWith(
dialogBackgroundColor: Colors.white, // Background color of the date picker
dialogBackgroundColor:
Colors.white, // Background color of the date picker
textButtonTheme: TextButtonThemeData(
style: ButtonStyle(
shape: WidgetStateProperty.all(RoundedRectangleBorder(
@ -237,8 +241,10 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
),
datePickerTheme: DatePickerThemeData(
confirmButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Color(0xFFAA8E83)), // OK button background color
foregroundColor: WidgetStateProperty.all(Colors.white), // OK button text color
backgroundColor: WidgetStateProperty.all(
Color(0xFFAA8E83)), // OK button background color
foregroundColor: WidgetStateProperty.all(
Colors.white), // OK button text color
// minimumSize: WidgetStateProperty.all(Size(150, 50)),
minimumSize: WidgetStateProperty.all(Size(100, 40)),
shape: WidgetStateProperty.all(RoundedRectangleBorder(
@ -247,12 +253,14 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
),
cancelButtonStyle: ButtonStyle(
// backgroundColor: WidgetStateProperty.all(Colors.white), // Cancel button background color
foregroundColor: WidgetStateProperty.all(Color(0xFFAA8E83)), // Cancel button text color
foregroundColor: WidgetStateProperty.all(
Color(0xFFAA8E83)), // Cancel button text color
// minimumSize: WidgetStateProperty.all(Size(150, 50)),
minimumSize: WidgetStateProperty.all(Size(100, 40)),
shape: WidgetStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0), // Rounded corners
side: const BorderSide(color: Color(0xFFAA8E83), width: 2), // Outline color
side: const BorderSide(
color: Color(0xFFAA8E83), width: 2), // Outline color
)),
),
),
@ -262,7 +270,6 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
},
);
if (pickedDate != null && pickedDate != _selectedDate) {
setState(() {
_selectedDate = pickedDate;
@ -282,7 +289,8 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
// Check if the selected date is in the future
if (selectedDate.isAfter(today)) {
return context.translate('Date of birth cannot be in the future','لا يمكن أن يكون تاريخ الميلاد في المستقبل');
return context.translate('Date of birth cannot be in the future',
'لا يمكن أن يكون تاريخ الميلاد في المستقبل');
}
return null;
}
@ -315,6 +323,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
// String email = 'surendarsuri30@gmail.com';
String dateOfBirth = _dateController.text; // in DD/MM/YYYY format
String countryRegion = _selectedCountry ?? '';
String preferredLang = _selectedLanguage == 'English' ? 'en' : 'ar';
bool termsAccepted = isChecked;
// Parse the date from dd/MM/yyyy format and convert to yyyy-MM-dd
@ -324,13 +333,14 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
// Create a multipart request
final uri =
Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID');
Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID');
final request = http.MultipartRequest('PATCH', uri);
// Add other fields
request.fields['full_name'] = fullName;
request.fields['dob'] = formattedDob;
request.fields['country_region'] = countryRegion;
request.fields['language'] = preferredLang;
request.fields['is_profile_completed'] = 'True';
// Add the file, if available
@ -371,6 +381,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
_fullNameController.clear();
_dateController.clear();
_selectedCountry = null;
_selectedLanguage = null;
isChecked = false;
// Reset profile image
@ -399,14 +410,15 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
'Logout',
'تسجيل الخروج',
),
style: TextStyle(color: Color(0xFF898C81),fontWeight: FontWeight.w700),
style:
TextStyle(color: Color(0xFF898C81), fontWeight: FontWeight.w700),
),
content: Text(
context.translate(
'Are you sure you want to logout?',
'هل أنت متأكد أنك تريد تسجيل الخروج؟',
),
style: TextStyle(color:Color(0xFF898C81)),
style: TextStyle(color: Color(0xFF898C81)),
),
actions: [
TextButton(
@ -414,7 +426,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
style: TextButton.styleFrom(
// backgroundColor:
// Color(0xFFAA8E83), // Set background color
side: BorderSide(color: Color(0xFFAA8E83), width: 2),
side: BorderSide(color: Color(0xFFAA8E83), width: 2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), // Set text color
),
@ -432,12 +444,10 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
TextButton(
onPressed: () => logout(context), // Exit the app
style: TextButton.styleFrom(
backgroundColor:
Color(0xFFAA8E83), // Set background color
backgroundColor: Color(0xFFAA8E83), // Set background color
// foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10.0), // Set text color
borderRadius: BorderRadius.circular(10.0), // Set text color
),
),
child: Text(
@ -560,7 +570,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
backgroundImage: _profileImage != null
? FileImage(_profileImage!)
: AssetImage("assets/edit_profile/profile.png")
as ImageProvider,
as ImageProvider,
child: Align(
alignment: Alignment.bottomRight,
child: GestureDetector(
@ -584,7 +594,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(Colors.grey),
AlwaysStoppedAnimation<Color>(Colors.grey),
),
),
],
@ -673,19 +683,18 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$");
if (!nameRegex.hasMatch(value)) {
return AppLocalizations.of(context)!.invalid_characters;
return AppLocalizations.of(context)!
.invalid_characters;
}
return null;
},
controller: _fullNameController,
focusNode: _focusNodes[2],
decoration: InputDecoration(
enabledBorder:OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
color: MyTheme.topicColor(IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
@ -695,7 +704,8 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
fontSize: 14,
),
border: OutlineInputBorder(
borderSide:BorderSide(color: Color(0xFF7296BE),
borderSide: BorderSide(
color: Color(0xFF7296BE),
),
borderRadius: BorderRadius.circular(8),
),
@ -723,17 +733,17 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
controller: _dateController,
focusNode: _focusNodes[3],
decoration: InputDecoration(
enabledBorder:OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
.shade400,
color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
border: OutlineInputBorder(
borderSide:BorderSide(color: Color(0xFF7296BE),
borderSide: BorderSide(
color: Color(0xFF7296BE),
),
borderRadius: BorderRadius.circular(8),
),
@ -748,10 +758,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
width: 45,
padding: EdgeInsets.only(right: 1),
alignment:
Alignment.center, // Center the icon vertically
Alignment.center, // Center the icon vertically
child: Icon(
Icons.keyboard_arrow_down_sharp,
color: _isHoveringDate ? Colors.black : Colors.grey,
color:
_isHoveringDate ? Colors.black : Colors.grey,
),
),
),
@ -773,35 +784,37 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
),
SizedBox(height: 10),
MouseRegion(
onEnter: (_) => setState(() => _isHoveringDropdown = true),
onExit: (_) => setState(() => _isHoveringDropdown = false),
onEnter: (_) =>
setState(() => _isHoveringDropdown = true),
onExit: (_) =>
setState(() => _isHoveringDropdown = false),
child: DropdownButtonFormField<String>(
value: _selectedCountry,
decoration: InputDecoration(
enabledBorder:OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
border: OutlineInputBorder(
borderSide:BorderSide(color: Color(0xFF7296BE),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
borderRadius: BorderRadius.circular(8),
),
labelText: context.translate('Select',' اختيار')
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFF7296BE),
),
borderRadius: BorderRadius.circular(8),
),
labelText: context.translate('Select', ' اختيار')),
icon: Icon(Icons.keyboard_arrow_down_sharp,
color:
_isHoveringDropdown ? Colors.black : Colors.grey),
color: _isHoveringDropdown
? Colors.black
: Colors.grey),
items: _countries
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(item),
))
value: item,
child: Text(item),
))
.toList(),
onChanged: (String? newValue) {
setState(() {
@ -811,6 +824,59 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
validator: _validateDropdown,
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.preferredLang,
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w500),
),
],
),
SizedBox(height: 10),
MouseRegion(
onEnter: (_) =>
setState(() => _isHoveringPreferredLang = true),
onExit: (_) =>
setState(() => _isHoveringPreferredLang = false),
child: DropdownButtonFormField<String>(
value: _selectedLanguage,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xFF7296BE),
),
borderRadius: BorderRadius.circular(8),
),
labelText: context.translate('Select', ' اختيار')),
icon: Icon(Icons.keyboard_arrow_down_sharp,
color: _isHoveringPreferredLang
? Colors.black
: Colors.grey),
items: preferred_language
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(item),
))
.toList(),
onChanged: (String? newValue) {
setState(() {
_selectedLanguage = newValue;
});
},
validator: _validateDropdown,
),
),
SizedBox(height: 20),
Row(
children: [
@ -823,53 +889,48 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
});
},
side: BorderSide(
color:
showError ? Color(0xFFb22222) : Color(0xFF7296BE),
color: showError
? Color(0xFFb22222)
: Color(0xFF7296BE),
width: 1,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(
top: 14.0,),
top: 14.0,
),
child: Text.rich(
TextSpan(
text: AppLocalizations.of(
context)!
.agree,
text: AppLocalizations.of(context)!.agree,
// text: 'I agree to ',
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
color: Color(
0xFF898C81,), // Change to your desired color
0xFF898C81,
), // Change to your desired color
),
children: [
TextSpan(
recognizer:TapGestureRecognizer()
..onTap = () => context.push('/terms&conditions'),
text: AppLocalizations.of(
context)!
recognizer: TapGestureRecognizer()
..onTap = () =>
context.push('/terms&conditions'),
text: AppLocalizations.of(context)!
.terms_conditions,
// text: 'Terms & Conditions',
style: TextStyle(
fontSize: 14,
fontWeight:
FontWeight.bold,
color:
Color(0xFF985400),
fontWeight: FontWeight.bold,
color: Color(0xFF985400),
// Makes the text bold
// decoration:
// TextDecoration.underline,
decorationColor:
Color(0xFF985400),
decorationThickness:
1),
decorationColor: Color(0xFF985400),
decorationThickness: 1),
),
TextSpan(
text: AppLocalizations.of(
context)!
.t_and,
text: AppLocalizations.of(context)!.t_and,
style: TextStyle(
color: Color(
0xFF898C81), // Change to your desired color
@ -877,31 +938,26 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
),
TextSpan(
recognizer: TapGestureRecognizer()
..onTap = () => context.push('/privacy_policy'),
text: AppLocalizations.of(
context)!
..onTap =
() => context.push('/privacy_policy'),
text: AppLocalizations.of(context)!
.privacy_policy,
style: TextStyle(
fontWeight:
FontWeight.bold,
fontWeight: FontWeight.bold,
fontSize: 14,
fontFamily: 'Roboto',
color:
Color(0xFF985400),
color: Color(0xFF985400),
// decoration:
// TextDecoration.underline,
decorationColor:
Color(0xFF648CBA),
decorationThickness:
1),
decorationColor: Color(0xFF648CBA),
decorationThickness: 1),
),
TextSpan(
text: AppLocalizations.of(
context)!
text: AppLocalizations.of(context)!
.conditions,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14,
fontSize: 14,
color: Color(
0xFF898C81), // Change to your desired color
),
@ -918,13 +974,14 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 10.0, right: profileLocale
?.languageCode ==
'ar'
? 15
: 0.0,),
padding: EdgeInsets.only(
left: 10.0,
right: profileLocale?.languageCode == 'ar'
? 15
: 0.0,
),
child: Text(
context.translate('Required', 'مطلوب'),
context.translate('Required', 'مطلوب'),
style: TextStyle(
color: Color(0xFFb22222),
fontSize: 12,
@ -960,7 +1017,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
ElevatedButton(
onPressed: () {
setState(() {
hasValidated = true;
hasValidated = true;
});
if ((_formKey.currentState?.validate() ?? false) &&
(isChecked)) {
@ -969,7 +1026,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
} else {
setState(() {
showError =
!isChecked; // Show error if the checkbox is not checked
!isChecked; // Show error if the checkbox is not checked
});
}
},
@ -982,7 +1039,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center, // Center the content
MainAxisAlignment.center, // Center the content
children: [
Text(
AppLocalizations.of(context)!.save,
@ -1041,10 +1098,10 @@ class ConfirmationDialog extends StatelessWidget {
TextSpan(
text: AppLocalizations.of(context)!.name,
style:
TextStyle(fontWeight: FontWeight.w700), // Bold for "name"
TextStyle(fontWeight: FontWeight.w700), // Bold for "name"
),
TextSpan(
text: context.translate(' or ','أو'),
text: context.translate(' or ', 'أو'),
),
TextSpan(
text: AppLocalizations.of(context)!.dob,
@ -1111,4 +1168,4 @@ class ConfirmationDialog extends StatelessWidget {
],
);
}
}
}

View File

@ -7,12 +7,14 @@ const Color environmentboldColor = Color(0xFF90B0D5);
const TextStyle subtitleStyle = TextStyle(
fontFamily: 'Roboto', // Font family set to Roboto
fontWeight: FontWeight.w400, // Regular weight (w400)
fontSize: 11,
// fontSize: 11,
fontSize: 11 * 1.2, // Increase by 20%
color: Color(0xFF8E8E8E) // Font size 11
);
const TextStyle robotoRegular11 = TextStyle(
fontFamily: 'Roboto', // Font family set to Roboto
fontWeight: FontWeight.w400, // Regular weight (w400)
fontSize: 11,
fontSize: 11 * 1.1,
color: Color(0xFF000000) // Font size 11
);

View File

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:external_repos/external_repos.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@ -27,7 +28,6 @@ import 'package:pocketbase/pocketbase.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:uae_stat/config/api_config.dart';
import '../../components/indicators/locale_provider.dart';
import '../../components/my_toggle.dart';
@ -42,7 +42,8 @@ class LoginRoute extends HookConsumerWidget {
dynamic userData;
String? role;
int? loginCount;
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
// final FirebaseAuth _auth = FirebaseAuth.instance;
static final formKey = GlobalKey<FormState>();
Future<bool> profileStatus(String userId) async {
@ -97,6 +98,89 @@ class LoginRoute extends HookConsumerWidget {
await prefs.setString('login_count', count.toString());
}
// Future<void> getDeviceToken() async {
// String? token = await FirebaseMessaging.instance.getToken();
// print("FCM Token: $token");
// }
Future<void> getDeviceToken(BuildContext context, String userId) async {
try {
// await _firebaseMessaging.requestPermission();
print("FCM Token Entry");
String? token = await FirebaseMessaging.instance.getToken();
print("FCM Token: $token");
if (token != null) {
await updateDeviceToken(userId, token);
// Automatically copy to clipboard
// Clipboard.setData(ClipboardData(text: token));
// Show token in Alert Dialog
// if (context.mounted) {
// showDialog(
// context: context,
// builder: (context) {
// return AlertDialog(
// title: Text("FCM Token"),
// content: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// SelectableText(token), // Allows manual selection
// SizedBox(height: 10),
// Text(
// "Token copied to clipboard ✅",
// style: TextStyle(color: Colors.green),
// ),
// ],
// ),
// actions: [
// TextButton(
// onPressed: () => Navigator.pop(context),
// child: Text("OK"),
// ),
// ],
// );
// },
// );
// }
}
} catch (e) {
print("Error getting FCM Token: $e");
}
}
Future<void> updateDeviceToken(String userId, String token) async {
final url = "${pb.baseUrl}/api/collections/users/records/$userId";
try {
// Authenticate admin (Persist session globally instead)
await pb.admins.authWithPassword(
'pb@venbainfotech.com',
'pb@venbainfotech.com',
);
final response = await http.patch(
Uri.parse(url),
headers: {
'Content-Type': 'application/json', // Add this
'Authorization': pb.authStore.token, // Correct way to send auth token
},
body: jsonEncode({
"device_token": token,
}),
);
if (response.statusCode == 200) {
print("✅ Device token updated successfully!");
} else {
print("❌ Failed to update device token: ${response.body}");
}
} catch (e) {
print("🚨 Error updating device token: $e");
}
}
// Future<void> authenticateAndStoreData() async {
// try {
// // Perform authentication
@ -244,15 +328,13 @@ class LoginRoute extends HookConsumerWidget {
'تم إرسال بريد إلكتروني إلى $email يتضمن المزيد من التفاصيل.',
),
);
},
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
// maximumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
overlayColor: Colors.white
),
overlayColor: Colors.white),
child: Text(
context.translate(
'Forgot Password?',
@ -273,7 +355,7 @@ class LoginRoute extends HookConsumerWidget {
width: double.infinity,
child: ElevatedButton(
onPressed: () async {
hasValidated.value=true;
hasValidated.value = true;
final isValid = formKey.currentState!.validate();
if (!isValid) return;
final session = await context.loaderWithErrorDialog(
@ -367,6 +449,7 @@ class LoginRoute extends HookConsumerWidget {
}
await saveUserId(userId, loginCount);
await getDeviceToken(context, userId);
}
try {
final bool isProfileComplete = await profileStatus(userId);
@ -451,14 +534,14 @@ class LoginRoute extends HookConsumerWidget {
'Login',
'تسجيل الدخول',
),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'Roboto',
),
fontSize: locale?.languageCode == 'ar' ? 12: 18,
fontWeight: FontWeight.w500,
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'Roboto',
),
fontSize: locale?.languageCode == 'ar' ? 12 : 18,
fontWeight: FontWeight.w500,
),
),
6.horizontalSpace,
const Icon(
@ -478,16 +561,15 @@ class LoginRoute extends HookConsumerWidget {
'Email',
'بريد إلكتروني',
),
validator: (value) {
final emailRegex =
r'^[a-zA-Z0-9àèìòùÀÈÌÒÙéàç~!#$%^&*()_+=-{}|;,.?<>]+@[a-zA-Z0-9àèìòùÀÈÌÒÙéàç~!#$%^&*()_+=-{}|;,.?<>]+\.[a-zA-Z]{2,}$';
if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب');
}
else if (!RegExp(emailRegex).hasMatch(value)) {
} else if (!RegExp(emailRegex).hasMatch(value)) {
return AppLocalizations.of(context)!.invalid_email;
} return null;
}
return null;
},
imgPath: MiscIconAssetPath.person,
controller: emailCtl,
@ -662,48 +744,47 @@ class LoginRoute extends HookConsumerWidget {
final listViewHorizontalPadding =
screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2;
final scaffoldBody = SingleChildScrollView(
child: Column(
children:[
Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
3.verticalSpace,
Align(
alignment: AlignmentDirectional.topEnd,
child: MyToggle(
isOn: locale?.languageCode == 'en',
knobTextWhenOn: 'ع',
knobTextWhenOff: 'EN',
pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300,
onTap: () {
final formState = formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (hasValidated.value && formState?.validate() == false) {
formState?.validate();
}
});
},
),
),
34.verticalSpace,
helloAndPleaseLoginTexts,
40.verticalSpace,
form,
15.verticalSpace,
dontHaveAnAccountRegisterBtn,
// continueAsGuestBtn,
// Spacer(),
15.verticalSpace,
fcscBanner,
],
child: Column(children: [
Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
3.verticalSpace,
Align(
alignment: AlignmentDirectional.topEnd,
child: MyToggle(
isOn: locale?.languageCode == 'en',
knobTextWhenOn: 'ع',
knobTextWhenOff: 'EN',
pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300,
onTap: () {
final formState = formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (hasValidated.value &&
formState?.validate() == false) {
formState?.validate();
}
});
},
),
),
)
]
),
34.verticalSpace,
helloAndPleaseLoginTexts,
40.verticalSpace,
form,
15.verticalSpace,
dontHaveAnAccountRegisterBtn,
// continueAsGuestBtn,
// Spacer(),
15.verticalSpace,
fcscBanner,
],
),
)
]),
);
// final bgScaffold = Scaffold(
// backgroundColor: Colors.white,
@ -783,4 +864,4 @@ class LoginRoute extends HookConsumerWidget {
// ),
// );
// }
}
}

View File

@ -1456,7 +1456,8 @@ class InfoCard extends StatelessWidget {
child: Text(
title,
style: const TextStyle(
fontSize: 11,
// fontSize: 11,
fontSize: 11 * 1.1,
fontWeight: FontWeight.w400,
// color: Colors.black,
fontFamily: 'Roboto',
@ -1478,7 +1479,8 @@ class InfoCard extends StatelessWidget {
subtitle,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 11,
// fontSize: 11,
fontSize: 11 * 1.1,
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
color: Color(0xFF8E8E8E),

View File

@ -204,7 +204,7 @@ class _EditProfileState extends State<EditProfile> {
if (avatarFilename.isNotEmpty && recordId.isNotEmpty) {
_avatarUrl =
'$apiUrl/$collectionId/$recordId/$avatarFilename';
'$apiUrl/api/files/$collectionId/$recordId/$avatarFilename';
} else {
_avatarUrl = ''; // Reset to default or empty
}
@ -308,7 +308,8 @@ class _EditProfileState extends State<EditProfile> {
// Check if the selected date is in the future
if (selectedDate.isAfter(today)) {
return context.translate('Date of birth cannot be in the future','لا يمكن أن يكون تاريخ الميلاد في المستقبل');
return context.translate('Date of birth cannot be in the future',
'لا يمكن أن يكون تاريخ الميلاد في المستقبل');
}
return null;
}
@ -691,7 +692,8 @@ class _EditProfileState extends State<EditProfile> {
enabled: false,
validator: (value) {
if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب');
return context.translate(
'Required', 'مطلوب');
}
//RegExp(r"^[a-zA-Z\s]+$");
@ -699,7 +701,8 @@ class _EditProfileState extends State<EditProfile> {
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$",
);
if (!nameRegex.hasMatch(value)) {
return AppLocalizations.of(context)!.invalid_characters;
return AppLocalizations.of(context)!
.invalid_characters;
}
return null;
},
@ -787,18 +790,19 @@ class _EditProfileState extends State<EditProfile> {
),
value: _selectedCountry,
decoration: InputDecoration(
enabledBorder:OutlineInputBorder(
enabledBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
BorderRadius.circular(10),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
border: OutlineInputBorder(
borderSide:BorderSide(color: Color(0xFF7296BE),
),
borderSide: BorderSide(
color: Color(0xFF7296BE),
),
borderRadius:
BorderRadius.circular(8),
),
@ -845,8 +849,9 @@ class _EditProfileState extends State<EditProfile> {
color: showError
? Color(0xFFb22222)
: MyTheme.topicColor(
IndicatorTopic.economy)
.shade400,
IndicatorTopic
.economy)
.shade400,
width: 1.5,
),
),
@ -880,8 +885,11 @@ class _EditProfileState extends State<EditProfile> {
TextDecoration
.underline,
),
recognizer:TapGestureRecognizer()
..onTap = () => context.push('/terms&conditions'),
recognizer:
TapGestureRecognizer()
..onTap = () =>
context.push(
'/terms&conditions'),
),
TextSpan(
text: AppLocalizations
@ -907,9 +915,11 @@ class _EditProfileState extends State<EditProfile> {
TextDecoration
.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => context.push('/privacy_policy'),
recognizer:
TapGestureRecognizer()
..onTap = () =>
context.push(
'/privacy_policy'),
),
TextSpan(
text: AppLocalizations
@ -1151,4 +1161,4 @@ class ConfirmationDialog extends StatelessWidget {
],
);
}
}
}

View File

@ -342,14 +342,18 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
padding: EdgeInsets.only(left: 12.0),
child: TextField(
decoration: InputDecoration(
hintText: "Search",
hintStyle: TextStyle(color: Color(0xFF898C81)),
prefixIconConstraints: BoxConstraints(maxWidth: 42, maxHeight: 42),
hintText: AppLocalizations.of(context)!.search,
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
// hintStyle: TextStyle(color: Color(0xFFAA8E83)),
prefixIconConstraints:
BoxConstraints(maxWidth: 42, maxHeight: 42),
prefixIcon: Container(
padding: EdgeInsets.only(right: 5),
child: SvgPicture.asset(
MiscIconAssetPath.Search,
semanticsLabel: 'Search',
colorFilter: ColorFilter.mode(
Color(0xFFAA8E83), BlendMode.srcIn),
),
),
@ -359,7 +363,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
// ),
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
vertical: 8.0, horizontal: 18.0),
vertical: 0.5, horizontal: 18.0),
),
onChanged: filterUsers,
),

View File

@ -1,22 +1,29 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
import '../../custom_drawer_routes.dart';
import 'package:http/http.dart' as http;
class NotificationPage extends StatefulWidget {
class NotificationPage extends ConsumerStatefulWidget {
@override
_NotificationPageState createState() => _NotificationPageState();
}
class _NotificationPageState extends State<NotificationPage> {
class _NotificationPageState extends ConsumerState<NotificationPage> {
// Example notification data
final _pb = PocketBase(apiUrl);
List<Map<String, dynamic>> notifications = [];
// Current selected tab index
int selectedTabIndex = 0;
late final Locale locale;
// Tab categories
final List<String> tabs = [
@ -28,6 +35,13 @@ class _NotificationPageState extends State<NotificationPage> {
"Favourites"
];
@override
void initState() {
super.initState();
locale = ref.read(localeProvider) ?? const Locale('en');
fetchNotifications(locale?.languageCode ?? 'en');
}
String formatDate(String dateString) {
try {
DateTime dateTime =
@ -39,36 +53,61 @@ class _NotificationPageState extends State<NotificationPage> {
}
}
Future<void> fetchNotifications() async {
Future<void> fetchNotifications(locale) async {
final baseUrl = apiUrl + '/api/getNotification';
try {
await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final response = await http.get(Uri.parse('$baseUrl?language=$locale'));
final result = await _pb.collection('notification').getFullList();
if (response.statusCode == 200) {
final Map<String, dynamic> jsonResponse =
jsonDecode(response.body); // Decode JSON
setState(() {
notifications = result.map((record) => record.toJson()).toList();
});
if (jsonResponse['message'] == 'Success') {
setState(() {
notifications = List<Map<String, dynamic>>.from(
jsonResponse['data']); // Assign decoded data
});
} else {
throw Exception('Failed to load data');
}
} else {
throw Exception(
'Failed to load data with status code ${response.statusCode}');
}
} catch (e) {
print('Error fetching notifications: $e');
print('Error fetching data: $e');
}
}
@override
void initState() {
super.initState();
fetchNotifications();
}
// Future<void> fetchNotifications() async {/api/getNotification?language=ar
// try {
// await _pb.admins
// .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
//
// final result = await _pb.collection('notification').getFullList();
//
// setState(() {
// notifications = result.map((record) => record.toJson()).toList();
// });
// } catch (e) {
// print('Error fetching notifications: $e');
// }
// }
@override
Widget build(BuildContext context) {
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
fetchNotifications(localeCode);
});
// Filter notifications based on the selected tab
List<Map<String, dynamic>> filteredNotifications = selectedTabIndex == 0
? notifications
: notifications
.where((notification) =>
notification["category"] == tabs[selectedTabIndex])
.toList();
: notifications.where((notification) {
print(
"Comparing: '${notification["category"]}' with '${tabs[selectedTabIndex]}'");
return notification["category"] == tabs[selectedTabIndex];
}).toList();
return PopScope(
canPop: false,
@ -77,7 +116,12 @@ class _NotificationPageState extends State<NotificationPage> {
context.go('/myhomepage');
},
child: BaseScaffold(
title: Text('Notification'),
title: Text(
context.translate(
'Notification',
'إشعار',
),
),
body: Column(
children: [
TabBarHeader(
@ -90,53 +134,41 @@ class _NotificationPageState extends State<NotificationPage> {
},
),
Expanded(
child: selectedTabIndex == 1
child: filteredNotifications.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/backgrounds/Notification/Update_notific.png',
height: 200,
),
Icon(Icons.info_outline,
size: 100, color: Colors.grey[400]),
SizedBox(height: 16),
Text(
filteredNotifications.isNotEmpty
? filteredNotifications[0]['title']
: 'No updates available.',
'No notifications available.',
style: TextStyle(fontSize: 16, color: Colors.grey),
textAlign: TextAlign.center,
),
],
),
)
: filteredNotifications.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.info_outline,
size: 100, color: Colors.grey[400]),
SizedBox(height: 16),
Text(
'No notifications available.',
style:
TextStyle(fontSize: 16, color: Colors.grey),
),
],
: ListView.builder(
itemCount: filteredNotifications.length,
itemBuilder: (context, index) {
final notification = filteredNotifications[index];
return Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Color(0xFFDEDEDE),
width: 1), // Bottom border only
),
),
)
: ListView.builder(
itemCount: filteredNotifications.length,
itemBuilder: (context, index) {
final notification = filteredNotifications[index];
return NotificationTile(
child: NotificationTile(
title: notification['title'] ?? 'No Title',
date: formatDate(notification['created'] ?? ''),
category: notification['category'] ?? 'Unknown',
);
},
),
message: notification['message'] ?? ''),
);
},
),
),
],
),
@ -205,22 +237,43 @@ class TabBarHeader extends StatelessWidget {
class NotificationTile extends StatelessWidget {
final String title;
final String message;
final String date;
final String category;
const NotificationTile({
required this.title,
required this.message,
required this.date,
required this.category,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(Icons.circle,
size: 12, color: category == "Social" ? Colors.red : Colors.grey),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(date),
return GestureDetector(
onTap: () {
context.go('/notification_details', extra: {
'title': title,
'message': message,
'date': date,
'category': category,
});
},
child: ListTile(
// leading: Icon(Icons.circle,
// size: 12, color: category == "Social" ? Colors.red : Colors.grey),
leading: Icon(Icons.circle, size: 12, color: Colors.red),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(
date,
style: const TextStyle(
color: Color(0xFF8E8E8E),
fontSize: 12,
fontWeight: FontWeight.w400),
),
trailing: const Icon(Icons.arrow_forward_ios,
size: 16, color: Color(0xFF898C81)),
),
);
}
}

View File

@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
class NotificationDetails extends ConsumerWidget {
final String title;
final String message;
final String date;
final String category;
const NotificationDetails({
super.key,
required this.title,
required this.message,
required this.date,
required this.category,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
context.go('/notification');
},
child: BaseScaffold(
title: Text(
context.translate(
'Notification',
'إشعار',
),
),
showBackButton: true,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Color(0xFF414042)),
),
const SizedBox(height: 20),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
category == 'App updates'
? 'assets/backgrounds/Notification/App-Update.png'
: 'assets/backgrounds/Notification/Update_notific.png',
height: 200,
),
],
),
),
const SizedBox(height: 20),
Text(
message.isNotEmpty
? message
: "No additional details available.",
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF414042)),
),
const SizedBox(height: 10),
Text(
"Date: $date",
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Color(0xFF8E8E8E)),
),
],
),
),
));
}
}

View File

@ -8,7 +8,8 @@ import Foundation
import connectivity_plus
import file_selector_macos
import firebase_core
import flutter_secure_storage_macos
import firebase_messaging
import flutter_secure_storage_darwin
import package_info_plus
import path_provider_foundation
import share_plus
@ -21,12 +22,13 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin"))
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
}

View File

@ -5,31 +5,34 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57
url: "https://pub.dev"
source: hosted
version: "76.0.0"
_macros:
version: "80.0.0"
_flutterfire_internals:
dependency: transitive
description: dart
source: sdk
version: "0.3.3"
description:
name: _flutterfire_internals
sha256: "7fd72d77a7487c26faab1d274af23fb008763ddc10800261abbfb2c067f183d5"
url: "https://pub.dev"
source: hosted
version: "1.3.53"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e"
url: "https://pub.dev"
source: hosted
version: "6.11.0"
version: "7.3.0"
analyzer_plugin:
dependency: transitive
description:
name: analyzer_plugin
sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161"
sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916"
url: "https://pub.dev"
source: hosted
version: "0.11.3"
version: "0.12.0"
ansicolor:
dependency: transitive
description:
@ -58,18 +61,18 @@ packages:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.11.0"
version: "2.12.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
boxy:
dependency: "direct main"
description:
@ -82,50 +85,50 @@ packages:
dependency: transitive
description:
name: build
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
build_config:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.0.4"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.4"
build_runner:
dependency: "direct dev"
description:
name: build_runner
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
url: "https://pub.dev"
source: hosted
version: "2.4.13"
version: "2.4.15"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
url: "https://pub.dev"
source: hosted
version: "7.3.2"
version: "8.0.0"
built_collection:
dependency: transitive
description:
@ -138,18 +141,18 @@ packages:
dependency: transitive
description:
name: built_value
sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2"
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.3"
version: "8.9.4"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@ -178,10 +181,10 @@ packages:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
code_builder:
dependency: transitive
description:
@ -194,18 +197,18 @@ packages:
dependency: transitive
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.19.1"
connectivity_plus:
dependency: "direct main"
description:
name: connectivity_plus
sha256: "8a68739d3ee113e51ad35583fdf9ab82c55d09d693d3c39da1aebab87c938412"
sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27"
url: "https://pub.dev"
source: hosted
version: "6.1.2"
version: "6.1.3"
connectivity_plus_platform_interface:
dependency: transitive
description:
@ -266,42 +269,42 @@ packages:
dependency: "direct dev"
description:
name: custom_lint
sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9"
sha256: "021897cce2b6c783b2521543e362e7fe1a2eaab17bf80514d8de37f99942ed9e"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.7.3"
custom_lint_builder:
dependency: transitive
description:
name: custom_lint_builder
sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759"
sha256: e4235b9d8cef59afe621eba086d245205c8a0a6c70cd470be7cb17494d6df32d
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.7.3"
custom_lint_core:
dependency: transitive
description:
name: custom_lint_core
sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5"
sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.7.1"
custom_lint_visitor:
dependency: transitive
description:
name: custom_lint_visitor
sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9
sha256: "36282d85714af494ee2d7da8c8913630aa6694da99f104fb2ed4afcf8fc857d8"
url: "https://pub.dev"
source: hosted
version: "1.0.0+6.11.0"
version: "1.0.0+7.3.0"
dart_style:
dependency: transitive
description:
name: dart_style
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac"
url: "https://pub.dev"
source: hosted
version: "2.3.7"
version: "3.0.1"
dartz:
dependency: transitive
description:
@ -330,10 +333,10 @@ packages:
dependency: transitive
description:
name: dio_web_adapter
sha256: e485c7a39ff2b384fa1d7e09b4e25f755804de8384358049124830b04fc4f93a
sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
equatable:
dependency: transitive
description:
@ -369,26 +372,26 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
fast_immutable_collections:
dependency: "direct main"
description:
name: fast_immutable_collections
sha256: c3c73f4f989d3302066e4ec94e6ec73b5dc872592d02194f49f1352d64126b8c
sha256: "95a69b9380483dff49ae2c12c9eb92e2b4e1aeff481a33c2a20883471771598a"
url: "https://pub.dev"
source: hosted
version: "10.2.4"
version: "11.0.3"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
version: "2.1.4"
file:
dependency: transitive
description:
@ -425,18 +428,18 @@ packages:
dependency: transitive
description:
name: file_selector_windows
sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4"
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.dev"
source: hosted
version: "0.9.3+3"
version: "0.9.3+4"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "26de145bb9688a90962faec6f838247377b0b0d32cc0abecd9a4e43525fc856c"
sha256: f4d8f49574a4e396f34567f3eec4d38ab9c3910818dec22ca42b2a467c685d8b
url: "https://pub.dev"
source: hosted
version: "2.32.0"
version: "3.12.1"
firebase_core_platform_interface:
dependency: transitive
description:
@ -449,10 +452,34 @@ packages:
dependency: transitive
description:
name: firebase_core_web
sha256: e47f5c2776de018fa19bc9f6f723df136bc75cdb164d64b65305babd715c8e41
sha256: faa5a76f6380a9b90b53bc3bdcb85bc7926a382e0709b9b5edac9f7746651493
url: "https://pub.dev"
source: hosted
version: "2.21.0"
version: "2.21.1"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "5fc345c6341f9dc69fd0ffcbf508c784fd6d1b9e9f249587f30434dd8b6aa281"
url: "https://pub.dev"
source: hosted
version: "15.2.4"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: a935924cf40925985c8049df4968b1dde5c704f570f3ce380b31d3de6990dd94
url: "https://pub.dev"
source: hosted
version: "4.6.4"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: fafebf6a1921931334f3f10edb5037a5712288efdd022881e2d093e5654a2fd4
url: "https://pub.dev"
source: hosted
version: "3.10.4"
fixnum:
dependency: transitive
description:
@ -486,10 +513,10 @@ packages:
dependency: "direct main"
description:
name: flutter_hooks
sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70
sha256: b772e710d16d7a20c0740c4f855095026b31c7eb5ba3ab67d2bd52021cd9461d
url: "https://pub.dev"
source: hosted
version: "0.20.5"
version: "0.21.2"
flutter_launcher_icons:
dependency: "direct dev"
description:
@ -523,10 +550,10 @@ packages:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3"
url: "https://pub.dev"
source: hosted
version: "2.0.24"
version: "2.0.27"
flutter_rating_bar:
dependency: "direct main"
description:
@ -547,50 +574,50 @@ packages:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
sha256: f7eceb0bc6f4fd0441e29d43cab9ac2a1c5ffd7ea7b64075136b718c46954874
url: "https://pub.dev"
source: hosted
version: "9.2.4"
version: "10.0.0-beta.4"
flutter_secure_storage_darwin:
dependency: transitive
description:
name: flutter_secure_storage_darwin
sha256: f226f2a572bed96bc6542198ebaec227150786e34311d455a7e2d3d06d951845
url: "https://pub.dev"
source: hosted
version: "0.1.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705
sha256: "9b4b73127e857cd3117d43a70fa3dddadb6e0b253be62e6a6ab85caa0742182c"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "2.0.1"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
sha256: "8ceea1223bee3c6ac1a22dabd8feefc550e4729b3675de4b5900f55afcb435d6"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "2.0.1"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
sha256: "4c3f233e739545c6cb09286eeec1cc4744138372b985113acc904f7263bef517"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "2.0.0"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
sha256: ff32af20f70a8d0e59b2938fc92de35b54a74671041c814275afd80e27df9f21
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "4.0.0"
flutter_staggered_grid_view:
dependency: "direct main"
description:
@ -621,18 +648,18 @@ packages:
dependency: "direct main"
description:
name: fluttertoast
sha256: "8971efe7e59585e9149052e33718d84bca51e806f063d1467622b3dcb2878b6c"
sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1"
url: "https://pub.dev"
source: hosted
version: "8.2.11"
version: "8.2.12"
freezed:
dependency: "direct dev"
description:
name: freezed
sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e"
sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c"
url: "https://pub.dev"
source: hosted
version: "2.5.7"
version: "2.5.8"
freezed_annotation:
dependency: "direct main"
description:
@ -669,10 +696,10 @@ packages:
dependency: "direct main"
description:
name: go_router
sha256: daf3ff5570f55396b2d2c9bf8136d7db3a8acf208ac0cef92a3ae2beb9a81550
sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3
url: "https://pub.dev"
source: hosted
version: "14.7.1"
version: "14.8.1"
graphs:
dependency: transitive
description:
@ -725,10 +752,10 @@ packages:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.1.2"
iconify_design:
dependency: "direct main"
description:
@ -757,10 +784,10 @@ packages:
dependency: transitive
description:
name: image_picker_android
sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c
sha256: "82652a75e3dd667a91187769a6a2cc81bd8c111bbead698d8e938d2b63e5e89a"
url: "https://pub.dev"
source: hosted
version: "0.8.12+20"
version: "0.8.12+21"
image_picker_for_web:
dependency: transitive
description:
@ -821,10 +848,10 @@ packages:
dependency: "direct dev"
description:
name: injectable_generator
sha256: af403d76c7b18b4217335e0075e950cd0579fd7f8d7bd47ee7c85ada31680ba1
sha256: b04673a4c88b3a848c0c77bf58b8309f9b9e064d9fe1df5450c8ee1675eaea1a
url: "https://pub.dev"
source: hosted
version: "2.6.2"
version: "2.7.0"
intl:
dependency: "direct main"
description:
@ -845,10 +872,10 @@ packages:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.6.7"
version: "0.7.2"
json_annotation:
dependency: "direct main"
description:
@ -861,10 +888,10 @@ packages:
dependency: "direct dev"
description:
name: json_serializable
sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c
sha256: "81f04dee10969f89f604e1249382d46b97a1ccad53872875369622b5bfc9e58a"
url: "https://pub.dev"
source: hosted
version: "6.9.0"
version: "6.9.4"
jwt_decoder:
dependency: "direct main"
description:
@ -877,18 +904,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
version: "10.0.7"
version: "10.0.8"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.8"
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
@ -901,10 +928,10 @@ packages:
dependency: transitive
description:
name: lints
sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
url: "https://pub.dev"
source: hosted
version: "5.0.0"
version: "5.1.1"
logging:
dependency: transitive
description:
@ -913,14 +940,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
url: "https://pub.dev"
source: hosted
version: "0.1.3-main.0"
mailer:
dependency: "direct main"
description:
@ -941,10 +960,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
version: "0.12.17"
material_charts:
dependency: "direct main"
description:
@ -965,10 +984,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.16.0"
mime:
dependency: transitive
description:
@ -1005,26 +1024,26 @@ packages:
dependency: "direct main"
description:
name: package_info_plus
sha256: c447a3c3e7be4addf129b8f9ab6a4bd5d166b78918223e223b61fddf4d07e254
sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191"
url: "https://pub.dev"
source: hosted
version: "8.2.0"
version: "8.3.0"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: "205ec83335c2ab9107bbba3f8997f9356d72ca3c715d2f038fc773d0366b4c76"
sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.2.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.9.1"
path_parsing:
dependency: transitive
description:
@ -1085,10 +1104,10 @@ packages:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev"
source: hosted
version: "6.0.2"
version: "6.1.0"
platform:
dependency: transitive
description:
@ -1141,10 +1160,10 @@ packages:
dependency: transitive
description:
name: pubspec_parse
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.5.0"
recase:
dependency: transitive
description:
@ -1173,10 +1192,10 @@ packages:
dependency: transitive
description:
name: riverpod_analyzer_utils
sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8
sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3"
url: "https://pub.dev"
source: hosted
version: "0.5.8"
version: "0.5.9"
riverpod_annotation:
dependency: "direct main"
description:
@ -1189,18 +1208,18 @@ packages:
dependency: "direct dev"
description:
name: riverpod_generator
sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188"
sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f"
url: "https://pub.dev"
source: hosted
version: "2.6.3"
version: "2.6.4"
riverpod_lint:
dependency: "direct dev"
description:
name: riverpod_lint
sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99"
sha256: b05408412b0f75dec954e032c855bc28349eeed2d2187f94519e1ddfdf8b3693
url: "https://pub.dev"
source: hosted
version: "2.6.3"
version: "2.6.4"
rxdart:
dependency: transitive
description:
@ -1244,18 +1263,18 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: "688ee90fbfb6989c980254a56cb26ebe9bb30a3a2dff439a78894211f73de67a"
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
url: "https://pub.dev"
source: hosted
version: "2.5.1"
version: "2.5.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "650584dcc0a39856f369782874e562efd002a9c94aec032412c9eb81419cce1f"
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
url: "https://pub.dev"
source: hosted
version: "2.4.4"
version: "2.4.6"
shared_preferences_foundation:
dependency: transitive
description:
@ -1284,10 +1303,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
@ -1300,18 +1319,18 @@ packages:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
sky_engine:
dependency: transitive
description: flutter
@ -1328,10 +1347,10 @@ packages:
dependency: transitive
description:
name: source_gen
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
version: "2.0.0"
source_helper:
dependency: transitive
description:
@ -1344,10 +1363,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.10.1"
sprintf:
dependency: transitive
description:
@ -1360,10 +1379,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.12.1"
state_notifier:
dependency: transitive
description:
@ -1376,10 +1395,10 @@ packages:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
stream_transform:
dependency: transitive
description:
@ -1392,42 +1411,42 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.1"
syncfusion_flutter_charts:
dependency: "direct main"
description:
name: syncfusion_flutter_charts
sha256: "672c17a7f4cb3020c06bb6a28d2d033623007b8e2a19704ad34b412e9bdd2dab"
sha256: c53e8616368c1a88397b7b180d0ded7d9e960564cdba01509cc5fa2d503ed727
url: "https://pub.dev"
source: hosted
version: "28.2.4+1"
version: "28.2.9"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: "3c1876b0a245de23de3b17a19e3106fed57d88f4fd2c8dc9bc1976705b1c31d5"
sha256: "5a1a76eef118e511443b299925d4a802eb8259388d6a580e0ad6413d1a70f987"
url: "https://pub.dev"
source: hosted
version: "28.2.4"
version: "28.2.9"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.3"
version: "0.7.4"
the_validator:
dependency: "direct main"
description:
@ -1448,10 +1467,10 @@ packages:
dependency: "direct main"
description:
name: tutorial_coach_mark
sha256: df450c88d4c812bc221afd3ff948da3dc0f44c0b4fa5dbc046d6d86f2cfc9e71
sha256: "2c77c0b00bbe7d5b8a6d31cb9e03d44bf77dfe7ba6514cc2b546886d024a9945"
url: "https://pub.dev"
source: hosted
version: "1.2.12"
version: "1.2.13"
typed_data:
dependency: transitive
description:
@ -1520,10 +1539,10 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.0"
url_launcher_windows:
dependency: transitive
description:
@ -1576,26 +1595,26 @@ packages:
dependency: "direct main"
description:
name: video_player
sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17"
sha256: "48941c8b05732f9582116b1c01850b74dbee1d8520cd7e34ad4609d6df666845"
url: "https://pub.dev"
source: hosted
version: "2.9.2"
version: "2.9.3"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898"
sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b"
url: "https://pub.dev"
source: hosted
version: "2.7.16"
version: "2.7.17"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: "8a4e73a3faf2b13512978a43cf1cdda66feeeb900a0527f1fbfd7b19cf3458d3"
sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc"
url: "https://pub.dev"
source: hosted
version: "2.6.7"
version: "2.7.0"
video_player_platform_interface:
dependency: transitive
description:
@ -1616,10 +1635,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
version: "14.3.1"
watcher:
dependency: transitive
description:
@ -1632,10 +1651,10 @@ packages:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -1664,10 +1683,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
sha256: d1ee28f44894cbabb1d94cc42f9980297f689ff844d067ec50ff88d86e27d63f
sha256: "512c26ccc5b8a571fd5d13ec994b7509f142ff6faf85835e243dde3538fdc713"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
version: "4.3.2"
webview_flutter_platform_interface:
dependency: transitive
description:
@ -1680,18 +1699,18 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: "4adc14ea9a770cc9e2c8f1ac734536bd40e82615bd0fa6b94be10982de656cc7"
sha256: c49a98510080378b1525132f407a92c3dcd3b7145bef04fb8137724aadcf1cf0
url: "https://pub.dev"
source: hosted
version: "3.17.0"
version: "3.18.4"
win32:
dependency: transitive
description:
name: win32
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
sha256: b89e6e24d1454e149ab20fbb225af58660f0c0bf4475544650700d8e2da54aef
url: "https://pub.dev"
source: hosted
version: "5.10.1"
version: "5.11.0"
xdg_directories:
dependency: transitive
description:
@ -1717,5 +1736,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.5.2 <4.0.0"
flutter: ">=3.24.0"
dart: ">=3.7.0 <4.0.0"
flutter: ">=3.27.0"

View File

@ -1,7 +1,7 @@
name: uae_stat
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
publish_to: "none"
version: 1.0.27+28
version: 1.0.30+31
environment:
sdk: ">=3.2.3 <4.0.0"
@ -9,9 +9,9 @@ environment:
dependencies:
flutter:
sdk: flutter
fast_immutable_collections: ^10.1.0
fast_immutable_collections: ^11.0.3
# flutter_cache_manager: ^3.3.1
flutter_hooks: ^0.20.4
flutter_hooks: ^0.21.2
flutter_riverpod: ^2.4.0
get_it: ^8.0.1
go_router: ^14.1.3
@ -33,10 +33,10 @@ dependencies:
csv: ^6.0.0
excel: ^4.0.2
intl: ^0.19.0
firebase_core: ^2.27.0
firebase_core: ^3.12.1
the_validator: ^2.0.0
pocketbase: ^0.18.1
flutter_secure_storage: ^9.0.0
flutter_secure_storage: ^10.0.0-beta.4
jwt_decoder: ^2.0.1
fluttertoast: ^8.2.11
webview_flutter: ^4.5.0
@ -66,6 +66,7 @@ dependencies:
package_info_plus: ^8.2.0
flutter_svg: ^2.0.17
boxy: ^2.2.1
firebase_messaging: ^15.2.4
dependency_overrides:
fading_edge_scrollview: ^4.1.1
@ -139,6 +140,7 @@ flutter:
- assets/icons/misc/group.png
- assets/icons/misc/search.png
- assets/icons/bookmark/
- assets/FCSC-GIF.gif
fonts:
- family: Segoe