Aplicacions amb Flutter, Dart i Flame

Tutorial Flutter Flame Projectes   Recursos CITCEA
Exemples Dart Dades pràctiques     Inici

Consulta de les dones d'un àmbit

El web també ens ofereix la possibilitat d'obtenir la llista de dones d'un àmbit concret, indicant-ne el codi. En aquest cas, el resultat és una llista amb el mateix format que quan es consulten les dones catalanes o les dones joves.

Tenim els àmbits en un diccionari que associa cada codi amb el descriptor de l'àmbit, farem un desplegable que ens permeti seleccionar un àmbit i faci la crida corresponent.

Per a la crida, podem modificar la classe CridaLlistaDones; atès que les crides tornen el mateix format de resultats i són molt semblants, només cal afegir un paràmetre a l'adreça URL. A la funció demanarLlistaDones mirarem si el paràmetre és el que correspon a les dones catalanes (tipus=cat) o a les dones joves (tipus=joves); en cas contrari, farem la crida per llegir la llista de dones de l'àmbit.

crida_llista_dones.dart
import 'dart:convert';
import 'package:dones_destacades/data/dades_rebudes_dones.dart';
import 'package:http/http.dart' as http;  // No el troba automàticament, s'ha d'entrar a mà
class CridaLlistaDones{
  Future<DadesRebudesDones?> demanarLlistaDones(String tip) async{
    String amb = "";
    if(tip.isEmpty){
      // Si, pel motiu que sigui, la clau és buida, retorna les catalanes
      tip = "cat";
    } else {
      if((tip != "cat") && (tip != "joves")){
        amb = "ambit&ambit=";
      }
    }
    final llistaDonesRebuda = await 
      http.get(Uri.parse("https://recursos.citcea.upc.edu/dones/service.php?tipus=$amb$tip"));
    if(llistaDonesRebuda.statusCode == 200){
      var jsonDecodificat = jsonDecode(llistaDonesRebuda.body);
      DadesRebudesDones dadesRebudesDones = DadesRebudesDones.fromJson(jsonDecodificat);
      return dadesRebudesDones;
    } else {
      return null;
    }
  }
}

A la pantalla principal hi afegirem el desplegable; a més, caldrà definir una variable.

pant_principal.dart
import 'package:dones_destacades/data/crida_llista_ambits.dart';
import 'package:dones_destacades/data/crida_llista_dones.dart';
import 'package:dones_destacades/data/dades_dona_llista.dart';
import 'package:dones_destacades/data/dades_rebudes_dones.dart';
import 'package:dones_destacades/screens/pant_detalls.dart';
import 'package:flutter/material.dart';
import 'package:html_unescape/html_unescape.dart';  // No ho posa automàticament
class PantPrincipal extends StatefulWidget {
  const PantPrincipal({super.key});

  @override
  State<PantPrincipal> createState(){
    return _PantPrincipalState();
  }
}

class _PantPrincipalState extends State<PantPrincipal> {
  Map<String, String> _dadesAmbits = {};
  Future<DadesRebudesDones?>? _dadesDones;
  CridaLlistaDones cridaLlistaDones = CridaLlistaDones();
  CridaLlistaAmbits cridaLlistaAmbits = CridaLlistaAmbits();
  bool _carregat = false;
  String titol = "Dones destacades";
  String? _opcioSeleccionada;
  
  @override
  void initState() {
    super.initState();
    _carregarDades();
  }

