123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- import 'dart:convert';
- import 'package:flutter/foundation.dart';
- import 'package:flutter/material.dart';
- import 'package:http/http.dart' as http;
- import 'package:shared_preferences/shared_preferences.dart';
- import 'custom_info_card.dart';
- import 'favorites_page.dart'; // Nuevo import
-
- void main() => runApp(const MyApp());
-
- class MyApp extends StatelessWidget {
- const MyApp({super.key});
-
- static const Color primaryColor = Color.fromARGB(255, 254, 100, 91);
- static const Color secondaryColor = Colors.orange;
-
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Custom Info Cards',
- theme: ThemeData(
- primaryColor: primaryColor,
- appBarTheme: const AppBarTheme(
- backgroundColor: primaryColor,
- elevation: 0,
- ),
- ),
- home: const HomePage(),
- debugShowCheckedModeBanner: false,
- );
- }
- }
-
- class HomePage extends StatefulWidget {
- const HomePage({super.key});
-
- @override
- State<HomePage> createState() => _HomePageState();
- }
-
- class _HomePageState extends State<HomePage> {
- List<Map<String, dynamic>> infoCards = [];
- List<Map<String, dynamic>> favoriteCards = [];
- int _currentIndex = 0;
- static const String googleSheetUrl = 'https://script.google.com/macros/s/AKfycbw1htmk7rlwLMOkOrpZ9ED-7ErWgMlYNtLKxoQ9QO-FopqTAhJuQkR7Gs1LxTJakbMT/exec';
-
- @override
- void initState() {
- super.initState();
- _loadInfoCards();
- }
-
- Future<void> _loadInfoCards() async {
- final prefs = await SharedPreferences.getInstance();
- String? savedData = prefs.getString('infoCardsData');
-
- setState(() {
- infoCards = savedData != null
- ? List<Map<String, dynamic>>.from(json.decode(savedData))
- : _defaultInfoCards();
- });
-
- await _fetchUpdatedData();
- }
-
- Future<void> _loadFavorites() async {
- final prefs = await SharedPreferences.getInstance();
- final allKeys = prefs.getKeys().where((key) => key.startsWith('fav_')).toList();
-
- setState(() {
- favoriteCards = infoCards.where((card) {
- return allKeys.contains('fav_${card['title']}') &&
- (prefs.getBool('fav_${card['title']}') ?? false);
- }).toList();
- });
- }
-
- List<Map<String, dynamic>> _defaultInfoCards() {
- return [
- {
- 'image': 'assets/icons/icono1.jpg',
- 'title': 'Tutorias de programación',
- 'subtitle': '8:00am a 11:30am En biblioteca Lázaro',
- 'texto': 'Detalles completos sobre tutorías...',
- },
- ];
- }
-
- Future<void> _fetchUpdatedData() async {
- try {
- final response = await http.get(Uri.parse(googleSheetUrl));
- if (response.statusCode == 200) {
- final List<Map<String, dynamic>> newData = List<Map<String, dynamic>>.from(json.decode(response.body));
-
- if (json.encode(newData) != json.encode(infoCards)) {
- setState(() => infoCards = newData);
- final prefs = await SharedPreferences.getInstance();
- await prefs.setString('infoCardsData', json.encode(newData));
- }
- }
- } catch (e) {
- if (kDebugMode) print('Error fetching data: $e');
- }
- }
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: _currentIndex == 0
- ? AppBar(
- flexibleSpace: Padding(
- padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top - 20),
- child: Image.asset(
- 'assets/header_image.png',
- fit: BoxFit.cover,
- ),
- ),
- toolbarHeight: MediaQuery.of(context).size.height * 0.19,
- )
- : null,
- body: Container(
- decoration: const BoxDecoration(
- gradient: LinearGradient(
- colors: [MyApp.primaryColor, MyApp.secondaryColor],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- ),
- child: _currentIndex == 0
- ? RefreshIndicator(
- onRefresh: _fetchUpdatedData,
- child: _buildMainContent(),
- )
- : FavoritesPage(favoriteCards: favoriteCards),
- ),
- bottomNavigationBar: BottomNavigationBar(
- currentIndex: _currentIndex,
- selectedItemColor: Colors.white,
- unselectedItemColor: Colors.white70,
- backgroundColor: MyApp.primaryColor,
- items: const [
- BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Inicio'),
- BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Favoritos'),
- ],
- onTap: (index) {
- if (index == 1) _loadFavorites();
- setState(() => _currentIndex = index);
- },
- ),
- );
- }
-
- Widget _buildMainContent() {
- return SafeArea(
- child: Column(
- children: [
- Expanded(
- child: ListView.builder(
- itemCount: infoCards.isEmpty ? 1 : infoCards.length,
- itemBuilder: (context, index) {
- if (infoCards.isEmpty) {
- return _buildErrorWidget();
- }
- final card = infoCards[index];
- return CustomInfoCard(
- imagePath: "assets/icons/${card['image']}",
- title: card['title'],
- subtitle: card['subtitle'],
- texto: card['texto'],
- );
- },
- ),
- ),
- ],
- ),
- );
- }
-
- Widget _buildErrorWidget() {
- return Card(
- margin: const EdgeInsets.all(16),
- color: Colors.white,
- child: Padding(
- padding: const EdgeInsets.all(16),
- child: Column(
- children: [
- const Icon(Icons.warning_amber_rounded, size: 48, color: Colors.orange),
- const SizedBox(height: 16),
- const Text('No se pudo cargar la información', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
- const SizedBox(height: 8),
- const Text('Desliza hacia abajo para intentar de nuevo', textAlign: TextAlign.center),
- const SizedBox(height: 16),
- ElevatedButton(
- onPressed: _fetchUpdatedData,
- style: ElevatedButton.styleFrom(backgroundColor: MyApp.primaryColor),
- child: const Text('Reintentar'),
- ),
- ],
- ),
- ),
- );
- }
- }
|