1155 lines
42 KiB
Dart
Executable File
1155 lines
42 KiB
Dart
Executable File
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:dio/dio.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:uae_stat/config/theme/service.dart';
|
|
import 'package:uae_stat/infrastructure/services/local_bookmarks_service.dart';
|
|
import 'package:uae_stat/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/lib/core/routing/app_router.dart';
|
|
import 'package:uae_stat/config/connectivity_provider.dart';
|
|
import 'package:uae_stat/config/theme/theme_provider.dart';
|
|
import 'package:uae_stat/config/toggle_lang_service.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/l10n/app_localizations.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});
|
|
|
|
@override
|
|
ConsumerState<BookMark> createState() => _BookMarkState();
|
|
}
|
|
|
|
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;
|
|
late UserService _userService;
|
|
late ThemeMode currentTheme;
|
|
|
|
List<dynamic> homePageData = [];
|
|
List<dynamic> filteredData = [];
|
|
List<Map<String, dynamic>> sortedList = [];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_userService = UserService();
|
|
final locale = ref.read(localeProvider);
|
|
currentTheme = ref.read(themeProvider);
|
|
// final isDark = currentTheme == ThemeMode.dark ||
|
|
// (currentTheme == ThemeMode.system &&
|
|
// MediaQuery.of(context).platformBrightness == Brightness.dark);
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
final isDark = currentTheme == ThemeMode.dark ||
|
|
(currentTheme == ThemeMode.system &&
|
|
MediaQuery.of(context).platformBrightness == Brightness.dark);
|
|
|
|
final themeMode = (isDark ? 'dark' : 'light');
|
|
fetchData(locale?.languageCode ?? 'en', themeMode);
|
|
fetchBookmarks(locale?.languageCode ?? 'en', themeMode);
|
|
});
|
|
}
|
|
|
|
Future<void> fetchData(locale, themeMode) async {
|
|
const baseUrl = '${apiUrl}api/getUAENumbersData';
|
|
try {
|
|
final response = await http.get(
|
|
Uri.parse(baseUrl + '?language=$locale&color_mode=$themeMode'),
|
|
headers: {'APP_SIGNATURE': 'fcsc.gov.ae.X7pL9qZm2A'});
|
|
if (response.statusCode == 200) {
|
|
setState(() {
|
|
homePageData = (json.decode(response.body) as List)
|
|
.map((e) => Map<String, dynamic>.from(e))
|
|
.toList();
|
|
filteredData = List.from(homePageData);
|
|
isLoading = false;
|
|
});
|
|
} else {
|
|
throw Exception('Failed to load data');
|
|
}
|
|
} catch (e) {
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
String colorToHex(Color color) {
|
|
return '0xFF${color.red.toRadixString(16).padLeft(2, '0').toUpperCase()}'
|
|
'${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) {
|
|
return const Color(0xFF80A8CD); // Default color
|
|
}
|
|
|
|
try {
|
|
return Color(int.parse(colorString.replaceFirst('#', '0xFF')));
|
|
} catch (e) {
|
|
return const Color(0xFF80A8CD); // Fallback color
|
|
}
|
|
}
|
|
|
|
Future<void> fetchBookmarks(locale, themeMode) async {
|
|
try {
|
|
final fetchedData = await LocalBookmarksService.getAll();
|
|
setState(() {
|
|
dataList = fetchedData.map((item) {
|
|
return {
|
|
'main_topic': item['main_topic'] ?? item['mainTopic'] ?? '',
|
|
'title': item['data_set_tile_heading'] ?? item['title'] ?? '',
|
|
'subtitle': item['sub_topic'] ?? '',
|
|
'value': item['value'] ?? '',
|
|
'value_source': item['value_source'] ?? '',
|
|
'data_set': item['data_set'] ?? item['dataset'] ?? '',
|
|
'valueColor': _parseColor(item['color_pattern']?.toString()),
|
|
'isBookmark': true,
|
|
'id': item['id'],
|
|
};
|
|
}).toList();
|
|
});
|
|
|
|
if (dataList.isNotEmpty) {
|
|
{
|
|
// grouped map build (unchanged structure)
|
|
|
|
List<Map<String, dynamic>> transformAndStore(
|
|
List<Map<String, dynamic>> fetchedData) {
|
|
// Define the required order
|
|
List<String> order = [
|
|
context.translate('ECONOMY', 'الاقتصاد'),
|
|
context.translate('SOCIAL', 'الاجتماعي'),
|
|
context.translate('ENVIRONMENT', 'البيئة')
|
|
];
|
|
|
|
// Create a list to store sorted data
|
|
// List<Map<String, dynamic>> sortedList = [];
|
|
|
|
// Group data based on categories
|
|
Map<String, List<Map<String, dynamic>>> groupedData = {
|
|
context.translate('ECONOMY', 'الاقتصاد'): [],
|
|
context.translate('SOCIAL', 'الاجتماعي'): [],
|
|
context.translate('ENVIRONMENT', 'البيئة'): []
|
|
};
|
|
|
|
// Categorize data
|
|
for (var item in fetchedData) {
|
|
String mainTopic = item["main_topic"]?.toString() ?? "";
|
|
if (groupedData.containsKey(mainTopic)) {
|
|
groupedData[mainTopic]!.add(item);
|
|
}
|
|
}
|
|
|
|
// Store sorted data in the correct order
|
|
for (String topic in order) {
|
|
if (groupedData.containsKey(topic)) {
|
|
sortedList.addAll(groupedData[topic]!);
|
|
}
|
|
}
|
|
|
|
// Store the sorted list (replace this with your storage method)
|
|
return sortedList;
|
|
}
|
|
|
|
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) {
|
|
setState(() {
|
|
dataList = []; // Clear the list
|
|
});
|
|
} finally {
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
Future<void> removeBookmark(bookmarkId) async {
|
|
try {
|
|
setState(() {
|
|
isLoading = true;
|
|
});
|
|
// final adminAuth = await _pb.admins
|
|
// .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
|
|
|
|
// final auth = ref.watch(authProvider);
|
|
|
|
// final adminAuth = await pb.admins.authWithPassword(
|
|
// auth.email,
|
|
// auth.password,
|
|
// );
|
|
//
|
|
//
|
|
|
|
await LocalBookmarksService.remove(bookmarkId!);
|
|
|
|
// currentTheme = ref.read(themeProvider);
|
|
// print('123456789');
|
|
// print(currentTheme);
|
|
final isDark = currentTheme == ThemeMode.dark ||
|
|
(currentTheme == ThemeMode.system &&
|
|
MediaQuery.of(context).platformBrightness == Brightness.dark);
|
|
|
|
final themeMode = (isDark ? 'dark' : 'light');
|
|
|
|
final locale = ref.read(localeProvider);
|
|
|
|
fetchBookmarks(locale?.languageCode ?? 'en', themeMode);
|
|
// ToastUtil.showSuccessToast("Removed from Bookmark.");
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
AppLocalizations.of(context)!.removed_from_Bookmark,
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
)),
|
|
),
|
|
duration: Duration(seconds: 2),
|
|
),
|
|
);
|
|
|
|
} catch (e) {
|
|
SnackBar(
|
|
content: Text(
|
|
context.translate(
|
|
'Unable to remove from bookmarks. Please try again',
|
|
'تعذر الإزالة من الإشارات المرجعية. يرجى المحاولة مرة أخرى.',
|
|
),
|
|
style: TextStyle(
|
|
color: Color(0xFFEB5F24),
|
|
fontWeight: FontWeight.w600,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
),
|
|
),
|
|
backgroundColor: Color(0xFFD6E9C6),
|
|
duration: Duration(seconds: 2),
|
|
);
|
|
} finally {
|
|
setState(() {
|
|
isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
void showRemoveBookmarkDialog(id) {
|
|
double myheight = MediaQuery.of(context).size.height;
|
|
showDialog(
|
|
context: context,
|
|
barrierDismissible: false, // User must tap button to dismiss dialog
|
|
builder: (context) => AlertDialog(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(5.0), // Rounded corners
|
|
),
|
|
contentPadding: EdgeInsets.zero,
|
|
content: Stack(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(10.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SizedBox(
|
|
height: myheight / 30,
|
|
),
|
|
Text(
|
|
context.translate(
|
|
'Are you sure you want to remove this bookmark?',
|
|
'هل أنت متأكد أنك تريد إزالة هذه الإشارة المرجعية؟'),
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
fontSize: 18,
|
|
color: Color(0xFF898C81),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
actions: [
|
|
SizedBox(height: 20),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
SizedBox(
|
|
width: 100, // Set the desired width
|
|
child: TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
style: TextButton.styleFrom(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(
|
|
10.0), // Adjust the radius as needed
|
|
),
|
|
side: BorderSide(
|
|
color: Color(0xFFB68A34), // Set the outline color
|
|
width: 1, // Set the border width
|
|
),
|
|
),
|
|
child: Text(
|
|
context.translate('No', 'لا'),
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
color: Color(0xFFB68A34),
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: 100, // Set the desired width
|
|
child: TextButton(
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
removeBookmark(id);
|
|
},
|
|
style: TextButton.styleFrom(
|
|
backgroundColor: Color(0xFFB68A34), // Set background color
|
|
foregroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius:
|
|
BorderRadius.circular(10.0), // Set text color
|
|
),
|
|
),
|
|
child: Text(
|
|
context.translate('Yes', 'نعم'),
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 16,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
|
|
if (hasInternet.value == false) {
|
|
context.push('/internetcheck');
|
|
}
|
|
});
|
|
|
|
ref.listen<Locale?>(localeProvider, (previous, next) async {
|
|
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
|
|
setState(() {
|
|
isLoading = true;
|
|
});
|
|
await _userService.updateLanguage(localeCode, ref);
|
|
|
|
final currentTheme = ref.read(themeProvider);
|
|
final isDark = currentTheme == ThemeMode.dark ||
|
|
(currentTheme == ThemeMode.system &&
|
|
MediaQuery.of(context).platformBrightness == Brightness.dark);
|
|
|
|
final themeString = isDark ? 'dark' : 'light';
|
|
|
|
fetchBookmarks(localeCode, themeString);
|
|
});
|
|
|
|
ref.listen<ThemeMode>(themeProvider, (previous, next) async {
|
|
final localeCode = ref.watch(localeProvider)?.languageCode ?? 'en';
|
|
|
|
// Default to 'en' if null
|
|
setState(() {
|
|
isLoading = true;
|
|
});
|
|
|
|
final currentTheme = ref.read(themeProvider);
|
|
final isDark = currentTheme == ThemeMode.dark ||
|
|
(currentTheme == ThemeMode.system &&
|
|
MediaQuery.of(context).platformBrightness == Brightness.dark);
|
|
|
|
final themeString = isDark ? 'dark' : 'light';
|
|
fetchBookmarks(localeCode, themeString);
|
|
});
|
|
|
|
final isDarkTheme = ref.watch(themeProvider) == ThemeMode.dark ||
|
|
(ref.watch(themeProvider) == ThemeMode.system &&
|
|
MediaQuery.of(context).platformBrightness == Brightness.dark);
|
|
|
|
final List<Map<String, dynamic>> tabs = [
|
|
{
|
|
'title': AppLocalizations.of(context)!.all_bookmarks,
|
|
'titleUpper': AppLocalizations.of(context)!.all_bookmarks,
|
|
'color': isDarkTheme ? Colors.white : Color(0xFFB68A34),
|
|
// 'color': isDarkTheme ? Colors.white : Colors.black,
|
|
},
|
|
{
|
|
'title': AppLocalizations.of(context)!.economy_title,
|
|
'titleUpper': AppLocalizations.of(context)!.economy_title_upper,
|
|
'color': isDarkTheme ? Color(0xFF89AFD8) : Color(0xFF89AFD8)
|
|
},
|
|
{
|
|
'title': AppLocalizations.of(context)!.social_title,
|
|
'titleUpper': AppLocalizations.of(context)!.social_title_upper,
|
|
'color': isDarkTheme ? Color(0xFF675863) : Color(0xFF675863)
|
|
},
|
|
{
|
|
'title': AppLocalizations.of(context)!.environment_title,
|
|
'titleUpper': AppLocalizations.of(context)!.environment_title_upper,
|
|
'color': isDarkTheme ? Color(0xFFB3CF99) : Color(0xFFB3CF99)
|
|
},
|
|
];
|
|
|
|
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();
|
|
|
|
// 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();
|
|
return PopScope(
|
|
canPop: false,
|
|
onPopInvokedWithResult: (didPop, result) {
|
|
if (didPop) return;
|
|
context.go('/myhomepage');
|
|
},
|
|
child: BaseScaffold(
|
|
backgroundColor: isDarkTheme ? Colors.black : Colors.white,
|
|
appbarColor: isDarkTheme ? Colors.black : Colors.white,
|
|
title: Text(
|
|
AppLocalizations.of(context)!.bookmarks,
|
|
style: TextStyle(
|
|
color: isDarkTheme ? Colors.white : Colors.black,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
)),
|
|
),
|
|
body: isLoading
|
|
? Container(
|
|
color: isDarkTheme ? Colors.black : Colors.white,
|
|
// color: Color(0x98FFFCE5), // Semi-transparent background
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Container(
|
|
margin: EdgeInsets.symmetric(
|
|
horizontal: 40), // Left & Right space
|
|
child: LinearProgressIndicator(
|
|
minHeight: 5, // Adjust thickness
|
|
backgroundColor:
|
|
Colors.grey[100], // Optional: Background color
|
|
valueColor: AlwaysStoppedAnimation<Color>(
|
|
Color(0xFFAA8E83)), // Loader color
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
: Column(
|
|
children: [
|
|
TabBarHeader(
|
|
tabs: tabs,
|
|
selectedIndex: selectedTabIndex,
|
|
onTabSelected: (index) {
|
|
setState(() {
|
|
selectedTabIndex = index;
|
|
});
|
|
},
|
|
isDarkTheme: isDarkTheme),
|
|
Expanded(
|
|
child: selectedTabIndex == 0
|
|
? (bookmarks.isNotEmpty
|
|
? SingleChildScrollView(
|
|
child: Container(
|
|
padding: const EdgeInsets.all(13.0),
|
|
child: Column(
|
|
children: List.generate(
|
|
transformedList.length, (i) {
|
|
final mainTopic = transformedList[i];
|
|
final list = List.from(
|
|
mainTopic['SubTopic'] ?? []);
|
|
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: isDarkTheme
|
|
? Colors.black
|
|
: Colors.white,
|
|
// borderRadius: BorderRadius.all(Radius.circular(20))
|
|
),
|
|
padding: const EdgeInsets.symmetric(
|
|
vertical: 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'],
|
|
isDarkTheme);
|
|
},
|
|
),
|
|
),
|
|
filteredBookmarks: List.from(
|
|
mainTopic['SubTopic'] ?? []),
|
|
titleBackgroundColor:
|
|
mainTopic['valueColor'],
|
|
// Ensure it's a new list
|
|
isDarkTheme: isDarkTheme,
|
|
);
|
|
}),
|
|
),
|
|
),
|
|
)
|
|
: 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(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
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(
|
|
context.translate('No BookMark Added',
|
|
'لم يتم إضافة أي علامة مرجعية'),
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
color: Colors.grey,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Container(
|
|
margin: const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
color: tabs[selectedTabIndex]
|
|
['color'],
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(20),
|
|
topRight: Radius.circular(20))
|
|
|
|
// borderRadius: BorderRadius.all(
|
|
// Radius.circular(35))
|
|
|
|
),
|
|
padding: const EdgeInsets.only(
|
|
left: 16,
|
|
bottom: 5,
|
|
top: 5,
|
|
right: 10),
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
tabs[selectedTabIndex]
|
|
['titleUpper'],
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
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,
|
|
isDarkTheme);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildBox(
|
|
Map<String, dynamic> data, BuildContext context, bool isDarkTheme) {
|
|
// Color borderColor = data['valueColor'];
|
|
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(colorPattern); // Get hex string
|
|
|
|
context.push(
|
|
AppRoutes.datasetDetailPath(
|
|
dataSet: data_set,
|
|
bgColor: hexColor,
|
|
mainTopic: encodedMainTopic,
|
|
title: encodedTitle,
|
|
kpi: data_set,
|
|
),
|
|
);
|
|
},
|
|
child: Container(
|
|
width: MediaQuery.of(context).size.width * 0.4,
|
|
height: 100,
|
|
padding: const EdgeInsets.all(8.0),
|
|
decoration: BoxDecoration(
|
|
color: isDarkTheme ? Colors.black : Colors.white,
|
|
borderRadius: BorderRadius.circular(10),
|
|
border: Border.all(color: data['valueColor']),
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
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: TextStyle(
|
|
fontWeight: FontWeight.w500,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
color: isDarkTheme ? Colors.white : null,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
maxLines: 1,
|
|
),
|
|
),
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
showRemoveBookmarkDialog(data['id']);
|
|
// removeBookmark(data['id']);
|
|
},
|
|
child: SvgPicture.asset(
|
|
BookmarkAssetPath.delete,
|
|
semanticsLabel: 'share',
|
|
width: 23,
|
|
height: 20,
|
|
)),
|
|
|
|
// GestureDetector(
|
|
// onTap: () {
|
|
// debugPrint("Icon clicked in: ${data['title']}");
|
|
// // showRemoveBookmarkDialog(data['id']);
|
|
// },
|
|
// child: const Icon(
|
|
// Icons.bookmarks_rounded,
|
|
// color: Colors.black,
|
|
// size: 20,
|
|
// ),
|
|
// ),
|
|
],
|
|
),
|
|
Text(
|
|
data['value_source'] ?? '',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
maxLines: 1,
|
|
),
|
|
Text(
|
|
data['value'] ?? '',
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
fontSize: 28,
|
|
fontWeight: FontWeight.bold,
|
|
color: data['valueColor'],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildBoxes(
|
|
Map<String, dynamic> data,
|
|
BuildContext context,
|
|
Color styleColor,
|
|
bool isDarkTheme,
|
|
) {
|
|
// Color borderColor = data['valueColor'];
|
|
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(
|
|
AppRoutes.datasetDetailPath(
|
|
dataSet: data_set,
|
|
bgColor: hexColor,
|
|
mainTopic: encodedMainTopic,
|
|
title: encodedTitle,
|
|
kpi: data_set,
|
|
),
|
|
);
|
|
|
|
// String hexColor = colorToHex(colorPattern); // Get hex string
|
|
// print(hexColor); // Prints: 0xFFAA8E83
|
|
|
|
// debugPrint("Box clicked: ${data['title']}");
|
|
context.push(
|
|
AppRoutes.datasetDetailPath(
|
|
dataSet: data_set,
|
|
bgColor: hexColor,
|
|
mainTopic: encodedMainTopic,
|
|
title: encodedTitle,
|
|
kpi: data_set,
|
|
),
|
|
);
|
|
},
|
|
child: Container(
|
|
width: MediaQuery.of(context).size.width * 0.4,
|
|
height: 100,
|
|
padding: const EdgeInsets.all(8.0),
|
|
decoration: BoxDecoration(
|
|
color: isDarkTheme ? Colors.black : 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: TextStyle(
|
|
fontWeight: FontWeight.w500,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
color: isDarkTheme ? Colors.white : null,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
maxLines: 1,
|
|
),
|
|
),
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
debugPrint("Icon clicked in: ${data['title']}");
|
|
showRemoveBookmarkDialog(data['id']);
|
|
},
|
|
child: SvgPicture.asset(
|
|
BookmarkAssetPath.delete,
|
|
semanticsLabel: 'share',
|
|
width: 23,
|
|
height: 20,
|
|
)),
|
|
],
|
|
),
|
|
Text(
|
|
data['value_source'] ?? '',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey,
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
maxLines: 1,
|
|
),
|
|
Text(
|
|
data['value'] ?? '',
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
fontSize: 28,
|
|
fontWeight: FontWeight.bold,
|
|
color: styleColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class TabBarHeader extends StatelessWidget {
|
|
final List<Map<String, dynamic>> tabs;
|
|
final int selectedIndex;
|
|
final ValueChanged<int> onTabSelected;
|
|
bool isDarkTheme;
|
|
|
|
TabBarHeader(
|
|
{required this.tabs,
|
|
required this.selectedIndex,
|
|
required this.onTabSelected,
|
|
required this.isDarkTheme});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
color: isDarkTheme ? Colors.black : Colors.white,
|
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: tabs.asMap().entries.map((entry) {
|
|
int index = entry.key;
|
|
String text = entry.value['title'];
|
|
return Row(
|
|
children: [
|
|
TextButton(
|
|
onPressed: () => onTabSelected(index),
|
|
style: ButtonStyle(
|
|
foregroundColor:
|
|
MaterialStateProperty.resolveWith((states) {
|
|
return selectedIndex == index
|
|
? entry.value['color']
|
|
: Color(0xFF898C81);
|
|
}),
|
|
),
|
|
child: Text(
|
|
text,
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (index < tabs.length - 1) buildDivider(),
|
|
],
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget buildDivider() {
|
|
return SizedBox(
|
|
height: 20,
|
|
child: const VerticalDivider(
|
|
color: Colors.grey,
|
|
thickness: 1,
|
|
width: 16,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
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;
|
|
final bool isDarkTheme;
|
|
|
|
const CustomExpandableTile({
|
|
required this.title,
|
|
required this.titleBackgroundColor,
|
|
required this.filteredBookmarks,
|
|
required this.index,
|
|
required this.isExpanded,
|
|
required this.onTap,
|
|
required this.childWidget,
|
|
required this.isDarkTheme,
|
|
});
|
|
|
|
@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: widget.isDarkTheme
|
|
? Colors.black
|
|
: Colors
|
|
.white, // Ensuring the background outside the rounded container is white
|
|
),
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: widget.titleBackgroundColor,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(20),
|
|
topRight: Radius.circular(20))
|
|
// borderRadius: BorderRadius.all(Radius.circular(35))
|
|
),
|
|
padding: const EdgeInsets.only(
|
|
left: 16, bottom: 5, top: 5, right: 10),
|
|
child: Row(
|
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Spacer(),
|
|
Text(
|
|
widget.title,
|
|
style: TextStyle(
|
|
fontFamily: context.translate(
|
|
'Roboto',
|
|
'NotoKufi',
|
|
),
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 20,
|
|
),
|
|
),
|
|
Spacer(),
|
|
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: widget.isDarkTheme ? Colors.black : 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,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|