  Future<void> _carregarDades() async {
    final dades = await cridaLlistaAmbits.demanarLlistaAmbits();
    setState(() {
      _dadesAmbits = dades;
      _carregat = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    var unescape = HtmlUnescape();
    return Scaffold(
      appBar: AppBar(title: Text("Dones destacades"),),
      body: Column(
        children: [
          Row(
            children: [
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: IconButton(
                  onPressed: () {
                    setState(() {
                      _dadesDones = cridaLlistaDones.demanarLlistaDones("cat");
                      titol = "Dones catalanes";
                    });
                  },
                  icon: Image.asset("assets/images/senyera.gif", height: 20, width: 20, fit: BoxFit.fill,),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextButton(
                  onPressed: () {
                    setState(() {
                      _dadesDones = cridaLlistaDones.demanarLlistaDones("joves");
                      titol = "Dones joves";
                    });
                  },
                  child: Text("s. XXI"),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: IconButton(
                  onPressed: () => Navigator.push(context, MaterialPageRoute(
                    builder: (context) => PantDetalls(
                      persona: "dia", 
                      dadesAmbits: _dadesAmbits, 
                      carregat: _carregat
                    ),
                  )),
                  icon: Icon(Icons.calendar_month)
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: IconButton(
                  onPressed: () => Navigator.push(context, MaterialPageRoute(
                    builder: (context) => PantDetalls(
                      persona: "aleat", 
                      dadesAmbits: _dadesAmbits, 
                      carregat: _carregat
                    ),
                  )),
                  icon: Icon(Icons.casino_outlined)
                ),
              ),
            ],
          ),
          if(_carregat && _dadesAmbits.isNotEmpty) DropdownButton<String>(
            value: _opcioSeleccionada,
            hint: const Text('Escull un àmbit'),
            isExpanded: true,
            items: _dadesAmbits.keys.map((String clau) {
              return DropdownMenuItem<String>(
                value: clau,
                child: Text(unescape.convert(_dadesAmbits[clau]!)),
              );
            }).toList(),
            onChanged: (String? novaClauSeleccionada) {
              setState(() {
                // Si, pel motiu que sigui, la clau és un nul, retorna les catalanes
                _dadesDones = cridaLlistaDones.demanarLlistaDones(novaClauSeleccionada ?? 'cat');
                titol = unescape.convert(_dadesAmbits[novaClauSeleccionada]!);
              });
            },
          ),
          Container(
            alignment: Alignment.topLeft,
            padding: const EdgeInsets.all(8),
            child: Text(titol, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold))
          ),
          mostraLlista()
        ],
      ),
    );
  }

  FutureBuilder<DadesRebudesDones?> mostraLlista() {
    return FutureBuilder(future: _dadesDones, builder: (context, snapshot){
      if(snapshot.connectionState == ConnectionState.waiting){
        return CircularProgressIndicator();
      } else if(snapshot.hasError){
        return Text("Error: ${snapshot.error}");
      } else if(snapshot.hasData){
        var llistaDones = snapshot.data?.llistaDadesDonaLlista;
        return Expanded(
          child: ListView.builder(
            itemCount: llistaDones?.length ?? 0,
            itemBuilder: (context, index) {
              if(llistaDones != null){
                return mostraElement(llistaDones[index]);
              } else {
                return Text("Error a la llista");
              }
            },
          ),
        );
      } else {
        return Text("No s'han trobat resultats");
      }
    });
  }

  Padding mostraElement(DadesDonaLlista donaDeLaLlista) {
    var unescape = HtmlUnescape();
    String ambitAct = "";
    if(_carregat){
      ambitAct = _dadesAmbits[donaDeLaLlista.ambit].toString();
    }
    return Padding(
      padding: const EdgeInsets.all(5.0),
      child: GestureDetector(
        onTap: () => Navigator.push(context, MaterialPageRoute(
            builder: (context) => PantDetalls(
              persona: donaDeLaLlista.id, 
              dadesAmbits: _dadesAmbits, 
              carregat: _carregat
            ),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(unescape.convert(donaDeLaLlista.nom), 
              style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)),
            Text(unescape.convert(donaDeLaLlista.professio), 
              style: TextStyle(fontSize: 13)),
            if(_carregat && ambitAct.isNotEmpty) 
              Text("Àmbit: ${unescape.convert(ambitAct)}", style: TextStyle(fontSize: 13)),
          ]
        )
      )
    );
  }
}

 

 

 

 

 

 

 

 

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.