diff --git a/lib/pantallas/pantalla_ajustes.dart b/lib/pantallas/pantalla_ajustes.dart index 0035f77..89f253d 100644 --- a/lib/pantallas/pantalla_ajustes.dart +++ b/lib/pantallas/pantalla_ajustes.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../tema/banderas_idioma.dart'; import 'package:farolero/l10n/generated/app_localizations.dart'; import 'package:provider/provider.dart'; import '../servicios/servicio_idioma.dart'; @@ -95,6 +96,7 @@ class _PantallaAjustesState extends State { const SizedBox(height: 12), _opcionIdioma( context, + codigoBandera: 'sistema', bandera: '\u{1F310}', nombre: '${l10n.automaticLanguage} (${_nombreIdiomaDelSistema()})', codigo: 'sistema', @@ -105,6 +107,7 @@ class _PantallaAjustesState extends State { ...ServicioIdioma.idiomasSoportados.entries.map((entrada) { return _opcionIdioma( context, + codigoBandera: entrada.key, bandera: entrada.value.bandera, nombre: entrada.value.nombre, codigo: entrada.key, @@ -126,6 +129,7 @@ class _PantallaAjustesState extends State { Widget _opcionIdioma( BuildContext context, { + required String codigoBandera, required String bandera, required String nombre, required String codigo, @@ -133,7 +137,7 @@ class _PantallaAjustesState extends State { required VoidCallback onTap, }) { return ListTile( - leading: Text(bandera, style: const TextStyle(fontSize: 24)), + leading: BanderaIdioma(codigo: codigoBandera, emoji: bandera), title: Text(nombre), trailing: seleccionado ? IconoFarolero(Icons.check_circle, color: TemaApp.colorAcento) diff --git a/lib/tema/banderas_idioma.dart b/lib/tema/banderas_idioma.dart new file mode 100644 index 0000000..5ea0941 --- /dev/null +++ b/lib/tema/banderas_idioma.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; + +/// Bandera del selector de idioma. +/// +/// La mayoría son emoji de indicador regional y el sistema los dibuja solo. +/// Catalán y euskera no: Unicode define sus secuencias de subdivisión, pero +/// fuera de Inglaterra, Escocia y Gales no están en el conjunto recomendado, +/// así que casi ningún sistema las representa y salía una bandera negra. Esas +/// dos se pintan aquí; son geometría simple y así quedan nítidas a cualquier +/// tamaño sin añadir imágenes. +class BanderaIdioma extends StatelessWidget { + final String codigo; + final String emoji; + final double alto; + + const BanderaIdioma({ + super.key, + required this.codigo, + required this.emoji, + this.alto = 22, + }); + + static const _pintadas = {'ca', 'eu'}; + + /// True si la bandera de ese idioma se dibuja en vez de usar emoji. + static bool sePinta(String codigo) => _pintadas.contains(codigo); + + @override + Widget build(BuildContext context) { + if (!sePinta(codigo)) { + // El emoji ocupa lo que ocupe; se le da la misma caja que a las pintadas + // para que la lista quede alineada. + return SizedBox( + width: alto * 1.5, + height: alto, + child: Center( + child: Text(emoji, style: TextStyle(fontSize: alto * 1.1)), + ), + ); + } + + return SizedBox( + width: alto * 1.5, + height: alto, + child: ClipRRect( + borderRadius: BorderRadius.circular(3), + child: CustomPaint( + painter: codigo == 'ca' + ? const _SenyeraPainter() + : const _IkurrinaPainter(), + size: Size(alto * 1.5, alto), + ), + ), + ); + } +} + +/// Senyera: cuatro palos rojos sobre fondo amarillo, nueve franjas iguales. +class _SenyeraPainter extends CustomPainter { + const _SenyeraPainter(); + + static const _amarillo = Color(0xFFFCDD09); + static const _rojo = Color(0xFFDA121A); + + @override + void paint(Canvas canvas, Size size) { + canvas.drawRect( + Rect.fromLTWH(0, 0, size.width, size.height), + Paint()..color = _amarillo, + ); + + final franja = size.height / 9; + final pincel = Paint()..color = _rojo; + // Las franjas impares (1, 3, 5, 7) son los cuatro palos. + for (var i = 1; i < 9; i += 2) { + canvas.drawRect( + Rect.fromLTWH(0, franja * i, size.width, franja), + pincel, + ); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} + +/// Ikurriña: fondo rojo, aspa verde y cruz blanca encima. +class _IkurrinaPainter extends CustomPainter { + const _IkurrinaPainter(); + + static const _rojo = Color(0xFFD52B1E); + static const _verde = Color(0xFF009B48); + static const _blanco = Color(0xFFFFFFFF); + + @override + void paint(Canvas canvas, Size size) { + final w = size.width; + final h = size.height; + + canvas.drawRect(Rect.fromLTWH(0, 0, w, h), Paint()..color = _rojo); + + // El aspa va de esquina a esquina, por debajo de la cruz. + final grosor = h * 0.19; + final aspa = Paint() + ..color = _verde + ..strokeWidth = grosor + ..style = PaintingStyle.stroke; + canvas.save(); + canvas.clipRect(Rect.fromLTWH(0, 0, w, h)); + canvas.drawLine(Offset.zero, Offset(w, h), aspa); + canvas.drawLine(Offset(w, 0), Offset(0, h), aspa); + canvas.restore(); + + // Cruz blanca centrada, encima del aspa. + final blanco = Paint()..color = _blanco; + canvas.drawRect( + Rect.fromLTWH((w - grosor) / 2, 0, grosor, h), + blanco, + ); + canvas.drawRect( + Rect.fromLTWH(0, (h - grosor) / 2, w, grosor), + blanco, + ); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +}