Aplicacions amb Flutter, Dart i Flame

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

Guardem permanentment l'opció triada

Ja hem vist com fer perquè l'usuari pugui triar si vol veure les dades en format text o en format gràfic; però cada cop que obri l'aplicació les veurà, per defecte, en format text. Podem fer que l'opció triada es guardi en forma permanent i es torni a carregar cada cop que s'inicia l'aplicació.

La biblioteca SharedPreferences ens permet guardar dades de diversos tipus en forma permanent a la memòria del dispositiu i tornar-les a carregar quan ens convingui. Per fer servir aquesta biblioteca, cal anar al fitxer pubspec.yaml per dir-li que la volem fer servir. Ho hem de posar a dependencies, indicant quina és la versió que volem. És recomanable indicar la darrera versió; que podem veure a la pàgina corresponent. Quan vam escriure aquest text era la 2.5.3.

dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^2.5.3

Un cop afegit, cal picar al botó per baixar el paquet (baixar).

Pot succeir que la nostra versió de NDK per a Android no sigui l'adequada, en aquest cas és probable que ens doni un error; si és així, ens indicarà quina és la versió de NDK que cal tenir. Caldrà modificar el fitxer build.gradle.kts (que es troba a la carpeta app dins de la carpeta android), posant o editant la línia dins de l'element android:

android {
    ndkVersion = "27.0.12077973"

Malgrat només tenim una dada a guardar, creem una classe, que anomenem ClausOpcions on posarem la clau que farem servir. Així es podrà modificar, sempre que calgui, en un únic lloc. Per tant, creem el fitxer claus_opcions.dart dins de la carpeta lib.

class ClausOpcions{
  static const grafic = "Grafic";
}

A la pantalla principal, a més de carregar els dos fitxers necessaris, hem d'afegir les funcions per llegir i guardar les dades, la crida a la funció de llegir-les a l'inici i la crida a la funció de guardar-les cada cop que s'acciona l'interruptor. En aquest cas, les funcions de llegir i guardar són molt senzilles; atès que només hi ha una dada per guardar.

pant_principal.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sheets/claus_opcions.dart';
import 'package:sheets/core/colors.dart';
import 'package:sheets/data/crida_dades.dart';
import 'package:sheets/data/dades_rebudes.dart';
class PantPrincipal extends StatefulWidget {
  const PantPrincipal({super.key});

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

class _PantPrincipalState extends State<PantPrincipal> {
  Future<DadesRebudes?>? _rebut;
  bool _grafic = false;
  CridaDades cridaDades = CridaDades();

  @override
  void initState() {
    super.initState();
    _rebut = cridaDades.llegirDades();
    _agafaOpcions();
  }

  _guardaOpcions(String clau, dynamic valor) async{
    final opcions = await SharedPreferences.getInstance();
    await opcions.setBool(clau, valor);
  }

  _agafaOpcions() async{
    final opcions = await SharedPreferences.getInstance();
    setState(() {
      _grafic = opcions.getBool(ClausOpcions.grafic) ?? false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Valors actuals"),),
      body: Column(
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Padding(
                padding: const EdgeInsets.all(8),
                child: TextButton(
                  onPressed: () {
                    setState(() {
                      _rebut = cridaDades.llegirDades();
                    });
                  },
                  child: Text("Recarrega"),
                ),
              ),
              Spacer(),
              Text("Gràfic"),
              Padding(
                padding: const EdgeInsets.all(12.0),
                child: Switch(
                  value: _grafic, 
                  onChanged:(value) {
                    setState(() =>  _grafic = value);
                    _guardaOpcions(ClausOpcions.grafic, _grafic);
                  },
                ),
              ) 
            ],
          ),
          FutureBuilder(future: _rebut, builder: (context, snapshot){
            if(snapshot.connectionState == ConnectionState.waiting){
              return CircularProgressIndicator();
            } else if(snapshot.hasError){
              return Text("Error: ${snapshot.error}");
            } else if(snapshot.hasData){
              if(_grafic){
                return mostraBarres(snapshot.data);
              } else {
                return escriuResultats(snapshot.data);
              }
            } else {
              return Text("No s'han trobat resultats");
            }
          })
        ],
      ),
    );
  }
}

Widget escriuResultats(DadesRebudes? dades){
  if(dades != null){
    if(dades.nom.length >=5){
      List<Widget> esquerra = [];
      List<Widget> dreta = [];
      Widget element;
      for(int i = 0; i < dades.nom.length; i++){
        element = Text("${dades.nom[i]}:      ");
        esquerra.add(element);
        element = Text("${dades.darrer[i].replaceAll('.', ',')} ${dades.unitats[i]}");
        dreta.add(element);
      }
      return Padding(
        padding: const EdgeInsets.all(8.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: esquerra,
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.end,
              children: dreta,
            ),
          ]
        ),
      );
    }
  }
  return Text("Dades incompletes");
}

Widget mostraBarres(DadesRebudes? dades){
  if(dades != null){
    if(dades.nom.length >=5){
      ColorsApp colorsApp = ColorsApp();
      List<Widget> barres = [];
      Widget element;
      double llarg;
      for(int i = 0; i < dades.nom.length; i++){
        llarg = double.parse(dades.darrer[i]) * 250 / double.parse(dades.maxim[i]);
        element = Row(
          children: [
            SizedBox(
              width: 30,
              child: Text(
                dades.titol[i], 
                style: TextStyle(
                  fontSize: 20, 
                  color: colorsApp.colorsColumnes[i], 
                  fontWeight: FontWeight.bold
                )
              ),
            ),
            Container(
              height: 40,
              width: llarg, 
              color: colorsApp.colorsColumnes[i],
            ),
            Padding(
              padding: const EdgeInsets.only(left: 10),
              child: Text(
                "${dades.darrer[i].replaceAll('.', ',')} ${dades.unitats[i]}", 
                style: TextStyle(
                  fontSize: 14, 
                  color: colorsApp.colorsColumnes[i], 
                )
              ),
            ),
          ],
        );
        barres.add(element);
      }
      return Padding(
        padding: const EdgeInsets.all(12),
        child: SizedBox(
          width: double.infinity,
          height: 300,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: barres,
          ),
        ),
      );
    }
  }
  return Text("Dades incompletes");
}

Nota: Aquest apartat està parcialment basat en l'aplicació Settings App creada per AristiDevs.

 

 

 

 

 

 

 

 

 

 

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