This commit is contained in:
venbaittech 2025-02-28 09:24:03 +05:30
commit cd1bb0fc8c
15 changed files with 537 additions and 178 deletions

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.1191 21.8809L17.6427 16.4056C19.2299 14.5 20.0214 12.0558 19.8525 9.58143C19.6836 7.10709 18.5672 4.79313 16.7357 3.12091C14.9041 1.4487 12.4984 0.546971 10.0189 0.603321C7.53944 0.65967 5.17715 1.66976 3.42345 3.42345C1.66976 5.17715 0.65967 7.53944 0.603321 10.0189C0.546971 12.4984 1.4487 14.9041 3.12091 16.7357C4.79313 18.5672 7.10709 19.6836 9.58143 19.8525C12.0558 20.0214 14.5 19.2299 16.4056 17.6427L21.8809 23.1191C21.9622 23.2004 22.0588 23.2649 22.165 23.3088C22.2712 23.3528 22.385 23.3755 22.5 23.3755C22.615 23.3755 22.7288 23.3528 22.835 23.3088C22.9413 23.2649 23.0378 23.2004 23.1191 23.1191C23.2004 23.0378 23.2649 22.9413 23.3088 22.835C23.3528 22.7288 23.3755 22.615 23.3755 22.5C23.3755 22.385 23.3528 22.2712 23.3088 22.165C23.2649 22.0588 23.2004 21.9622 23.1191 21.8809ZM2.37501 10.25C2.37501 8.69248 2.83687 7.16993 3.70218 5.87489C4.5675 4.57985 5.79741 3.57049 7.23637 2.97445C8.67534 2.37841 10.2587 2.22246 11.7863 2.52632C13.3139 2.83018 14.7171 3.5802 15.8185 4.68154C16.9198 5.78288 17.6698 7.18607 17.9737 8.71367C18.2775 10.2413 18.1216 11.8247 17.5256 13.2636C16.9295 14.7026 15.9202 15.9325 14.6251 16.7978C13.3301 17.6631 11.8075 18.125 10.25 18.125C8.16214 18.1227 6.16044 17.2923 4.6841 15.8159C3.20775 14.3396 2.37732 12.3379 2.37501 10.25Z" fill="#9EA2A9"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.125 3L10.325 11.6637V18.1683L13.925 20V11.6637L21.125 3H3.125Z" stroke="white" stroke-width="2" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 237 B

View File

@ -12,5 +12,5 @@ abstract class MiscIconAssetPath {
static const save = '$_basePath/save.png'; static const save = '$_basePath/save.png';
static const group = '$_basePath/group.png'; static const group = '$_basePath/group.png';
static const search = '$_basePath/search.png'; static const search = '$_basePath/search.png';
static const Search = '$_basePath/Search.svg';
} }

View File

@ -6,5 +6,6 @@ abstract class UaeNumbersAssetPath {
// static const bookmarksSelectedUae = '$_basePath/bookmarksSelectedUae.png'; // static const bookmarksSelectedUae = '$_basePath/bookmarksSelectedUae.png';
// static const shareUae = '$_basePath/share.png'; // static const shareUae = '$_basePath/share.png';
static const share = '$_basePath/share.svg'; static const share = '$_basePath/share.svg';
static const filterUae = '$_basePath/filters.png'; static const filterUae = '$_basePath/filters.png';
static const filterCharts = '$_basePath/Filter.svg';
} }

View File

