Aplicacions amb Flutter, Dart i Flame

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

Commutem entre modes

Ara anem a donar l'opció a l'usuari de poder triar quin dels dos modes vol. A més, aprofitant que ja ho fèiem per al mode gràfic, també guardarem de manera permanent quina és el mode preferit.

Necessitarem modificar el mode durant el funcionament i això ens obliga a fer un canvi. Fins ara el giny MaterialApp estava dins del programa principal (main), però la classe MainApp és un giny sense estat i això ens impediria fer el canvi de mode. Cal, doncs, passar el MaterialApp a la pantalla principal, de manera que el programa principal ens quedarà així:

main.dart
import 'package:flutter/material.dart';
import 'package:sheets/screens/pant_principal.dart';
void main() {
  runApp(const MainApp());
}
class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return PantPrincipal();
  }
}

A més de modificar la pantalla principal, que ho farem una mica més avall, també ens cal definir la clau per guradar el mode.

claus_opcions.dart
class ClausOpcions{
  static const grafic = "Grafic";
  static const fosc = "Fosc";
}

A la pantalla principal hem de definir una variable per guardar el mode, Afegir la lectura del mode a la funció _agafaOpcions, afegir el MaterialApp amb el mode (que dependrà de la variable) i afegir l'interruptor. A la funció mostraColumnes hem creat una variable per gestionar el color, atès que es fa servir en tres llocs diferents i no té sentit comprovar-ho tres vegades.

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;
  bool _fosc = 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;
      _fosc = opcions.getBool(ClausOpcions.fosc) ?? false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: _fosc ? ThemeData.dark() : ThemeData.light(),
      home: 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);
                    },
                  ),
                ),
                Spacer(),
                Text("Fosc"),
                Padding(
                  padding: const EdgeInsets.all(12.0),
                  child: Switch(
                    value: _fosc, 
                    onChanged:(value) {
                      setState(() =>  _fosc = value);
                      _guardaOpcions(ClausOpcions.fosc, _fosc);
                    },
                  ),
                )
              ],
            ),
            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 mostraColumnes(snapshot.data, _fosc);
                } 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 mostraColumnes(DadesRebudes? dades, bool mode){
  if(dades != null){
    if(dades.nom.length >=5){
      ColorsApp colorsApp = ColorsApp();
      List<Widget> columnes = [];
      Widget element;
      double alt;
      Color colorAct;
      for(int i = 0; i < dades.nom.length; i++){
        alt = double.parse(dades.darrer[i]) * 150 / double.parse(dades.maxim[i]);
        if(mode){
          colorAct = colorsApp.colorsColumnesFosc[i];
        } else {
          colorAct = colorsApp.colorsColumnesClar[i];
        }
        element = Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Text(
              "${dades.darrer[i].replaceAll('.', ',')} ${dades.unitats[i]}", 
              style: TextStyle(
                fontSize: 14, 
                color: colorAct, 
              )
            ),
            Container(
              height: alt,
              width: 40, 
                color: colorAct, 
            ),
            Text(
              dades.titol[i], 
              style: TextStyle(
                fontSize: 20, 
                color: colorAct, 
                fontWeight: FontWeight.bold
              )
            )
          ],
        );
        columnes.add(element);
      }
      return SizedBox(
        width: double.infinity,
        height: 200,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: columnes,
        ),
      );
    }
  }
  return Text("Dades incompletes");
}

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

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.