fix: perfil - dropdown ciudad con todas las opciones

- WhiteCard usa Theme.cardColor en lugar de Colors.white fijo
- Dropdown ciudad: normaliza valor guardado vs lista (evita mismatch)
- Muestra spinner mientras cargan las ciudades
- Texto de items adapta color segun el tema (isDark)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-27 09:22:10 -05:00
co-authored by Claude Sonnet 4.6
parent fac4135835
commit 7349d4e3fd
2 changed files with 39 additions and 15 deletions
+4 -3
View File
@@ -14,7 +14,7 @@ class WhiteCard extends StatelessWidget {
width: width, // width == null ? null : width,
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(10),
decoration: buildBoxDecoration(),
decoration: buildBoxDecoration(context),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -37,9 +37,10 @@ class WhiteCard extends StatelessWidget {
);
}
BoxDecoration buildBoxDecoration() {
BoxDecoration buildBoxDecoration(BuildContext context) {
final cardColor = Theme.of(context).cardColor;
return BoxDecoration(
color: Colors.white,
color: cardColor,
borderRadius: BorderRadius.circular(5),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 5)
+35 -12
View File
@@ -109,6 +109,20 @@ class _ProfileViewForm extends StatelessWidget {
final citiesProvider = Provider.of<CitiesProvider>(context);
final cities = citiesProvider.cities;
final user = profileFormProvider.user!;
final isDark = Theme.of(context).brightness == Brightness.dark;
final textColor = isDark ? Colors.white : Colors.black87;
// Normaliza el valor actual para que coincida exactamente con la lista
final cityNames = cities.map((c) => c.cityName).toList();
String? currentCity;
if (user.city != null && user.city!.isNotEmpty) {
final saved = user.city!.toLowerCase().trim();
currentCity = cityNames.firstWhere(
(n) => n.toLowerCase().trim() == saved,
orElse: () => '',
);
if (currentCity!.isEmpty) currentCity = null;
}
return WhiteCard(
title: 'Información general',
@@ -169,14 +183,19 @@ class _ProfileViewForm extends StatelessWidget {
),
),
const SizedBox(height: 20),
DropdownButtonFormField(
if (citiesProvider.isLoading)
const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Center(child: CircularProgressIndicator()),
)
else
DropdownButtonFormField<String>(
validator: (value) {
if (value == null) {
return 'La ciudad es obligatoria';
}
if (value == null) return 'La ciudad es obligatoria';
return null;
},
value: user.city == '' ? null : user.city,
value: currentCity,
isExpanded: true,
decoration: CustomInputs.formInputDecoration(
hint: 'Selecciona tu ciudad',
label: 'Ciudad',
@@ -185,16 +204,20 @@ class _ProfileViewForm extends StatelessWidget {
items: cities.map((City ciudad) {
return DropdownMenuItem<String>(
value: ciudad.cityName,
child: Text('${ciudad.cityName} - ${ciudad.stateOfCity}',
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
)),
child: Text(
'${ciudad.cityName} - ${ciudad.stateOfCity}',
style: TextStyle(
color: textColor,
fontWeight: FontWeight.normal,
),
overflow: TextOverflow.ellipsis,
),
);
}).toList(),
onChanged: (value) {
profileFormProvider.copyUserWith(city: value!);
}),
if (value != null) profileFormProvider.copyUserWith(city: value);
},
),
const SizedBox(height: 20),
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 130),