merge
This commit is contained in:
commit
cd1bb0fc8c
3
assets/icons/misc/Search.svg
Normal file
3
assets/icons/misc/Search.svg
Normal 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 |
3
assets/icons/uae_numbers/Filter.svg
Normal file
3
assets/icons/uae_numbers/Filter.svg
Normal 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 |
@ -12,5 +12,5 @@ abstract class MiscIconAssetPath {
|
||||
static const save = '$_basePath/save.png';
|
||||
static const group = '$_basePath/group.png';
|
||||
static const search = '$_basePath/search.png';
|
||||
|
||||
static const Search = '$_basePath/Search.svg';
|
||||
}
|
||||
|
||||
@ -6,5 +6,6 @@ abstract class UaeNumbersAssetPath {
|
||||
// static const bookmarksSelectedUae = '$_basePath/bookmarksSelectedUae.png';
|
||||
// static const shareUae = '$_basePath/share.png';
|
||||
static const share = '$_basePath/share.svg';
|
||||
static const filterUae = '$_basePath/filters.png';
|
||||
static const filterUae = '$_basePath/filters.png';
|
||||
static const filterCharts = '$_basePath/Filter.svg';
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"all_bookmarks":"كل العلامات المرجعية",
|
||||
"economy_title":" الاقتصاد",
|
||||
"economy_title":"اقتصاد",
|
||||
"social_title":"اجتماعي",
|
||||
"environment_title":"البيئة",
|
||||
"environment_title":"بيئة",
|
||||
"bookmarks": "الإشارات المرجعية",
|
||||
|
||||
"feedback_title": "تعليق",
|
||||
|
||||
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||
|
||||
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/domain/use_cases/language.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(
|
||||
hintText: "Search",
|
||||
hintStyle: TextStyle(color: Color(0xFF898C81)),
|
||||
|
||||
prefixIcon: Image(
|
||||
image: ExactAssetImage(MiscIconAssetPath.search),
|
||||
width: 24,
|
||||
height: 24,
|
||||
prefixIconConstraints: BoxConstraints(maxWidth: 42, maxHeight: 42),
|
||||
prefixIcon: Container(
|
||||
padding: EdgeInsets.only(right: 5),
|
||||
child: SvgPicture.asset(
|
||||
MiscIconAssetPath.Search,
|
||||
semanticsLabel: 'Search',
|
||||
),
|
||||
),
|
||||
|
||||
// prefixIcon: Image.asset(
|
||||
|
||||
@ -33,7 +33,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
|
||||
bool _obscureNewPassword = true;
|
||||
bool _obscureConfirmPassword = true;
|
||||
bool _isPasswordUpdated = false; // Variable to toggle UI
|
||||
|
||||
bool hasValidated = false;
|
||||
String? _oldPassword;
|
||||
String? _newPassword;
|
||||
String? _confirmPassword;
|
||||
@ -243,10 +243,12 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
|
||||
pathColorWhenOn: Colors.grey.shade300,
|
||||
pathColorWhenOff: Colors.grey.shade300,
|
||||
onTap: () {
|
||||
print('has validated $hasValidated');
|
||||
final formState = _formKey.currentState;
|
||||
ref.read(localeProvider.notifier).toggleLocale();
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
if (formState?.validate() == false) {
|
||||
if (hasValidated && formState?.validate() == false) {
|
||||
print('has validated $hasValidated');
|
||||
formState?.validate();
|
||||
}
|
||||
});
|
||||
@ -582,6 +584,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
|
||||
width: screenWidth / 1.1,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
hasValidated=true;
|
||||
});
|
||||
if ((_formKey.currentState?.validate() ?? false)) {
|
||||
await updatePassword(
|
||||
widget.userId,
|
||||
|
||||
@ -28,7 +28,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
final _confirmpasswordController = TextEditingController();
|
||||
|
||||
bool hasValidated = false;
|
||||
bool _obscurePassword = true;
|
||||
bool _obscureConfirmPassword = true;
|
||||
bool isChecked = false;
|
||||
@ -217,6 +217,9 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
|
||||
}
|
||||
|
||||
Future<void> _registerUser() async {
|
||||
setState(() {
|
||||
hasValidated = true;
|
||||
});
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
if (isChecked) {
|
||||
setState(() {
|
||||
@ -387,7 +390,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
|
||||
final formState = _formKey.currentState;
|
||||
ref.read(localeProvider.notifier).toggleLocale();
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
if (formState?.validate() == false) {
|
||||
if (hasValidated && formState?.validate() == false) {
|
||||
formState?.validate();
|
||||
}
|
||||
});
|
||||
@ -1111,11 +1114,11 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
|
||||
?.languageCode ==
|
||||
'ar'
|
||||
? 0
|
||||
: 30.0,
|
||||
: 40.0,
|
||||
right: registerLocale
|
||||
?.languageCode ==
|
||||
'ar'
|
||||
? 40
|
||||
? 45
|
||||
: 0.0,),
|
||||
child: Text(
|
||||
context.translate('Required', 'مطلوب'),
|
||||
|
||||
@ -1535,11 +1535,12 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
UaeNumbersAssetPath.filterUae,
|
||||
color: Color(0xFF8E8E8E), // Outline color
|
||||
width: 24, // Slightly larger
|
||||
height: 24,
|
||||
SvgPicture.asset(
|
||||
UaeNumbersAssetPath.filterCharts,
|
||||
semanticsLabel: 'Filter',
|
||||
colorFilter:ColorFilter.mode(Color(0xFF8E8E8E),BlendMode.srcIn),
|
||||
width: 25,
|
||||
height: 25,
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
@ -2265,12 +2266,11 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Image.asset(
|
||||
UaeNumbersAssetPath.filterUae,
|
||||
color: Colors
|
||||
.white, // Set color to white
|
||||
width: 21,
|
||||
height: 21,
|
||||
SvgPicture.asset(
|
||||
UaeNumbersAssetPath.filterCharts,
|
||||
semanticsLabel: 'Filter',
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -37,7 +37,7 @@ class ProfileScreen extends ConsumerStatefulWidget {
|
||||
class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
final _pb = PocketBase(apiUrl);
|
||||
// final _pb = PocketBase('http://127.0.0.1:8090');
|
||||
|
||||
bool hasValidated = false;
|
||||
// Add focus nodes and hint states
|
||||
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
|
||||
final List<bool> _showHints = [
|
||||
@ -457,6 +457,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final profileLocale = ref.watch(localeProvider);
|
||||
return PopScope(
|
||||
canPop: false, // Allow back navigation only if not login screen
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
@ -489,7 +490,13 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
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 && formState?.validate() == false) {
|
||||
formState?.validate();
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -785,7 +792,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
labelText: 'Select',
|
||||
labelText: context.translate('Select',' اختيار')
|
||||
),
|
||||
icon: Icon(Icons.keyboard_arrow_down_sharp,
|
||||
color:
|
||||
@ -911,7 +918,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
padding: EdgeInsets.only(left: 10.0, right: profileLocale
|
||||
?.languageCode ==
|
||||
'ar'
|
||||
? 15
|
||||
: 0.0,),
|
||||
child: Text(
|
||||
context.translate('Required', 'مطلوب'),
|
||||
style: TextStyle(
|
||||
@ -948,6 +959,9 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
// ElevatedButton.icon(
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
hasValidated = true;
|
||||
});
|
||||
if ((_formKey.currentState?.validate() ?? false) &&
|
||||
(isChecked)) {
|
||||
_formKey.currentState?.save();
|
||||
|
||||
@ -45,7 +45,7 @@ class ThemedFormField extends HookWidget {
|
||||
final inputDecoration = InputDecoration(
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 14),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 15),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
|
||||
@ -127,6 +127,7 @@ class LoginRoute extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final hasValidated = useState(false);
|
||||
final locale = ref.watch(localeProvider);
|
||||
final emailCtl = useTextEditingController();
|
||||
final pwCtl = useTextEditingController();
|
||||
@ -272,6 +273,7 @@ class LoginRoute extends HookConsumerWidget {
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
hasValidated.value=true;
|
||||
final isValid = formKey.currentState!.validate();
|
||||
if (!isValid) return;
|
||||
final session = await context.loaderWithErrorDialog(
|
||||
@ -680,7 +682,7 @@ class LoginRoute extends HookConsumerWidget {
|
||||
final formState = formKey.currentState;
|
||||
ref.read(localeProvider.notifier).toggleLocale();
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
if (formState?.validate() == false) {
|
||||
if (hasValidated.value && formState?.validate() == false) {
|
||||
formState?.validate();
|
||||
}
|
||||
});
|
||||
|
||||
@ -25,19 +25,11 @@ class _BookMarkState extends ConsumerState<BookMark> {
|
||||
final _pb = PocketBase(apiUrl);
|
||||
List<Map<String, dynamic>> dataList = [];
|
||||
bool isLoading = true;
|
||||
|
||||
Map<String, Map<String, dynamic>> groupedMap = {};
|
||||
int? expandedIndex = 0;
|
||||
// Current selected tab index
|
||||
int selectedTabIndex = 0;
|
||||
|
||||
// Tab categories
|
||||
// final List<String> tabs = [
|
||||
// 'All Bookmarks',
|
||||
// 'Economy',
|
||||
// 'Social',
|
||||
// 'Environment',
|
||||
// ];
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -106,8 +98,36 @@ class _BookMarkState extends ConsumerState<BookMark> {
|
||||
'id': item['id'],
|
||||
};
|
||||
}).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) {
|
||||
@ -268,11 +288,11 @@ class _BookMarkState extends ConsumerState<BookMark> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final List<String> tabs = [
|
||||
AppLocalizations.of(context)!.all_bookmarks,
|
||||
AppLocalizations.of(context)!.economy_title,
|
||||
AppLocalizations.of(context)!.social_title,
|
||||
AppLocalizations.of(context)!.environment_title,
|
||||
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)},
|
||||
];
|
||||
|
||||
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>> filteredBookmarks = dataList
|
||||
.where((bookmark) =>
|
||||
bookmark['main_topic'].toString().trim().toLowerCase() == tabs[selectedTabIndex].toString().trim().toLowerCase())
|
||||
.toList();
|
||||
.where((bookmark) {
|
||||
String mainTopic = bookmark['main_topic'].toString().trim().toLowerCase();
|
||||
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(
|
||||
title: Text(AppLocalizations.of(context)!.bookmarks,),
|
||||
body: Column(
|
||||
@ -302,23 +330,68 @@ class _BookMarkState extends ConsumerState<BookMark> {
|
||||
),
|
||||
Expanded(
|
||||
child: selectedTabIndex == 0
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 10.0,
|
||||
mainAxisSpacing: 10.0,
|
||||
mainAxisExtent: 100,
|
||||
),
|
||||
itemCount: bookmarks.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildBox(bookmarks[index], context);
|
||||
},
|
||||
? (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,
|
||||
),
|
||||
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(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@ -336,20 +409,47 @@ class _BookMarkState extends ConsumerState<BookMark> {
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 10.0,
|
||||
mainAxisSpacing: 10.0,
|
||||
mainAxisExtent: 100,
|
||||
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,
|
||||
),
|
||||
),
|
||||
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
|
||||
|
||||
debugPrint("Box clicked: ${data['title']}");
|
||||
context.go(
|
||||
context.push(
|
||||
'/chartScreen/$data_set?bgColor=$hexColor&mainTopic=$encodedMainTopic&title=$encodedTitle');
|
||||
},
|
||||
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 {
|
||||
final List<String> tabs;
|
||||
final List<Map<String, dynamic>> tabs;
|
||||
final int selectedIndex;
|
||||
final ValueChanged<int> onTabSelected;
|
||||
|
||||
@ -481,7 +681,7 @@ class TabBarHeader extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: tabs.asMap().entries.map((entry) {
|
||||
int index = entry.key;
|
||||
String text = entry.value;
|
||||
String text = entry.value['title'];
|
||||
return Row(
|
||||
children: [
|
||||
TextButton(
|
||||
@ -490,7 +690,7 @@ class TabBarHeader extends StatelessWidget {
|
||||
foregroundColor:
|
||||
MaterialStateProperty.resolveWith((states) {
|
||||
return selectedIndex == index
|
||||
? Colors.black
|
||||
? entry.value['color']
|
||||
: Colors.grey[700];
|
||||
}),
|
||||
),
|
||||
@ -506,7 +706,7 @@ class TabBarHeader extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget buildDivider() {
|
||||
return Container(
|
||||
return SizedBox(
|
||||
height: 20,
|
||||
child: const VerticalDivider(
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
@ -343,11 +344,14 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search",
|
||||
hintStyle: TextStyle(color: Color(0xFF898C81)),
|
||||
prefixIcon: Image(
|
||||
image: ExactAssetImage(MiscIconAssetPath.search),
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Color(0xFFAA8E83)),
|
||||
prefixIconConstraints: BoxConstraints(maxWidth: 42, maxHeight: 42),
|
||||
prefixIcon: Container(
|
||||
padding: EdgeInsets.only(right: 5),
|
||||
child: SvgPicture.asset(
|
||||
MiscIconAssetPath.Search,
|
||||
semanticsLabel: 'Search',
|
||||
),
|
||||
),
|
||||
|
||||
// prefixIcon: Image.asset(
|
||||
// MiscIconAssetPath.search,
|
||||
|
||||
@ -7,7 +7,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
|
||||
class Userguide extends StatefulWidget {
|
||||
const Userguide({super.key});
|
||||
Userguide({super.key});
|
||||
|
||||
@override
|
||||
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': 'لأسئلة الشائعة'},
|
||||
];
|
||||
|
||||
@override
|
||||
Widget buildDynamicWidget(dynamic icons, Color color) {
|
||||
if (icons is IconData) {
|
||||
return Icon(
|
||||
@ -46,41 +47,41 @@ class _UserguideState extends State<Userguide> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
if (didPop) return;
|
||||
context.go('/myhomepage');
|
||||
},
|
||||
child: BaseScaffold(
|
||||
showDivider: true,
|
||||
bottomColor: Colors.white,
|
||||
dividerColor: Colors.grey[300],
|
||||
appbarColor: Colors.white,
|
||||
title: Text(AppLocalizations.of(context)!.guide_title) ,
|
||||
body: Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16 , vertical: 20),
|
||||
child: GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2, // Two columns
|
||||
crossAxisSpacing: 10.0,
|
||||
mainAxisSpacing: 10.0,
|
||||
mainAxisExtent:MediaQuery.of(context).size.height* 0.15 ,
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
if (didPop) return;
|
||||
context.go('/myhomepage');
|
||||
},
|
||||
child: BaseScaffold(
|
||||
showDivider: true,
|
||||
bottomColor: Colors.white,
|
||||
dividerColor: Colors.grey[300],
|
||||
appbarColor: Colors.white,
|
||||
title: Text(AppLocalizations.of(context)!.guide_title) ,
|
||||
body: Container(
|
||||
color: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16 , vertical: 20),
|
||||
child: GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 10.0,
|
||||
mainAxisSpacing: 10.0,
|
||||
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(
|
||||
onTap: () { context.push('/user-guide/${widget.routePath}');},
|
||||
child: MouseRegion(
|
||||
onEnter: (_) => setState(() => isHovered = true),
|
||||
onExit: (_) => setState(() => isHovered = true),
|
||||
child : Container(
|
||||
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),
|
||||
onEnter: (_) => setState(() => isHovered = true),
|
||||
onExit: (_) => setState(() => isHovered = true),
|
||||
child : Container(
|
||||
padding: EdgeInsets.only(top: 4, right: 4, left: 4, bottom: 6),
|
||||
|
||||
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: containerWidth * 0.25,),
|
||||
// buildDynamicWidget(data['icon'], Color(0xFF7DAFBC)),
|
||||
SizedBox(width: 10,height: containerWidth * 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,
|
||||
width: screenWidth*0.30,
|
||||
margin: EdgeInsets.all(1),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: isHovered
|
||||
? [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(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){
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
})
|
||||
|
||||
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user