Aplicacions amb Flutter, Dart i Flame

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

Afegim dues consultes més

El web també ens ofereix la possibilitat d'obtenir la dona del dia i també una dona escollida alesatòriament. En aquest cas, només s'obtenen les dades d'una persona; en el mateix format que quan es consulta una dona de la llista.

Ara afegirem dos botons més, de manera que la filera de botons s'anirà omplint; per això sembla oportú un canvi de disseny que faci els botons més petits. En el cas dels dos botons que afegim, posarem una icona; un dau per a la dona escollida aleatòriament i un calendari per a la dona del dia. Per a les dones catalanes, podem posar una imatge que mostri la senyera. En el cas de les dones nascude a partir de l'any 2000, no hem trobat cap icona adequada i hem optat per posar el text s. XXI.

Per a la crida, podem modificar la classe CridaDetall; atès que les crides tornen el mateix format de resultats i són gairebé idèntiques, només cal modificar un paràmetre a l'adreça URL. A la funció demanarDetall mirarem si el paràmetre és el que correspon a la dona del dia (tipus=dia) o a la dona escollida aleatòriament (tipus=aleat); en cas contrari, es farà el mateix que fins ara.

crida_detall.dart
import 'dart:convert';
import 'package:dones_destacades/data/dades_rebudes_detall.dart';
import 'package:http/http.dart' as http;  // No el troba automàticament, s'ha d'entrar a mà
class CridaDetall{
  Future<DadesRebudesDetall?> demanarDetall(String ident) async{
    String params = "tipus=concreta&id=$ident";
    if(ident == "dia"){
      params = "tipus=dia";
    }
    if(ident == "aleat"){
      params = "tipus=aleat";
    }
    final detallRebut = await 
      http.get(Uri.parse("https://recursos.citcea.upc.edu/dones/service.php?$params"));
    if(detallRebut.statusCode == 200){
      var jsonDecodificat = jsonDecode(detallRebut.body);
      DadesRebudesDetall dadesRebudesDetall = DadesRebudesDetall.fromJson(jsonDecodificat);
      return dadesRebudesDetall;
    } else {
      return null;
    }
  }
}

A la pantalla principal és on hi ha més canvis, però abans hem de posar la imatge que farem servir per al botó. A l'arrel del projecte, crearem la carpeta assets i, dins d'aquesta, la carpeta images; dins d'aquesta hi posarem la imatge senyera.gif (que podem descarregar picant amb el botó dret sobre l'enllaç). Aquesta imatge té només 9 ⨯ 1 píxels i l'escalem per donar-li la mida desitjada. Per tal que Flutter la trobi, cal afegir la ruta on està la imatge al fitxer pubspec.yaml.

...
flutter:
  uses-material-design: true
  assets:
    - assets/images/

En la pantalla principal modificarem els dos botons ja existents per donar-los el nou format i afegirem els dos botons que manquen.

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";

  @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) {
    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)
                ),
              ),
            ],
          ),
          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.