@ -1,8 +1,8 @@
{ {
"all_bookmarks":"كل العلامات المرجعية", "all_bookmarks":"كل العلامات المرجعية",
"economy_title":" الاقتصاد", "economy_title":"اقتصاد",
"social_title":"اجتماعي", "social_title":"اجتماعي",
"environment_title":"البيئة", "environment_title":"بيئة",
"bookmarks": "الإشارات المرجعية", "bookmarks": "الإشارات المرجعية",
"feedback_title": "تعليق", "feedback_title": "تعليق",

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart';
@ -199,11 +200,13 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search", hintText: "Search",
hintStyle: TextStyle(color: Color(0xFF898C81)), hintStyle: TextStyle(color: Color(0xFF898C81)),
prefixIconConstraints: BoxConstraints(maxWidth: 42, maxHeight: 42),
prefixIcon: Image( prefixIcon: Container(
image: ExactAssetImage(MiscIconAssetPath.search), padding: EdgeInsets.only(right: 5),
width: 24, child: SvgPicture.asset(
height: 24, MiscIconAssetPath.Search,
semanticsLabel: 'Search',
),
), ),
// prefixIcon: Image.asset( // prefixIcon: Image.asset(

View File

@ -33,7 +33,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
bool _obscureNewPassword = true; bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true; bool _obscureConfirmPassword = true;
bool _isPasswordUpdated = false; // Variable to toggle UI bool _isPasswordUpdated = false; // Variable to toggle UI
bool hasValidated = false;
String? _oldPassword; String? _oldPassword;
String? _newPassword; String? _newPassword;
String? _confirmPassword; String? _confirmPassword;
@ -243,10 +243,12 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
pathColorWhenOn: Colors.grey.shade300, pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: () { onTap: () {
print('has validated $hasValidated');
final formState = _formKey.currentState; final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () { Future.delayed(Duration(milliseconds: 100), () {
if (formState?.validate() == false) { if (hasValidated && formState?.validate() == false) {
print('has validated $hasValidated');
formState?.validate(); formState?.validate();
} }
}); });
@ -582,6 +584,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
width: screenWidth / 1.1, width: screenWidth / 1.1,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
setState(() {
hasValidated=true;
});
if ((_formKey.currentState?.validate() ?? false)) { if ((_formKey.currentState?.validate() ?? false)) {
await updatePassword( await updatePassword(
widget.userId, widget.userId,

View File

@ -28,7 +28,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
final _emailController = TextEditingController(); final _emailController = TextEditingController();
final _passwordController = TextEditingController(); final _passwordController = TextEditingController();
final _confirmpasswordController = TextEditingController(); final _confirmpasswordController = TextEditingController();
bool hasValidated = false;
bool _obscurePassword = true; bool _obscurePassword = true;
bool _obscureConfirmPassword = true; bool _obscureConfirmPassword = true;
bool isChecked = false; bool isChecked = false;
@ -217,6 +217,9 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
} }
Future<void> _registerUser() async { Future<void> _registerUser() async {
setState(() {
hasValidated = true;
});
if (_formKey.currentState?.validate() ?? false) { if (_formKey.currentState?.validate() ?? false) {
if (isChecked) { if (isChecked) {
setState(() { setState(() {
@ -387,7 +390,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
final formState = _formKey.currentState; final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () { Future.delayed(Duration(milliseconds: 100), () {
if (formState?.validate() == false) { if (hasValidated && formState?.validate() == false) {
formState?.validate(); formState?.validate();
} }
}); });
@ -1111,11 +1114,11 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
?.languageCode == ?.languageCode ==
'ar' 'ar'
? 0 ? 0
: 30.0, : 40.0,
right: registerLocale right: registerLocale
?.languageCode == ?.languageCode ==
'ar' 'ar'
? 40 ? 45
: 0.0,), : 0.0,),
child: Text( child: Text(
context.translate('Required', 'مطلوب'), context.translate('Required', 'مطلوب'),

View File

@ -1535,11 +1535,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
children: [ children: [
Row( Row(
children: [ children: [
Image.asset( SvgPicture.asset(
UaeNumbersAssetPath.filterUae, UaeNumbersAssetPath.filterCharts,
color: Color(0xFF8E8E8E), // Outline color semanticsLabel: 'Filter',
width: 24, // Slightly larger colorFilter:ColorFilter.mode(Color(0xFF8E8E8E),BlendMode.srcIn),
height: 24, width: 25,
height: 25,
), ),
SizedBox(width: 8), SizedBox(width: 8),
Text( Text(
@ -2265,12 +2266,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
), ),
), ),
SizedBox(width: 10), SizedBox(width: 10),
Image.asset( SvgPicture.asset(
UaeNumbersAssetPath.filterUae, UaeNumbersAssetPath.filterCharts,
color: Colors semanticsLabel: 'Filter',
.white, // Set color to white width: 24,
width: 21, height: 24,
height: 21,
), ),
], ],
), ),

View File

@ -37,7 +37,7 @@ class ProfileScreen extends ConsumerStatefulWidget {
class _ProfileScreenState extends ConsumerState<ProfileScreen> { class _ProfileScreenState extends ConsumerState<ProfileScreen> {
final _pb = PocketBase(apiUrl); final _pb = PocketBase(apiUrl);
// final _pb = PocketBase('http://127.0.0.1:8090'); // final _pb = PocketBase('http://127.0.0.1:8090');
bool hasValidated = false;
// Add focus nodes and hint states // Add focus nodes and hint states
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode()); final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
final List<bool> _showHints = [ final List<bool> _showHints = [
@ -457,6 +457,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final profileLocale = ref.watch(localeProvider);
return PopScope( return PopScope(
canPop: false, // Allow back navigation only if not login screen canPop: false, // Allow back navigation only if not login screen
onPopInvokedWithResult: (didPop, result) { onPopInvokedWithResult: (didPop, result) {
@ -489,7 +490,13 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
pathColorWhenOn: Colors.grey.shade300, pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: () { onTap: () {
final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (hasValidated && formState?.validate() == false) {
formState?.validate();
}
});
}, },
); );
}, },
@ -785,7 +792,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
), ),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
labelText: 'Select', labelText: context.translate('Select',' اختيار')
), ),
icon: Icon(Icons.keyboard_arrow_down_sharp, icon: Icon(Icons.keyboard_arrow_down_sharp,
color: color:
@ -911,7 +918,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0), padding: EdgeInsets.only(left: 10.0, right: profileLocale
?.languageCode ==
'ar'
? 15
: 0.0,),
child: Text( child: Text(
context.translate('Required', 'مطلوب'), context.translate('Required', 'مطلوب'),
style: TextStyle( style: TextStyle(
@ -948,6 +959,9 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
// ElevatedButton.icon( // ElevatedButton.icon(
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
setState(() {
hasValidated = true;
});
if ((_formKey.currentState?.validate() ?? false) && if ((_formKey.currentState?.validate() ?? false) &&
(isChecked)) { (isChecked)) {
_formKey.currentState?.save(); _formKey.currentState?.save();

View File

@ -45,7 +45,7 @@ class ThemedFormField extends HookWidget {
final inputDecoration = InputDecoration( final inputDecoration = InputDecoration(
filled: true, filled: true,
fillColor: Colors.white, fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(vertical: 14), contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 15),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide( borderSide: BorderSide(

View File

@ -127,6 +127,7 @@ class LoginRoute extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final hasValidated = useState(false);
final locale = ref.watch(localeProvider); final locale = ref.watch(localeProvider);
final emailCtl = useTextEditingController(); final emailCtl = useTextEditingController();
final pwCtl = useTextEditingController(); final pwCtl = useTextEditingController();
@ -272,6 +273,7 @@ class LoginRoute extends HookConsumerWidget {
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
hasValidated.value=true;
final isValid = formKey.currentState!.validate(); final isValid = formKey.currentState!.validate();
if (!isValid) return; if (!isValid) return;
final session = await context.loaderWithErrorDialog( final session = await context.loaderWithErrorDialog(
@ -680,7 +682,7 @@ class LoginRoute extends HookConsumerWidget {
final formState = formKey.currentState; final formState = formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () { Future.delayed(Duration(milliseconds: 100), () {
if (formState?.validate() == false) { if (hasValidated.value && formState?.validate() == false) {
formState?.validate(); formState?.validate();
} }
}); });

View File

@ -25,19 +25,11 @@ class _BookMarkState extends ConsumerState<BookMark> {
final _pb = PocketBase(apiUrl); final _pb = PocketBase(apiUrl);
List<Map<String, dynamic>> dataList = []; List<Map<String, dynamic>> dataList = [];
bool isLoading = true; bool isLoading = true;
Map<String, Map<String, dynamic>> groupedMap = {};
int? expandedIndex = 0;
// Current selected tab index // Current selected tab index
int selectedTabIndex = 0; int selectedTabIndex = 0;
// Tab categories
// final List<String> tabs = [
// 'All Bookmarks',
// 'Economy',
// 'Social',
// 'Environment',
// ];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -106,8 +98,36 @@ class _BookMarkState extends ConsumerState<BookMark> {
'id': item['id'], 'id': item['id'],
}; };
}).toList(); }).toList();
print('dataList $dataList'); // print('dataList $dataList');
}); });
groupedMap = {};
for (var item in dataList) {
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,
'valueColor': item['valueColor'],
'SubTopic': []
};
}
// Add subtitle as a key with its corresponding map value
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'],
'id': item['id'],
});
}
} }
} }
} catch (e) { } catch (e) {
@ -268,11 +288,11 @@ class _BookMarkState extends ConsumerState<BookMark> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<String> tabs = [ final List<Map<String, dynamic>> tabs = [
AppLocalizations.of(context)!.all_bookmarks, { 'title':AppLocalizations.of(context)!.all_bookmarks, 'color': Colors.black},
AppLocalizations.of(context)!.economy_title, { 'title': AppLocalizations.of(context)!.economy_title, 'color': Color(0xFF90B0D5)},
AppLocalizations.of(context)!.social_title, { 'title':AppLocalizations.of(context)!.social_title, 'color': Color(0xFFAA8E83)},
AppLocalizations.of(context)!.environment_title, { 'title': AppLocalizations.of(context)!.environment_title, 'color': Color(0xFF7DAFBC)},
]; ];
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
@ -282,11 +302,19 @@ class _BookMarkState extends ConsumerState<BookMark> {
List<Map<String, dynamic>> bookmarks = dataList.where((item) => item['isBookmark'] == true).toList(); List<Map<String, dynamic>> bookmarks = dataList.where((item) => item['isBookmark'] == true).toList();
List<Map<String, dynamic>> filteredBookmarks = dataList List<Map<String, dynamic>> filteredBookmarks = dataList
.where((bookmark) => .where((bookmark) {
bookmark['main_topic'].toString().trim().toLowerCase() == tabs[selectedTabIndex].toString().trim().toLowerCase()) String mainTopic = bookmark['main_topic'].toString().trim().toLowerCase();
.toList(); String selectedTabTitle = tabs[selectedTabIndex]['title'].toString().trim().toLowerCase();
print('filtered $filteredBookmarks'); // Debugging prints
print("main_topic: '$mainTopic', selected_tab_title: '$selectedTabTitle'");
return mainTopic == selectedTabTitle;
})
.toList();
// print( 'filtered one :${filteredBookmarks['main_topic']} , Tabs : ${tabs[selectedTabIndex]["title"]}');
List<Map<String, dynamic>> transformedList = groupedMap.values.toList();
// print('filtered $filteredBookmarks');
return BaseScaffold( return BaseScaffold(
title: Text(AppLocalizations.of(context)!.bookmarks,), title: Text(AppLocalizations.of(context)!.bookmarks,),
body: Column( body: Column(
@ -302,23 +330,68 @@ class _BookMarkState extends ConsumerState<BookMark> {
), ),
Expanded( Expanded(
child: selectedTabIndex == 0 child: selectedTabIndex == 0
? Padding( ? (bookmarks.isNotEmpty
padding: const EdgeInsets.all(8.0), ? SingleChildScrollView(
child: GridView.builder( child: Column(
gridDelegate: children: List.generate(transformedList.length, (i) {
const SliverGridDelegateWithFixedCrossAxisCount( final mainTopic = transformedList[i];
crossAxisCount: 2, print('oustside1 $mainTopic');
crossAxisSpacing: 10.0, final list=List.from(mainTopic['SubTopic'] ?? []);
mainAxisSpacing: 10.0, print('oustside2 $list');
mainAxisExtent: 100, return CustomExpandableTile(
), index: i,
itemCount: bookmarks.length, isExpanded: expandedIndex == i,
itemBuilder: (context, index) { onTap: (int index) { // 🔹 Expecting an index
return _buildBox(bookmarks[index], context); 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
);
}),
), ),
)
):filteredBookmarks.isEmpty : 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( ? Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -336,20 +409,47 @@ class _BookMarkState extends ConsumerState<BookMark> {
) )
: Padding( : Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: GridView.builder( child: Column(
gridDelegate: children: [
const SliverGridDelegateWithFixedCrossAxisCount( Container(
crossAxisCount: 2, decoration: BoxDecoration(
crossAxisSpacing: 10.0, color: tabs[selectedTabIndex]['color'],
mainAxisSpacing: 10.0, borderRadius: BorderRadius.all(Radius.circular(35))
mainAxisExtent: 100, ),
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,
),
), ),
itemCount: filteredBookmarks.length, ],
itemBuilder: (context, index) { ),
return _buildBox(filteredBookmarks[index], context); ),
}, 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);
},
),
),
],
),
), ),
), ),
], ],
@ -372,7 +472,7 @@ class _BookMarkState extends ConsumerState<BookMark> {
print(hexColor); // Prints: 0xFFAA8E83 print(hexColor); // Prints: 0xFFAA8E83
debugPrint("Box clicked: ${data['title']}"); debugPrint("Box clicked: ${data['title']}");
context.go( context.push(
'/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle'); '/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle');
}, },
child: Container( child: Container(
@ -457,10 +557,110 @@ class _BookMarkState extends ConsumerState<BookMark> {
), ),
); );
} }
Widget _buildBoxes(Map<String, dynamic> data, BuildContext context, Color styleColor) {
// Color borderColor = data['valueColor'];
print('inside function $data');
return GestureDetector(
onTap: () {
final data_set = data['data_set'];
// final Color colorPattern = data['valueColor'];
final encodedMainTopic = data['main_topic'];
final encodedTitle = data['title'];
String hexColor = colorToHex(styleColor);
debugPrint( '/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle');
// String hexColor = colorToHex(colorPattern); // Get hex string
// print(hexColor); // Prints: 0xFFAA8E83
// debugPrint("Box clicked: ${data['title']}");
context.push(
'/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle');
},
child: Container(
width: MediaQuery.of(context).size.width * 0.4,
height: 100,
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: styleColor),
),
child:
Align(
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Align(
alignment: Alignment.center,
child: Text(
data['title'] ?? '',
style: const TextStyle(fontWeight: FontWeight.w500),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
),
GestureDetector(
onTap: () {
debugPrint("Icon clicked in: ${data['title']}");
removeBookmark(data['id']);
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// context.translate('Removed From Bookmark','تمت الإزالة من العلامات المرجعية'),
// // style: TextStyle(color: Color(0xFF2F692C),
// // fontWeight: FontWeight.w500),
// ),
// // backgroundColor: Color(0xFFD6E9C6),
// duration: Duration(seconds: 2),
// ),
// );
},
child: SvgPicture.asset(
BookmarkAssetPath.delete,
semanticsLabel: 'share',
width:23,
height: 20,
)
),
],
),
Text(
data['value_source'] ?? '',
style: const TextStyle(
fontWeight: FontWeight.w500, color: Colors.grey),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
Text(
data['value'] ?? '',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: styleColor,
),
),
],
),
),
),
);
}
} }
class TabBarHeader extends StatelessWidget { class TabBarHeader extends StatelessWidget {
final List<String> tabs; final List<Map<String, dynamic>> tabs;
final int selectedIndex; final int selectedIndex;
final ValueChanged<int> onTabSelected; final ValueChanged<int> onTabSelected;
@ -481,7 +681,7 @@ class TabBarHeader extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: tabs.asMap().entries.map((entry) { children: tabs.asMap().entries.map((entry) {
int index = entry.key; int index = entry.key;
String text = entry.value; String text = entry.value['title'];
return Row( return Row(
children: [ children: [
TextButton( TextButton(
@ -490,7 +690,7 @@ class TabBarHeader extends StatelessWidget {
foregroundColor: foregroundColor:
MaterialStateProperty.resolveWith((states) { MaterialStateProperty.resolveWith((states) {
return selectedIndex == index return selectedIndex == index
? Colors.black ? entry.value['color']
: Colors.grey[700]; : Colors.grey[700];
}), }),
), ),
@ -506,7 +706,7 @@ class TabBarHeader extends StatelessWidget {
} }
Widget buildDivider() { Widget buildDivider() {
return Container( return SizedBox(
height: 20, height: 20,
child: const VerticalDivider( child: const VerticalDivider(
color: Colors.grey, color: Colors.grey,
@ -516,3 +716,123 @@ class TabBarHeader extends StatelessWidget {
); );
} }
} }
class CustomExpandableTile extends StatefulWidget {
final String title;
final Color titleBackgroundColor;
final List filteredBookmarks;
final int index;
final bool isExpanded;
final ValueChanged<int> onTap;
final Widget childWidget;
const CustomExpandableTile({
required this.title,
required this.titleBackgroundColor,
required this.filteredBookmarks,
required this.index,
required this.isExpanded,
required this.onTap,
required this.childWidget,
});
@override
_CustomExpandableTileState createState() => _CustomExpandableTileState();
}
class _CustomExpandableTileState extends State<CustomExpandableTile> {
@override
void initState() {
super.initState(); // Initialize isExpanded based on widget's property
}
@override
Widget build(BuildContext context) {
double myheight = MediaQuery.of(context).size.height;
// print(widget.filteredBookmarks);
return Card(
elevation: 0,
child: Column(
children: [
GestureDetector(
onTap: () => widget.onTap(widget.index),
child: Container(
decoration: BoxDecoration(
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))
),
padding: const EdgeInsets.only(
left: 16, bottom: 5, top: 5, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.title,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
Icon(
widget.isExpanded
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Colors.white,
size: 28.0,
),
],
),
),
),
),
ClipRRect(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: double.infinity,
color: Colors.white,
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);
// },
// ),
// ),
],
),
)
: null,
),
),
],
),
);
}
}

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
@ -343,11 +344,14 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search", hintText: "Search",
hintStyle: TextStyle(color: Color(0xFF898C81)), hintStyle: TextStyle(color: Color(0xFF898C81)),
prefixIcon: Image( prefixIconConstraints: BoxConstraints(maxWidth: 42, maxHeight: 42),
image: ExactAssetImage(MiscIconAssetPath.search), prefixIcon: Container(
width: 24, padding: EdgeInsets.only(right: 5),
height: 24, child: SvgPicture.asset(
color: Color(0xFFAA8E83)), MiscIconAssetPath.Search,
semanticsLabel: 'Search',
),
),
// prefixIcon: Image.asset( // prefixIcon: Image.asset(
// MiscIconAssetPath.search, // MiscIconAssetPath.search,

View File

@ -7,7 +7,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class Userguide extends StatefulWidget { class Userguide extends StatefulWidget {
const Userguide({super.key}); Userguide({super.key});
@override @override
State<Userguide> createState() => _UserguideState(); State<Userguide> createState() => _UserguideState();
@ -20,6 +20,7 @@ class _UserguideState extends State<Userguide> {
{'routePath':'faq','color': Color(0xFF7296BE), 'text': 'FAQs', 'icon': 'mdi:faq', 'text-ar': 'لأسئلة الشائعة'}, {'routePath':'faq','color': Color(0xFF7296BE), 'text': 'FAQs', 'icon': 'mdi:faq', 'text-ar': 'لأسئلة الشائعة'},
]; ];
@override
Widget buildDynamicWidget(dynamic icons, Color color) { Widget buildDynamicWidget(dynamic icons, Color color) {
if (icons is IconData) { if (icons is IconData) {
return Icon( return Icon(
@ -46,41 +47,41 @@ class _UserguideState extends State<Userguide> {
} }
} }
@override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopScope( return PopScope(
canPop: false, canPop: false,
onPopInvokedWithResult: (didPop, result) { onPopInvokedWithResult: (didPop, result) {
if (didPop) return; if (didPop) return;
context.go('/myhomepage'); context.go('/myhomepage');
}, },
child: BaseScaffold( child: BaseScaffold(
showDivider: true, showDivider: true,
bottomColor: Colors.white, bottomColor: Colors.white,
dividerColor: Colors.grey[300], dividerColor: Colors.grey[300],
appbarColor: Colors.white, appbarColor: Colors.white,
title: Text(AppLocalizations.of(context)!.guide_title) , title: Text(AppLocalizations.of(context)!.guide_title) ,
body: Container( body: Container(
color: Colors.white, color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 16 , vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 16 , vertical: 20),
child: GridView.builder( child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, // Two columns crossAxisCount: 2,
crossAxisSpacing: 10.0, crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0, mainAxisSpacing: 10.0,
mainAxisExtent:MediaQuery.of(context).size.height* 0.15 , childAspectRatio: 1.7,
// mainAxisExtent:MediaQuery.of(context).size.height* 0.15 ,
),
itemCount: guideList.length,
itemBuilder: (context, index) {
return HoverContainer(
iconName: guideList[index]['icon'],
title: context.translate(guideList[index]['text'], guideList[index]['text-ar']),
routePath: guideList[index]['routePath'],
);
},
), ),
itemCount: guideList.length,
itemBuilder: (context, index) {
return HoverContainer(
iconName: guideList[index]['icon'],
title: context.translate(guideList[index]['text'], guideList[index]['text-ar']),
routePath: guideList[index]['routePath'],
);
},
), ),
), ),
),
); );
} }
@ -108,69 +109,69 @@ class _HoverContainerState extends State<HoverContainer> {
return GestureDetector( return GestureDetector(
onTap: () { context.push('/user-guide/${widget.routePath}');}, onTap: () { context.push('/user-guide/${widget.routePath}');},
child: MouseRegion( child: MouseRegion(
onEnter: (_) => setState(() => isHovered = true), onEnter: (_) => setState(() => isHovered = true),
onExit: (_) => setState(() => isHovered = true), onExit: (_) => setState(() => isHovered = true),
child : Container( child : Container(
padding: EdgeInsets.only(top: 4, right: 4, left: 4, bottom: 6), padding: EdgeInsets.only(top: 4, right: 4, left: 4, bottom: 6),
height: screenHeight* 0.23 ,
width: screenWidth*0.30,
margin: EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: isHovered
? [
BoxShadow(
color: Colors.black.withValues(alpha:0.2),
blurRadius:2,
spreadRadius: 1,
offset: Offset(0, 4),
),
]
: [],
border: Border.all(
color: Color(0xFF7DAFBC),
width: 1.0,
),
),
alignment: Alignment.center,
// duration: Duration(milliseconds: 200),
child: LayoutBuilder(builder: (context, constraints){ width: screenWidth*0.30,
double containerWidth = constraints.maxWidth; margin: EdgeInsets.all(1),
// double containerHeight = constraints.maxHeight; decoration: BoxDecoration(
return Column( color: Colors.white,
mainAxisAlignment: MainAxisAlignment.center, borderRadius: BorderRadius.circular(10),
children: [ boxShadow: isHovered
IconifyIcon(icon: widget.iconName, ? [
color: Color((0xFF7DAFBC)), BoxShadow(
size: containerWidth * 0.25,), color: Colors.black.withOpacity(0.2),
// buildDynamicWidget(data['icon'], Color(0xFF7DAFBC)), blurRadius:2,
SizedBox(width: 10,height: containerWidth * 0.04,), // Space between icon and text spreadRadius: 1,
Container( offset: Offset(0, 4),
width: containerWidth* 0.85,
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 4),
margin: EdgeInsets.only(bottom: 3),
decoration: BoxDecoration(
color: Color(0xFF7DAFBC),
borderRadius: BorderRadius.circular(5),
border: Border.all(color: Color(0xFF7DAFBC)),
),
child: Text(
widget.title,
style: TextStyle(
color: Colors.white, // Text color
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
), ),
]
: [],
border: Border.all(
color: Color(0xFF7DAFBC),
width: 1.0
), ),
], ),
); alignment: Alignment.center,
},), // duration: Duration(milliseconds: 200),
child: LayoutBuilder(builder: (context, constraints){
double containerWidth = constraints.maxWidth;
double containerHeight = constraints.maxHeight;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconifyIcon(icon: widget.iconName,
color: Color((0xFF7DAFBC)),
size: containerHeight * 0.45,),
// buildDynamicWidget(data['icon'], Color(0xFF7DAFBC)),
SizedBox(width: 10,height: containerHeight * 0.04,), // Space between icon and text
Container(
width: containerWidth* 0.85,
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 4),
margin: EdgeInsets.only(bottom: 3),
decoration: BoxDecoration(
color: Color(0xFF7DAFBC),
borderRadius: BorderRadius.circular(5),
border: Border.all(color: Color(0xFF7DAFBC))
),
child: Text(
widget.title,
style: TextStyle(
color: Colors.white, // Text color
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
],
);
})
), ),
), ),