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.

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