feat: integrate persona D (recycling guide) and routes modules
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
// lib/features/recycling_guide/data/datasources/recycling_local_datasource.dart
|
||||
// Único archivo que sabe que los datos vienen de un JSON en assets.
|
||||
// Funciona sin conexión a internet.
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../../domain/entities/recycling_category.dart';
|
||||
|
||||
class RecyclingLocalDatasource {
|
||||
static const _assetPath = 'assets/recycling_guide.json';
|
||||
|
||||
// Cache en memoria — se carga una sola vez durante la sesión
|
||||
List<RecyclingCategory>? _cache;
|
||||
|
||||
Future<List<RecyclingCategory>> cargarCategorias() async {
|
||||
if (_cache != null) return _cache!;
|
||||
|
||||
final raw = await rootBundle.loadString(_assetPath);
|
||||
final List<dynamic> json = jsonDecode(raw);
|
||||
|
||||
_cache = json.map(_mapearCategoria).toList();
|
||||
return _cache!;
|
||||
}
|
||||
|
||||
RecyclingCategory _mapearCategoria(dynamic json) {
|
||||
final items = (json['items'] as List)
|
||||
.map(
|
||||
(i) => RecyclingItem(
|
||||
nombre: i['nombre'] as String,
|
||||
ejemplos: i['ejemplos'] as String,
|
||||
acepta: i['acepta'] as bool,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
return RecyclingCategory(
|
||||
id: json['id'] as String,
|
||||
nombre: json['nombre'] as String,
|
||||
descripcion: json['descripcion'] as String,
|
||||
colorHex: json['color'] as String,
|
||||
icono: json['icono'] as String,
|
||||
consejo: json['consejo'] as String,
|
||||
items: items,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// lib/features/recycling_guide/data/repositories/recycling_repository.dart
|
||||
|
||||
import '../datasources/recycling_local_datasource.dart';
|
||||
import '../../domain/entities/recycling_category.dart';
|
||||
|
||||
class RecyclingRepository {
|
||||
final RecyclingLocalDatasource _datasource;
|
||||
|
||||
RecyclingRepository({RecyclingLocalDatasource? datasource})
|
||||
: _datasource = datasource ?? RecyclingLocalDatasource();
|
||||
|
||||
Future<List<RecyclingCategory>> obtenerCategorias() =>
|
||||
_datasource.cargarCategorias();
|
||||
|
||||
/// Busca en nombres y ejemplos de todos los items de todas las categorías.
|
||||
/// Devuelve pares (categoría, item) para que la UI sepa dónde mostrar el resultado.
|
||||
Future<List<SearchResult>> buscar(String query) async {
|
||||
if (query.trim().isEmpty) return [];
|
||||
|
||||
final q = query.toLowerCase();
|
||||
final categorias = await obtenerCategorias();
|
||||
final resultados = <SearchResult>[];
|
||||
|
||||
for (final cat in categorias) {
|
||||
for (final item in cat.items) {
|
||||
final coincide = item.nombre.toLowerCase().contains(q) ||
|
||||
item.ejemplos.toLowerCase().contains(q);
|
||||
if (coincide) {
|
||||
resultados.add(SearchResult(categoria: cat, item: item));
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultados;
|
||||
}
|
||||
}
|
||||
|
||||
class SearchResult {
|
||||
final RecyclingCategory categoria;
|
||||
final RecyclingItem item;
|
||||
|
||||
const SearchResult({required this.categoria, required this.item});
|
||||
}
|
||||
Reference in New Issue
Block a user