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)),
]
)
)
);
}
}

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