bug fix and notification

This commit is contained in:
venbaittech 2025-03-11 18:00:20 +05:30
parent f9a16ec99a
commit cbe243ea1d
15 changed files with 1433 additions and 1172 deletions

View File

@ -20,12 +20,12 @@ if (project.hasProperty('google-services.json')) {
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "33"
flutterVersionCode = "34"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0.32"
flutterVersionName = "1.0.33"
}
def keystorePropertiesFile = rootProject.file("key.properties")

View File

@ -0,0 +1,15 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
final connectivityProvider = StreamProvider<bool>((ref) async* {
await for (var result in Connectivity().onConnectivityChanged) {
bool isConnected = result != ConnectivityResult.none;
if (isConnected) {
isConnected = await InternetConnectionChecker.instance.hasConnection;
}
yield isConnected;
}
});

View File

@ -377,7 +377,7 @@ final GoRouter router = GoRouter(
// ),
GoRoute(
path: '/internetcheck',
builder: (context, state) => InternetCheck(),
builder: (context, state) => InternetCheckScreen(),
),
GoRoute(
path: '/login',
@ -653,7 +653,8 @@ final GoRouter router = GoRouter(
],
redirect: (context, state) async {
if (state.uri.path == '/SessionCheckScreen' ||
state.uri.path == '/login') {
state.uri.path == '/login' ||
state.uri.path == '/register') {
return null;
}

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart';
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
@ -170,10 +171,20 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
}
Widget build(BuildContext context) {
final isConnected = ref.watch(connectivityProvider);
// If no internet, redirect to InternetCheckScreen
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.go('/internetcheck');
}
});
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
fetchData(localeCode);
});
double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width;
@ -362,6 +373,16 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
colorPattern,
double mywidth,
String mainTopic) {
print('UAE Numbers $value , $title');
// Check if title is "Population Growth"
bool isPopulationGrowth = title == "Population Growth";
// Convert value to double for checking positive or negative (only for Population Growth)
double parsedValue = isPopulationGrowth
? double.tryParse(value.replaceAll('%', '')) ?? 0.0
: 0.0;
bool isPositive = parsedValue >= 0;
return GestureDetector(
onTap: () {
// print('checking data');
@ -403,13 +424,28 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
SizedBox(height: 0.1),
Text(subtitle, textAlign: TextAlign.center, style: subtitleStyle),
SizedBox(height: 0.3),
Text(
value,
style: TextStyle(
fontSize: 20,
color: boldColor,
fontWeight: FontWeight.bold,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
value,
style: TextStyle(
fontSize: 20,
color: isPopulationGrowth
? (isPositive ? Colors.green : Colors.red)
: boldColor,
fontWeight: FontWeight.bold,
),
),
if (isPopulationGrowth) ...[
const SizedBox(width: 5),
Icon(
isPositive ? Icons.arrow_upward : Icons.arrow_downward,
color: isPositive ? Colors.green : Colors.red,
size: 20,
),
],
],
),
],
),

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ import 'package:screenshot/screenshot.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/config/toast_util.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/uae_numbers_asset_path.dart';
@ -2098,6 +2099,15 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
final locale = ref.watch(localeProvider);
final localeNotifier = ref.read(localeProvider.notifier);
final isConnected = ref.watch(connectivityProvider);
// If no internet, redirect to InternetCheckScreen
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.go('/internetcheck');
}
});
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
@ -2330,7 +2340,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
Row(
children: [
GestureDetector(
onTap: () => shareCurrentPage(context, _isSharing),
onTap: () =>
shareCurrentPage(context, _isSharing),
child: Row(
children: [
Text(
@ -2343,19 +2354,20 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
SizedBox(width: 5),
_isSharing
? SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
) // Show loading spinner
width: 24,
height: 24,
child:
CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2,
),
) // Show loading spinner
: SvgPicture.asset(
UaeNumbersAssetPath.share,
semanticsLabel: 'share',
width: 24,
height: 24,
),
UaeNumbersAssetPath.share,
semanticsLabel: 'share',
width: 24,
height: 24,
),
],
),
),
@ -2664,7 +2676,7 @@ Future<void> shareCurrentPage(BuildContext context, bool _isSharing) async {
height: 200,
);
final Uint8List? capturedImage =
await screenshotController.captureFromWidget(
await screenshotController.captureFromWidget(
Material(child: svgWidget),
);

View File

@ -2684,6 +2684,8 @@ class ChartWidget extends StatelessWidget {
print('spots - $spots');
// lineChartLabel = spots;
// List<FlSpot> spots = filteredData
// .where((entry) => entry['ObsKey'][groupByKey] == group)
// .map<FlSpot>((entry) {

View File

@ -1,54 +1,75 @@
import 'package:flutter/material.dart';
import 'package:uae_stat/presentation/components/constant/constant.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
class InternetCheck extends StatelessWidget {
const InternetCheck({super.key});
class InternetCheckScreen extends ConsumerWidget {
const InternetCheckScreen({super.key});
@override
Widget build(BuildContext context) {
double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width;
Widget build(BuildContext context, WidgetRef ref) {
// Listen to changes in connectivity and navigate back to Home if online
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == true) {
Navigator.pop(context);
// context.go('/myhomepage');
}
});
double myHeight = MediaQuery.of(context).size.height;
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(image: AssetImage('assets/logos/no-internet.png')),
SizedBox(height: myheight/40,),
Text("No Internet Connection",style: TextStyle(fontSize: 25,fontWeight: FontWeight.bold)),
Text("Please check with your Wi-Fi or Mobile",style: TextStyle(fontSize: 15,fontWeight: FontWeight.w500)),
Text("Data connection and try again",style: TextStyle(fontSize: 15,fontWeight: FontWeight.w500)),
SizedBox(height: myheight/40,),
ElevatedButton(
onPressed: (){
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(
0xFFA7887A), // Brownish color for Register
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Retry",
style: TextStyle(
fontSize: 16, color: Colors.white),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/logos/no-internet.png', width: 150),
SizedBox(height: myHeight / 40),
Text("No Internet Connection",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold)),
Text("Please check your Wi-Fi or Mobile Data",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500)),
Text("connection and try again",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500)),
SizedBox(height: myHeight / 40),
ElevatedButton(
onPressed: () async {
bool hasInternet =
await InternetConnectionChecker.instance.hasConnection;
if (hasInternet) {
Navigator.pop(
context); // Redirect to home if internet is available
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("No internet connection. Please try again."),
backgroundColor: Colors.red,
),
SizedBox(width: 8),
Icon(Icons.arrow_forward_ios_outlined,size: 12,
color: Colors.white),
],
);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFA7887A),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
),
],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("Retry",
style: TextStyle(fontSize: 16, color: Colors.white)),
SizedBox(width: 8),
Icon(Icons.refresh, size: 16, color: Colors.white),
],
),
),
],
),
),
),

