Created
March 22, 2023 19:35
-
-
Save Klerith/0b7282fc4d3d83e686b8e47b5292b696 to your computer and use it in GitHub Desktop.
Pantalla de Producto y Custom Product Field
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
class CustomProductField extends StatelessWidget { | |
final bool isTopField; // La idea es que tenga bordes redondeados arriba | |
final bool isBottomField; // La idea es que tenga bordes redondeados abajo | |
final String? label; | |
final String? hint; | |
final String? errorMessage; | |
final bool obscureText; | |
final TextInputType? keyboardType; | |
final int maxLines; | |
final String initialValue; | |
final Function(String)? onChanged; | |
final Function(String)? onFieldSubmitted; | |
final String? Function(String?)? validator; | |
const CustomProductField({ | |
super.key, | |
this.isTopField = false, | |
this.isBottomField = false, | |
this.label, | |
this.hint, | |
this.errorMessage, | |
this.obscureText = false, | |
this.keyboardType = TextInputType.text, | |
this.maxLines = 1, | |
this.initialValue = '', | |
this.onChanged, | |
this.onFieldSubmitted, | |
this.validator, | |
}); | |
@override | |
Widget build(BuildContext context) { | |
final colors = Theme.of(context).colorScheme; | |
final border = OutlineInputBorder( | |
borderSide: const BorderSide(color: Colors.transparent), | |
borderRadius: BorderRadius.circular(40) | |
); | |
const borderRadius = Radius.circular(15); | |
return Container( | |
// padding: const EdgeInsets.only(bottom: 0, top: 15), | |
decoration: BoxDecoration( | |
color: Colors.white, | |
borderRadius: BorderRadius.only( | |
topLeft: isTopField ? borderRadius : Radius.zero, | |
topRight: isTopField ? borderRadius : Radius.zero, | |
bottomLeft: isBottomField ? borderRadius : Radius.zero, | |
bottomRight: isBottomField ? borderRadius : Radius.zero, | |
), | |
boxShadow: [ | |
if (isBottomField) | |
BoxShadow( | |
color: Colors.black.withOpacity(0.06), | |
blurRadius: 5, | |
offset: const Offset(0,3) | |
) | |
] | |
), | |
child: TextFormField( | |
onChanged: onChanged, | |
onFieldSubmitted: onFieldSubmitted, | |
validator: validator, | |
obscureText: obscureText, | |
keyboardType: keyboardType, | |
style: const TextStyle( fontSize: 15, color: Colors.black54 ), | |
maxLines: maxLines, | |
initialValue: initialValue, | |
decoration: InputDecoration( | |
floatingLabelBehavior: maxLines > 1 ? FloatingLabelBehavior.always : FloatingLabelBehavior.auto, | |
floatingLabelStyle: const TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 15), | |
enabledBorder: border, | |
focusedBorder: border, | |
errorBorder: border.copyWith( borderSide: const BorderSide( color: Colors.transparent )), | |
focusedErrorBorder: border.copyWith( borderSide: const BorderSide( color: Colors.transparent )), | |
isDense: true, | |
label: label != null ? Text(label!) : null, | |
hintText: hint, | |
errorText: errorMessage, | |
focusColor: colors.primary, | |
// icon: Icon( Icons.supervised_user_circle_outlined, color: colors.primary, ) | |
), | |
), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class _ProductView extends StatelessWidget { | |
final Product product; | |
const _ProductView({required this.product}); | |
@override | |
Widget build(BuildContext context) { | |
final textStyles = Theme.of(context).textTheme; | |
return ListView( | |
children: [ | |
SizedBox( | |
height: 250, | |
width: 600, | |
child: _ImageGallery(images: product.images ), | |
), | |
const SizedBox( height: 10 ), | |
Center(child: Text( product.title, style: textStyles.titleSmall )), | |
const SizedBox( height: 10 ), | |
_ProductInformation( product: product ), | |
], | |
); | |
} | |
} | |
class _ProductInformation extends ConsumerWidget { | |
final Product product; | |
const _ProductInformation({required this.product}); | |
@override | |
Widget build(BuildContext context, WidgetRef ref ) { | |
return Padding( | |
padding: const EdgeInsets.symmetric(horizontal: 20), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
const Text('Generales'), | |
const SizedBox(height: 15 ), | |
CustomProductField( | |
isTopField: true, | |
label: 'Nombre', | |
initialValue: product.title, | |
), | |
CustomProductField( | |
isTopField: true, | |
label: 'Slug', | |
initialValue: product.slug, | |
), | |
CustomProductField( | |
isBottomField: true, | |
label: 'Precio', | |
keyboardType: const TextInputType.numberWithOptions(decimal: true), | |
initialValue: product.price.toString(), | |
), | |
const SizedBox(height: 15 ), | |
const Text('Extras'), | |
_SizeSelector(selectedSizes: product.sizes ), | |
const SizedBox(height: 5 ), | |
_GenderSelector( selectedGender: product.gender ), | |
const SizedBox(height: 15 ), | |
CustomProductField( | |
isTopField: true, | |
label: 'Existencias', | |
keyboardType: const TextInputType.numberWithOptions(decimal: true), | |
initialValue: product.stock.toString(), | |
), | |
CustomProductField( | |
maxLines: 6, | |
label: 'Descripción', | |
keyboardType: TextInputType.multiline, | |
initialValue: product.description, | |
), | |
CustomProductField( | |
isBottomField: true, | |
maxLines: 2, | |
label: 'Tags (Separados por coma)', | |
keyboardType: TextInputType.multiline, | |
initialValue: product.tags.join(', '), | |
), | |
const SizedBox(height: 100 ), | |
], | |
), | |
); | |
} | |
} | |
class _SizeSelector extends StatelessWidget { | |
final List<String> selectedSizes; | |
final List<String> sizes = const['XS','S','M','L','XL','XXL','XXXL']; | |
const _SizeSelector({required this.selectedSizes}); | |
@override | |
Widget build(BuildContext context) { | |
return SegmentedButton( | |
showSelectedIcon: false, | |
segments: sizes.map((size) { | |
return ButtonSegment( | |
value: size, | |
label: Text(size, style: const TextStyle(fontSize: 10)) | |
); | |
}).toList(), | |
selected: Set.from( selectedSizes ), | |
onSelectionChanged: (newSelection) { | |
print(newSelection); | |
}, | |
multiSelectionEnabled: true, | |
); | |
} | |
} | |
class _GenderSelector extends StatelessWidget { | |
final String selectedGender; | |
final List<String> genders = const['men','women','kid']; | |
final List<IconData> genderIcons = const[ | |
Icons.man, | |
Icons.woman, | |
Icons.boy, | |
]; | |
const _GenderSelector({required this.selectedGender}); | |
@override | |
Widget build(BuildContext context) { | |
return Center( | |
child: SegmentedButton( | |
multiSelectionEnabled: false, | |
showSelectedIcon: false, | |
style: const ButtonStyle(visualDensity: VisualDensity.compact ), | |
segments: genders.map((size) { | |
return ButtonSegment( | |
icon: Icon( genderIcons[ genders.indexOf(size) ] ), | |
value: size, | |
label: Text(size, style: const TextStyle(fontSize: 12)) | |
); | |
}).toList(), | |
selected: { selectedGender }, | |
onSelectionChanged: (newSelection) { | |
print(newSelection); | |
}, | |
), | |
); | |
} | |
} | |
class _ImageGallery extends StatelessWidget { | |
final List<String> images; | |
const _ImageGallery({required this.images}); | |
@override | |
Widget build(BuildContext context) { | |
return PageView( | |
scrollDirection: Axis.horizontal, | |
controller: PageController( | |
viewportFraction: 0.7 | |
), | |
children: images.isEmpty | |
? [ ClipRRect( | |
borderRadius: const BorderRadius.all(Radius.circular(20)), | |
child: Image.asset('assets/images/no-image.jpg', fit: BoxFit.cover )) | |
] | |
: images.map((e){ | |
return ClipRRect( | |
borderRadius: const BorderRadius.all(Radius.circular(20)), | |
child: Image.network(e, fit: BoxFit.cover,), | |
); | |
}).toList(), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Gracias profe por el código!