View File

@ -13,6 +13,7 @@ import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/config/my_theme.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/data/p_auth_repo.dart';
@ -467,6 +468,14 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
@override
Widget build(BuildContext context) {
final isConnected = ref.watch(connectivityProvider);
// If no internet, redirect to InternetCheckScreen
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.go('/internetcheck');
}
});
final profileLocale = ref.watch(localeProvider);
return PopScope(
canPop: false, // Allow back navigation only if not login screen

View File

@ -209,6 +209,21 @@ class LoginRoute extends HookConsumerWidget {
// }
// }
emailValidation({String? message, String? requiredMessage}) {
return (fieldValue) {
if (fieldValue == null || fieldValue.trim().isEmpty) {
return requiredMessage ?? "Email is required";
}
if (!Validator.isEmail(fieldValue)) {
if (fieldValue.contains(" ")) {
return "Space is present, email is not correct";
}
return message ?? "Email is not correct";
}
return null; // Validation passed
};
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final hasValidated = useState(false);
@ -241,7 +256,7 @@ class LoginRoute extends HookConsumerWidget {
content: Form(
key: forgotPwFormKey,
child: TextFormField(
validator: FieldValidator.email(),
validator: emailValidation(),
controller: emailCtl,
decoration: InputDecoration(
labelText: context.translate(
@ -456,7 +471,8 @@ class LoginRoute extends HookConsumerWidget {
print("Is Profile Complete: $isProfileComplete");
// Extract intendedPath from query parameters (if coming from redirect)
final String? intendedPath = GoRouterState.of(context).uri.queryParameters['intendedPath'];
final String? intendedPath =
GoRouterState.of(context).uri.queryParameters['intendedPath'];
print("Extracted intendedPath after login: $intendedPath");
if (!context.mounted) return;

View File

@ -168,6 +168,7 @@ import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/data/p_auth_repo.dart';
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
@ -1134,6 +1135,16 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
fetchData(localeCode);
});
final isConnected = ref.watch(connectivityProvider);
// If no internet, redirect to InternetCheckScreen
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.go('/internetcheck');
}
});
double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width;

View File

@ -7,13 +7,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/bookmark_asset_path.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/uae_numbers_asset_path.dart';
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
class BookMark extends ConsumerStatefulWidget {
const BookMark({super.key});
@ -35,7 +35,6 @@ class _BookMarkState extends ConsumerState<BookMark> {
super.initState();
final locale = ref.read(localeProvider);
fetchBookmarks(locale?.languageCode ?? 'en');
}
String colorToHex(Color color) {
@ -43,6 +42,7 @@ class _BookMarkState extends ConsumerState<BookMark> {
'${color.green.toRadixString(16).padLeft(2, '0').toUpperCase()}'
'${color.blue.toRadixString(16).padLeft(2, '0').toUpperCase()}';
}
// Function to convert hex color string to int
Color _parseColor(String? colorString) {
if (colorString == null || colorString.isEmpty) {
@ -105,26 +105,26 @@ class _BookMarkState extends ConsumerState<BookMark> {
String? mainTopic = item['main_topic'];
String subtitle = item['subtitle'];
// Ignore if main_topic is null
if (mainTopic == null) continue;
// If main_topic doesn't exist in groupedMap, create a new entry
if (!groupedMap.containsKey(mainTopic)) {
groupedMap[mainTopic] = {'main_topic': mainTopic,
groupedMap[mainTopic] = {
'main_topic': mainTopic,
'valueColor': item['valueColor'],
'SubTopic': []
};
}
// Add subtitle as a key with its corresponding map value
groupedMap[mainTopic]!['SubTopic'].add ({
groupedMap[mainTopic]!['SubTopic'].add({
'subtitle': subtitle,
'isBookmark': item['isBookmark'],
'value': item['value'],
'title':item['title'],
'value_source':item['value_source'],
'data_set':item['data_set'],
'title': item['title'],
'value_source': item['value_source'],
'data_set': item['data_set'],
'id': item['id'],
});
}
@ -170,7 +170,7 @@ class _BookMarkState extends ConsumerState<BookMark> {
content: Text(
'Unable to remove from bookmarks. Please try again',
style:
TextStyle(color: Color(0xFFEB5F24), fontWeight: FontWeight.w600),
TextStyle(color: Color(0xFFEB5F24), fontWeight: FontWeight.w600),
),
backgroundColor: Color(0xFFD6E9C6),
duration: Duration(seconds: 2),
@ -253,7 +253,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
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(
@ -264,7 +265,6 @@ class _BookMarkState extends ConsumerState<BookMark> {
),
],
)
],
),
);
@ -272,12 +272,32 @@ class _BookMarkState extends ConsumerState<BookMark> {
@override
Widget build(BuildContext context) {
final isConnected = ref.watch(connectivityProvider);
// If no internet, redirect to InternetCheckScreen
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.go('/internetcheck');
}
});
final List<Map<String, dynamic>> tabs = [
{ 'title':AppLocalizations.of(context)!.all_bookmarks, 'color': Colors.black},
{ 'title': AppLocalizations.of(context)!.economy_title, 'color': Color(0xFF90B0D5)},
{ 'title':AppLocalizations.of(context)!.social_title, 'color': Color(0xFFAA8E83)},
{ 'title': AppLocalizations.of(context)!.environment_title, 'color': Color(0xFF7DAFBC)},
{
'title': AppLocalizations.of(context)!.all_bookmarks,
'color': Colors.black
},
{
'title': AppLocalizations.of(context)!.economy_title,
'color': Color(0xFF90B0D5)
},
{
'title': AppLocalizations.of(context)!.social_title,
'color': Color(0xFFAA8E83)
},
{
'title': AppLocalizations.of(context)!.environment_title,
'color': Color(0xFF7DAFBC)
},
];
ref.listen<Locale?>(localeProvider, (previous, next) {
@ -285,23 +305,26 @@ class _BookMarkState extends ConsumerState<BookMark> {
fetchBookmarks(localeCode);
});
List<Map<String, dynamic>> bookmarks = dataList.where((item) => item['isBookmark'] == true).toList();
List<Map<String, dynamic>> filteredBookmarks = dataList
.where((bookmark) {
List<Map<String, dynamic>> bookmarks =
dataList.where((item) => item['isBookmark'] == true).toList();
List<Map<String, dynamic>> filteredBookmarks = dataList.where((bookmark) {
String mainTopic = bookmark['main_topic'].toString().trim().toLowerCase();
String selectedTabTitle = tabs[selectedTabIndex]['title'].toString().trim().toLowerCase();
String selectedTabTitle =
tabs[selectedTabIndex]['title'].toString().trim().toLowerCase();
// Debugging prints
print("main_topic: '$mainTopic', selected_tab_title: '$selectedTabTitle'");
print(
"main_topic: '$mainTopic', selected_tab_title: '$selectedTabTitle'");
return mainTopic == selectedTabTitle;
})
.toList();
}).toList();
// print( 'filtered one :${filteredBookmarks['main_topic']} , Tabs : ${tabs[selectedTabIndex]["title"]}');
List<Map<String, dynamic>> transformedList = groupedMap.values.toList();
// print('filtered $filteredBookmarks');
return BaseScaffold(
title: Text(AppLocalizations.of(context)!.bookmarks,),
title: Text(
AppLocalizations.of(context)!.bookmarks,
),
body: Column(
children: [
TabBarHeader(
@ -316,134 +339,143 @@ class _BookMarkState extends ConsumerState<BookMark> {
Expanded(
child: selectedTabIndex == 0
? (bookmarks.isNotEmpty
? SingleChildScrollView(
child: Column(
children: List.generate(transformedList.length, (i) {
final mainTopic = transformedList[i];
print('oustside1 $mainTopic');
final list=List.from(mainTopic['SubTopic'] ?? []);
print('oustside2 $list');
return CustomExpandableTile(
index: i,
isExpanded: expandedIndex == i,
onTap: (int index) { // 🔹 Expecting an index
setState(() {
expandedIndex = (expandedIndex == index) ? null : index;
});
},
title: mainTopic['main_topic'] ?? 'No Topic',
childWidget:
Container(
decoration: BoxDecoration(
color: Colors.white,
// borderRadius: BorderRadius.all(Radius.circular(20))
),
padding: const EdgeInsets.all(16),
child: GridView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
mainAxisExtent: 100,
? SingleChildScrollView(
child: Column(
children: List.generate(transformedList.length, (i) {
final mainTopic = transformedList[i];
print('oustside1 $mainTopic');
final list = List.from(mainTopic['SubTopic'] ?? []);
print('oustside2 $list');
return CustomExpandableTile(
index: i,
isExpanded: expandedIndex == i,
onTap: (int index) {
// 🔹 Expecting an index
setState(() {
expandedIndex =
(expandedIndex == index) ? null : index;
});
},
title: mainTopic['main_topic'] ?? 'No Topic',
childWidget: Container(
decoration: BoxDecoration(
color: Colors.white,
// borderRadius: BorderRadius.all(Radius.circular(20))
),
padding: const EdgeInsets.all(16),
child: GridView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
mainAxisExtent: 100,
),
itemCount: list.length,
itemBuilder: (context, index) {
return _buildBoxes(
mainTopic['SubTopic'][index],
context,
mainTopic['valueColor']);
},
),
),
filteredBookmarks:
List.from(mainTopic['SubTopic'] ?? []),
titleBackgroundColor: mainTopic['valueColor'],
// Ensure it's a new list
);
}),
),
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.info_outline,
size: 100, color: Colors.grey[400]),
SizedBox(height: 16),
Text(
context.translate('No BookMark Added',
'لم يتم إضافة أي علامة مرجعية'),
style:
TextStyle(fontSize: 16, color: Colors.grey),
),
],
),
))
: filteredBookmarks.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.info_outline,
size: 100, color: Colors.grey[400]),
SizedBox(height: 16),
Text(
'No Bookmark is added',
style:
TextStyle(fontSize: 16, color: Colors.grey),
),
],
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: tabs[selectedTabIndex]['color'],
borderRadius:
BorderRadius.all(Radius.circular(35))),
padding: const EdgeInsets.only(
left: 16, bottom: 5, top: 5, right: 10),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
tabs[selectedTabIndex]['title'],
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
],
),
),
SizedBox(
height: 20,
),
Expanded(
child: GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
mainAxisExtent: 100,
),
itemCount: filteredBookmarks.length,
itemBuilder: (context, index) {
return _buildBox(
filteredBookmarks[index], context);
},
),
),
],
),
itemCount:list.length,
itemBuilder: (context, index) {
return _buildBoxes(mainTopic['SubTopic'][index], context,mainTopic['valueColor']);
},
),
),
filteredBookmarks: List.from(mainTopic['SubTopic'] ?? []), titleBackgroundColor: mainTopic['valueColor'],
// Ensure it's a new list
);
}),
),
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.info_outline,
size: 100, color: Colors.grey[400]),
SizedBox(height: 16),
Text(
context.translate('No BookMark Added','لم يتم إضافة أي علامة مرجعية'),
style:
TextStyle(fontSize: 16, color: Colors.grey),
),
],
),
))
:filteredBookmarks.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.info_outline,
size: 100, color: Colors.grey[400]),
SizedBox(height: 16),
Text(
'No Bookmark is added',
style:
TextStyle(fontSize: 16, color: Colors.grey),
),
],
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: tabs[selectedTabIndex]['color'],
borderRadius: BorderRadius.all(Radius.circular(35))
),
padding: const EdgeInsets.only(
left: 16, bottom: 5, top: 5, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
tabs[selectedTabIndex]['title'],
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
],
),
),
SizedBox(height: 20,),
Expanded(
child: GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
mainAxisExtent: 100,
),
itemCount: filteredBookmarks.length,
itemBuilder: (context, index) {
return _buildBox(filteredBookmarks[index], context);
},
),
),
],
),
),
),
],
),
);
}
Widget _buildBox(Map<String, dynamic> data, BuildContext context) {
// Color borderColor = data['valueColor'];
return GestureDetector(
@ -501,10 +533,9 @@ class _BookMarkState extends ConsumerState<BookMark> {
child: SvgPicture.asset(
BookmarkAssetPath.delete,
semanticsLabel: 'share',
width:23,
width: 23,
height: 20,
)
),
)),
// GestureDetector(
// onTap: () {
@ -543,7 +574,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
);
}
Widget _buildBoxes(Map<String, dynamic> data, BuildContext context, Color styleColor) {
Widget _buildBoxes(
Map<String, dynamic> data, BuildContext context, Color styleColor) {
// Color borderColor = data['valueColor'];
print('inside function $data');
return GestureDetector(
@ -555,7 +587,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
final encodedTitle = data['title'];
String hexColor = colorToHex(styleColor);
debugPrint( '/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle');
debugPrint(
'/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle');
// String hexColor = colorToHex(colorPattern); // Get hex string
// print(hexColor); // Prints: 0xFFAA8E83
@ -573,8 +606,7 @@ class _BookMarkState extends ConsumerState<BookMark> {
borderRadius: BorderRadius.circular(10),
border: Border.all(color: styleColor),
),
child:
Align(
child: Align(
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
@ -603,10 +635,9 @@ class _BookMarkState extends ConsumerState<BookMark> {
child: SvgPicture.asset(
BookmarkAssetPath.delete,
semanticsLabel: 'share',
width:23,
width: 23,
height: 20,
)
),
)),
],
),
Text(
@ -630,11 +661,10 @@ class _BookMarkState extends ConsumerState<BookMark> {
),
);
}
}
class TabBarHeader extends StatelessWidget {
final List<Map<String, dynamic>> tabs;
final List<Map<String, dynamic>> tabs;
final int selectedIndex;
final ValueChanged<int> onTabSelected;
@ -662,7 +692,7 @@ class TabBarHeader extends StatelessWidget {
onPressed: () => onTabSelected(index),
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.resolveWith((states) {
MaterialStateProperty.resolveWith((states) {
return selectedIndex == index
? entry.value['color']
: Colors.grey[700];
@ -715,7 +745,6 @@ class CustomExpandableTile extends StatefulWidget {
}
class _CustomExpandableTileState extends State<CustomExpandableTile> {
@override
void initState() {
super.initState(); // Initialize isExpanded based on widget's property
@ -733,13 +762,13 @@ class _CustomExpandableTileState extends State<CustomExpandableTile> {
onTap: () => widget.onTap(widget.index),
child: Container(
decoration: BoxDecoration(
color: Colors.white, // Ensuring the background outside the rounded container is white
color: Colors
.white, // Ensuring the background outside the rounded container is white
),
child: Container(
decoration: BoxDecoration(
color: widget.titleBackgroundColor,
borderRadius: BorderRadius.all(Radius.circular(35))
),
borderRadius: BorderRadius.all(Radius.circular(35))),
padding: const EdgeInsets.only(
left: 16, bottom: 5, top: 5, right: 10),
child: Row(
@ -771,37 +800,37 @@ class _CustomExpandableTileState extends State<CustomExpandableTile> {
curve: Curves.easeInOut,
width: double.infinity,
color: Colors.white,
height:widget.isExpanded ? myheight * 0.4 : 0,
child:widget.isExpanded
// height: widget.isExpanded ? myheight * 0.4 : 0,
child: widget.isExpanded
? SingleChildScrollView(
child: Column(
children: [
widget.childWidget,
// Container(
// decoration: BoxDecoration(
// color: Colors.white,
// // borderRadius: BorderRadius.all(Radius.circular(20))
// ),
// padding: const EdgeInsets.all(16),
// child: GridView.builder(
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// gridDelegate:
// const SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 2,
// crossAxisSpacing: 10.0,
// mainAxisSpacing: 10.0,
// mainAxisExtent: 100,
// ),
// itemCount: widget.filteredBookmarks.length,
// itemBuilder: (context, index) {
// return _buildBox(widget.filteredBookmarks[index], context,widget.titleBackgroundColor);
// },
// ),
// ),
],
),
)
child: Column(
children: [
widget.childWidget,
// Container(
// decoration: BoxDecoration(
// color: Colors.white,
// // borderRadius: BorderRadius.all(Radius.circular(20))
// ),
// padding: const EdgeInsets.all(16),
// child: GridView.builder(
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// gridDelegate:
// const SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 2,
// crossAxisSpacing: 10.0,
// mainAxisSpacing: 10.0,
// mainAxisExtent: 100,
// ),
// itemCount: widget.filteredBookmarks.length,
// itemBuilder: (context, index) {
// return _buildBox(widget.filteredBookmarks[index], context,widget.titleBackgroundColor);
// },
// ),
// ),
],
),
)
: null,
),
),

View File

@ -5,6 +5,7 @@ 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:shared_preferences/shared_preferences.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';
@ -21,28 +22,67 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
// Example notification data
final _pb = PocketBase(apiUrl);
List<Map<String, dynamic>> notifications = [];
List<String> pushedNotification = [];
// Current selected tab index
int selectedTabIndex = 0;
late final Locale locale;
dynamic userID;
// Tab categories
final List<String> tabs = [
"All updates",
"App updates",
"Social",
"Economy",
"Environment",
"Favourites"
];
// final List<String> tabs = [
// "All updates",
// "App updates",
// "Social",
// "Economy",
// "Environment",
// "Favourites"
// ];
@override
void initState() {
super.initState();
locale = ref.read(localeProvider) ?? const Locale('en');
_fetchUserData();
fetchNotifications(locale?.languageCode ?? 'en');
}
Future<String?> getUserId() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('userId'); // Retrieve the userId
}
Future<void> _fetchUserData() async {
try {
String? fetchedUserId = await getUserId();
userID = fetchedUserId;
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token;
print('adminToken- ${adminToken}');
final userDetailsResponse = await _pb.collection('users').getOne(
fetchedUserId!,
headers: {
'Authorization': 'Bearer $adminToken',
},
);
print('userDetails: $userDetailsResponse');
setState(() {
print('In');
// Extract pushed_notification from response
List<dynamic> notifications =
userDetailsResponse.data['pushed_notification'];
// Convert to List<String>
pushedNotification = List<String>.from(notifications);
print('pushedNotification: $pushedNotification');
});
} catch (e) {
print('Error fetching user details: $e');
}
}
String formatDate(String dateString) {
try {
DateTime dateTime =
@ -81,21 +121,6 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
}
}
// 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) {
@ -177,6 +202,8 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
category: notification['category'] ?? 'Unknown',
message: notification['message'] ?? '',
id: notification['id'],
pushedNotification: pushedNotification,
userID: userID,
),
);
},
@ -253,6 +280,8 @@ class NotificationTile extends StatelessWidget {
final String date;
final String category;
final String id;
final String userID;
final List<String> pushedNotification;
const NotificationTile({
required this.title,
@ -260,37 +289,83 @@ class NotificationTile extends StatelessWidget {
required this.date,
required this.category,
required this.id,
required this.userID,
required this.pushedNotification,
});
@override
Widget build(BuildContext context) {
bool isPushed = pushedNotification.contains(id);
print('isPushed $isPushed , $id');
return GestureDetector(
onTap: () {
final encodedKey = Uri.encodeQueryComponent('notification');
context.go('/notification_details', extra: {
'title': title,
'message': message,
'date': date,
'category': category,
'id': id,
'backNavigation': encodedKey
});
},
onTap: isPushed
? () {
readedNotification(userID, id);
final encodedKey = Uri.encodeQueryComponent('notification');
context.go('/notification_details', extra: {
'title': title,
'message': message,
'date': date,
'category': category,
'id': id,
'backNavigation': encodedKey
});
}
: null,
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)),
leading: isPushed
? const Icon(Icons.circle, size: 12, color: Color(0xFFFF274E))
: const Icon(Icons.circle, size: 12, color: Color(0x99414042)),
title: Text(
title,
style: TextStyle(
color: isPushed ? const Color(0xFF414042) : const Color(0x99414042),
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
date,
style: const TextStyle(
color: Color(0xFF8E8E8E),
fontSize: 12,
fontWeight: FontWeight.w400),
style: TextStyle(
color: isPushed ? const Color(0xFF8E8E8E) : const Color(0x998E8E8E),
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
trailing: const Icon(Icons.arrow_forward_ios,
size: 16, color: Color(0xFF898C81)),
trailing: isPushed
? const Icon(Icons.arrow_forward_ios,
size: 16, color: Color(0xFF898C81))
: null,
),
);
}
}
final pb = PocketBase(apiUrl);
Future<void> readedNotification(String userId, String notificationId) async {
await pb.admins.authWithPassword(
'pb@venbainfotech.com',
'pb@venbainfotech.com',
);
final url =
"${pb.baseUrl}api/removeNotification?user_id=$userId&notification_id=$notificationId";
try {
final response = await http.get(
Uri.parse(url),
headers: {
'Content-Type': 'application/json', // Add this
'Authorization': pb.authStore.token, // Correct way to send auth token
},
);
if (response.statusCode == 200) {
print("✅ updated successfully!");
} else {
print("❌ Failed to update : ${response.body}");
}
} catch (e) {
print("🚨 Error updating : $e");
}
}

View File

@ -173,10 +173,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4
url: "https://pub.dev"
source: hosted
version: "8.9.4"
version: "8.9.5"
characters:
dependency: transitive
description:
@ -824,10 +824,10 @@ packages:
dependency: transitive
description:
name: image_picker_android
sha256: "82652a75e3dd667a91187769a6a2cc81bd8c111bbead698d8e938d2b63e5e89a"
sha256: "8bd392ba8b0c8957a157ae0dc9fcf48c58e6c20908d5880aea1d79734df090e9"
url: "https://pub.dev"
source: hosted
version: "0.8.12+21"
version: "0.8.12+22"
image_picker_for_web:
dependency: transitive
description:
@ -892,6 +892,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.7.0"
internet_connection_checker:
dependency: "direct main"
description:
name: internet_connection_checker
sha256: ee08f13d8b13b978affe226e9274ca3ba7a9bed07c9479e8ae245f785b7a488a
url: "https://pub.dev"
source: hosted
version: "3.0.1"
intl:
dependency: "direct main"
description:
@ -1104,10 +1112,10 @@ packages:
dependency: transitive
description:
name: path_provider_android
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12"
url: "https://pub.dev"
source: hosted
version: "2.2.15"
version: "2.2.16"
path_provider_foundation:
dependency: transitive
description:
@ -1192,10 +1200,10 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
version: "2.2.0"
pubspec_parse:
dependency: transitive
description:
@ -1311,10 +1319,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_android
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad"
url: "https://pub.dev"
source: hosted
version: "2.4.6"
version: "2.4.8"
shared_preferences_foundation:
dependency: transitive
description:
@ -1539,10 +1547,10 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4"
url: "https://pub.dev"
source: hosted
version: "6.3.14"
version: "6.3.15"
url_launcher_ios:
dependency: transitive
description:
@ -1643,10 +1651,10 @@ packages:
dependency: transitive
description:
name: video_player_android
sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b"
sha256: d949a83d1a333178eb3a9683f70afa41b7771c2bfa4cedd894fe836942de06b1
url: "https://pub.dev"
source: hosted
version: "2.7.17"
version: "2.8.1"
video_player_avfoundation:
dependency: transitive
description:
@ -1723,10 +1731,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
sha256: "512c26ccc5b8a571fd5d13ec994b7509f142ff6faf85835e243dde3538fdc713"
sha256: "631093a7fbd93e9690ac61d8c8f3e857efbc189fc33f712b9ad6c01a623517ef"
url: "https://pub.dev"
source: hosted
version: "4.3.2"
version: "4.3.3"
webview_flutter_platform_interface:
dependency: transitive
description:

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.32+33
version: 1.0.33+34
environment:
sdk: ">=3.2.3 <4.0.0"
@ -68,6 +68,7 @@ dependencies:
flutter_svg: ^2.0.17
boxy: ^2.2.1
firebase_messaging: ^15.2.4
internet_connection_checker: ^3.0.1
dependency_overrides:
fading_edge_scrollview: ^4.1.1