Created with <3 with dartpad.dev.
Last active
May 31, 2023 17:24
-
-
Save stephanedeluca/a629879ae8cb08d429757d784a36ce10 to your computer and use it in GitHub Desktop.
Shokaze category details form designer
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'; | |
import 'package:intl/intl.dart'; | |
const Color darkBlue = Color.fromARGB(255, 18, 32, 47); | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData.dark().copyWith( | |
scaffoldBackgroundColor: darkBlue, | |
), | |
debugShowCheckedModeBanner: false, | |
home: Scaffold( | |
appBar:AppBar(title:const Text("Shokaze category details form designer")), | |
body: Center( | |
child: CategoryTesterWidget(), | |
), | |
), | |
); | |
} | |
} | |
class CategoryTesterWidget extends StatefulWidget { | |
@override State<CategoryTesterWidget> createState() => _CategoryTesterWidgetState(); | |
} | |
class _CategoryTesterWidgetState extends State<CategoryTesterWidget> { | |
ClassifiedAdCategory _category = ClassifiedAdCategory.car; | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.all(20), | |
child: Column( | |
children:[ | |
ListTile( | |
onTap:(){ | |
showModalBottomSheet( | |
context: context, | |
builder: (context) => //Center(child:Text("bottom sheet")) | |
//ClassifiedAdCategory.showModalBottomSheetListPicker | |
ClassifiedAdCategory.foldingSuperCategoryListPicker | |
(context, | |
value:_category, | |
onTap:(value)=> setState(()=>_category=value) | |
), | |
); | |
}, | |
title: const Text( | |
'Pick the category to test:', | |
//style: Theme.of(context).textTheme.headlineMedium | |
), | |
trailing: Text("${_category.name} >") | |
), | |
Card( | |
child: Padding( | |
padding: const EdgeInsets.all(20), | |
child:AdFormCategoryDetail(category: _category), | |
), | |
), | |
]), | |
); | |
} | |
} | |
/* | |
/// The main form for the classified ad | |
class _AdFormMain extends StatefulWidget { | |
final Key formKey; | |
//final ClassifiedAd ad; | |
const _AdFormMain({super.key, required this.formKey, //required this.ad | |
}); | |
@override | |
State<_AdFormMain> createState() => _AdFormMainState(); | |
} | |
class _AdFormMainState extends State<_AdFormMain> { | |
// static const form = { | |
// "title": {"type": "string"}, | |
// "category": { | |
// "type": "enum", | |
// "values": ["realEstate", "furniture", "vehicle", "computer"], | |
// }, | |
// "address": {"type": "address"}, | |
// "price": {"type": "price"}, | |
// }; | |
// Limitation à 10 charactères: 2 caractères; => B24 (// B23: retour AVI du dimanche 6 mars 2023 à 16 h 29) | |
static const titleCharacterCountMinLimit = 2; | |
/// Whether the value have been loaded from the persistence | |
bool _loaded = false; | |
@override | |
void initState() { | |
loadValues(); | |
super.initState(); | |
} | |
void loadValues() async { | |
/* | |
final sharedPreferences = await SharedPreferences.getInstance(); | |
widget.ad.title = | |
sharedPreferences.getString("$persistenceKey.title") ?? ""; | |
try { | |
final catergoryValue = | |
sharedPreferences.getString("$persistenceKey.category") ?? "other"; | |
widget.ad.category = ClassifiedAdCategory.fromName(catergoryValue); | |
} catch (e) { | |
widget.ad.category = ClassifiedAdCategory.other; | |
} | |
final price = sharedPreferences.getDouble("$persistenceKey.price") ?? 0; | |
widget.ad.price = price; | |
*/ | |
setState(() => _loaded = true); | |
} | |
static const persistenceKey = "AdFormMain"; | |
void saveValues() async { | |
/* | |
final ad = widget.ad; | |
final sharedPreferences = await SharedPreferences.getInstance(); | |
await sharedPreferences.setString("$persistenceKey.title", ad.title); | |
await sharedPreferences.setString( | |
"$persistenceKey.category", ad.category.name); | |
// final city = widget.ad.; | |
// if (city == null){ | |
// sharedPreferences.remove("$peristenceKey.city"); | |
//} | |
// else { | |
// sharedPreferences.setString("$peristenceKey.city", city); | |
//} | |
final price = ad.price; | |
if (price == null) { | |
await sharedPreferences.remove("$persistenceKey.price"); | |
} else { | |
await sharedPreferences.setDouble("$persistenceKey.price", price); | |
} | |
*/ | |
} | |
@override | |
Widget build(BuildContext context) { | |
if (!_loaded) return const LinearProgressIndicator(); | |
final formKey = widget.formKey; | |
//final ad = widget.ad; | |
return Form( | |
key: formKey, | |
autovalidateMode: AutovalidateMode.always, | |
onChanged: () { | |
saveValues(); | |
}, | |
// onWillPop: () async { | |
// saveValues(); | |
// return true; | |
// }, | |
child: Column( | |
//mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: [ | |
// == The ad list widget | |
//ad.listWidget(context, withAction: ClassifiedAdAction.none), | |
// == The title | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: "Title", | |
), | |
validator: (value) { | |
if (value == null) return "Title is mandatory"; | |
if (value.trim().length < titleCharacterCountMinLimit) { | |
return "You must provide a title of at least $titleCharacterCountMinLimit characters" | |
; | |
} | |
return null; | |
}, | |
onChanged: (newValue) { | |
setState(() { | |
//ad.title = newValue; | |
}); | |
}, | |
), | |
// == Ad category | |
ClassifiedAdPropertyEditor( | |
isSignedInUserIsAdOwner: true, | |
icon: Icons.category, | |
caption: "Category", | |
value: ad.category.toString(), | |
onPressed: () => | |
ClassifiedAdCategory.showModalBottomSheetListPicker(context, | |
value: ad.category, | |
onTap: (value) => setState(() { | |
ad.category = value; | |
})), | |
onChanged: (value) {}), | |
// TextFormField( | |
// decoration: const InputDecoration( | |
// labelText: 'City', | |
// ), | |
// onChanged: (newValue) { | |
// //setState(() { | |
// // ad.city = newValue!; | |
// //}); | |
// }, | |
// ), | |
// == Ad price | |
PriceInputField( | |
price: ad.price, | |
currency: ad.priceCurrency, | |
onChanged: (price, currency) { | |
setState(() { | |
ad.price = price; | |
ad.priceCurrency = currency; | |
}); | |
}), | |
// == Description | |
TextFormField( | |
maxLines: 8, | |
decoration: InputDecoration( | |
labelText: "Description" | |
), | |
validator: (value) { | |
//if (value == null) return i18n_Title_is_mandatory.i18n; | |
// if (value.trim().length < titleMinCharacterCount) { | |
// return i18n_You_must_provide_a_title_of_at_least_d_characters | |
// .i18n | |
// .fill([titleMinCharacterCount]); | |
// } | |
return null; | |
}, | |
onChanged: (newValue) { | |
setState(() { | |
ad.description = newValue; | |
}); | |
}, | |
), | |
], | |
)); | |
} | |
} | |
*/ | |
/// The form that takes the style from the classified [ad] | |
class AdFormCategoryDetail extends StatelessWidget { | |
//final Key formKey; | |
final ClassifiedAdCategory category; | |
const AdFormCategoryDetail( | |
{super.key, //required this.formKey, | |
required this.category}); | |
@override | |
Widget build(BuildContext context) { | |
final style = category.metaData(); | |
List<Widget> children = []; | |
style.forEach(((name, fieldDefinition) { | |
final w = | |
GenericFormInputField(name: name, fieldDefinition: fieldDefinition); | |
children.add(w); | |
})); | |
return Column(children: children); | |
} | |
} | |
/// The form that takes the fields from [fieldsDefinition] | |
class GenericForm extends StatelessWidget { | |
final Key formKey; | |
final Map<String, Map<String, dynamic>> fieldsDefinition; | |
const GenericForm( | |
{Key? key, required this.formKey, required this.fieldsDefinition}) | |
: super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
List<Widget> children = []; | |
fieldsDefinition.forEach(((name, fieldDefinition) { | |
final w = | |
GenericFormInputField(name: name, fieldDefinition: fieldDefinition); | |
children.add(w); | |
})); | |
return Form( | |
key: formKey, | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: children)); | |
} | |
} | |
/// The form input field that takes its [name] and json definition | |
class GenericFormInputField extends StatefulWidget { | |
final String name; | |
final Map<String, dynamic> fieldDefinition; | |
const GenericFormInputField( | |
{Key? key, required this.name, required this.fieldDefinition}) | |
: super(key: key); | |
@override | |
State<GenericFormInputField> createState() => _GenericFormInputField(); | |
} | |
class _GenericFormInputField extends State<GenericFormInputField> { | |
final controller = TextEditingController(); | |
// @override | |
// void initState() { | |
// super.initState(); | |
// } | |
/* | |
{ | |
"surface": {"type": double, "unit": "m2"}, | |
"buildDate": { | |
"type": DateTime, | |
}, | |
"price": {"type": double, "unit": "€"}, | |
"type": { | |
"type": Enum, | |
"values": ["Maison", "Appart", "Terrain", "Appart", null] | |
}, | |
}*/ | |
String? _initialValue; | |
int? _maxLines; | |
@override | |
initState() { | |
final def = widget.fieldDefinition; | |
final value = def["value"]; | |
if (value != null) { | |
controller.text = "$value"; | |
} | |
if (def["maxLines"] != null) { | |
_maxLines = def["maxLines"]; | |
} | |
super.initState(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final name = widget.name; | |
final fieldDefinition = widget.fieldDefinition; | |
TextInputType tit = TextInputType.text; | |
final type = fieldDefinition["type"]; | |
final prefixIcon = fieldDefinition["icon"] is IconData | |
? Padding(padding: const EdgeInsets.only(top:20),child:Icon(fieldDefinition["icon"])) | |
: null; | |
final unit = fieldDefinition["unit"] is String | |
? Padding( | |
padding: const EdgeInsets.only( | |
top: 20), | |
child: Text(fieldDefinition["unit"]), | |
) | |
: null; | |
switch (type) { | |
case "enum": | |
Set<String> set = fieldDefinition["values"]; | |
/* | |
// == Build a set to prevent multiple same values | |
final Set<String> set = {}; | |
for (final value in values) { | |
set.add(value); | |
} | |
*/ | |
return ListTile( | |
leading:prefixIcon, | |
title:Text(name), | |
trailing:DropdownButton<String>( | |
value: set.first, | |
onChanged: (newValue) { | |
//setState(() { | |
final _ = newValue!; | |
//}); | |
}, | |
items: set.map((value) { | |
return DropdownMenuItem<String>( | |
value: value, child: Text(value)); | |
}).toList()), | |
); | |
case "dateTime": | |
case "date": | |
DateTime dateMin = DateTime(1900); | |
DateTime? dateMax; | |
if (fieldDefinition["ageMin"] != null) { | |
late final int ageMin; | |
try { | |
ageMin = fieldDefinition["ageMin"] ?? 15; | |
} catch (e) { | |
ageMin = 15; | |
} | |
dateMax = DateTime.now().subtract(Duration(days: 365 * ageMin)); | |
} | |
return | |
ListTile( | |
title:TextFormField( | |
controller: controller, | |
readOnly: true, | |
decoration: InputDecoration( | |
icon: Padding(padding: const EdgeInsets.only(top:20),child:const Icon(Icons.calendar_today)), //icon of text field | |
labelText: fieldDefinition["label"] ?? name, | |
), | |
onTap: () async { | |
final pickedDate = await showDatePicker( | |
context: context, | |
initialDate: dateMax ?? DateTime.now(), | |
firstDate: | |
dateMin, //DateTime.now() - not to allow to choose before today. | |
lastDate: dateMax ?? DateTime.now()); | |
if (pickedDate != null) { | |
//debugPrint(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000 | |
String formattedDate = | |
DateFormat('yyyy-MM-dd').format(pickedDate); | |
//formatted date output using intl package => 2021-03-16 | |
debugPrint(formattedDate); | |
fieldDefinition["value"] = formattedDate; | |
if (!mounted) return; | |
setState(() { | |
controller.text = formattedDate; | |
}); | |
} | |
})); | |
case "int": | |
tit = const TextInputType.numberWithOptions(decimal: false); | |
break; | |
case "double": | |
tit = const TextInputType.numberWithOptions(decimal: true); | |
break; | |
case "string": | |
_maxLines = fieldDefinition["maxLines"]; | |
break; | |
default: | |
break; | |
} | |
return Padding( | |
padding: const EdgeInsets.symmetric(vertical: 10), | |
child: | |
ListTile( | |
//leading:prefixIcon, | |
trailing: unit, | |
title:TextFormField( | |
controller: controller, | |
keyboardType: tit, | |
maxLines: _maxLines, | |
decoration: InputDecoration( | |
labelText: fieldDefinition["label"] ?? name, | |
icon: prefixIcon, | |
// suffixIcon:unit, | |
), | |
/// Saves new value | |
onChanged: (value) { | |
fieldDefinition["value"] = value; | |
}, | |
))); | |
} | |
} | |
/* | |
/// The category widget in a gallery | |
class CategoryGalleryWidget extends StatelessWidget { | |
final String? imageUrl; | |
final ClassifiedAdSuperCategory? superCategory; | |
final ClassifiedAdCategory? category; | |
final int index; | |
final void Function()? onTap; | |
const CategoryGalleryWidget({ | |
super.key, | |
required this.superCategory, | |
required this.category, | |
required this.imageUrl, | |
required this.index, | |
this.onTap, | |
}); | |
@override | |
Widget build(BuildContext context) { | |
final size = GalleryOptions.categorySize(context); | |
final name = category?.toString() ?? superCategory?.toString(); | |
final List<ClassifiedAdCategory> listOfCategories = category == null | |
? (superCategory == null ? [] : superCategory!.allCategories) | |
: [category!]; | |
final int friezeIndex = index % 4; | |
const scale = 1.65; | |
// 0 1 2 3 | |
const List<double?> backgroundTop = [0, null, 0, null]; | |
const List<double?> backgroundBottom = [null, 0, null, 0]; | |
const List<double?> backgroundLeft = [null, null, 0, null]; | |
const List<double?> backgroundRight = [0, 0, null, 0]; | |
const List<double?> foregroundTop = [null, 0, null, 0]; | |
const List<double?> foregroundBottom = [0, null, 0, null]; | |
const List<double?> foregroundLeft = [0, 0, 0, 0]; | |
const List<double?> foregroundRight = [null, null, null, null]; | |
return GestureDetector( | |
onTap: onTap ?? | |
() => Navigator.of(context).push(MaterialPageRoute( | |
builder: (context) => listOfCategories.length == 1 | |
? ClassifiedAdGalleryScreen(categories: listOfCategories) | |
: SuperCategoryGalleryScreen( | |
superCategory: superCategory!))), | |
child: Container( | |
color: AppTheme.nightBlue.color, | |
width: size.width, | |
height: size.height, | |
margin: const EdgeInsets.only(right: 4), | |
padding: const EdgeInsets.all(0), | |
child: Stack(children: [ | |
// == Background image | |
if (true) | |
Positioned( | |
top: backgroundTop[friezeIndex], | |
bottom: backgroundBottom[friezeIndex], | |
right: backgroundRight[friezeIndex], | |
left: backgroundLeft[friezeIndex], | |
child: Image.asset( | |
"assets/images/[email protected]", | |
// width: size.width, | |
// height: size.height, | |
scale: scale // backgroundScale[friezeIndex], | |
//fit: BoxFit.none, | |
)), | |
// Transform.rotate( | |
// angle: -5, | |
// child: Container( | |
// decoration: BoxDecoration( | |
// borderRadius: BorderRadius.circular(20), | |
// color: AppTheme.green.color, | |
// ), | |
// width: size.width, | |
// height: size.height, | |
// ), | |
// ), | |
// == Simple image | |
if (imageUrl != null) | |
Positioned( | |
top: backgroundTop[friezeIndex], | |
bottom: backgroundBottom[friezeIndex], | |
right: backgroundRight[friezeIndex], | |
left: backgroundLeft[friezeIndex], | |
child: Image.asset( | |
imageUrl!, | |
// width: size.width, | |
// height: size.height, | |
scale: scale, | |
//fit: BoxFit.scaleDown, | |
)), | |
// == Foreground image | |
if (true) | |
Positioned( | |
top: foregroundTop[friezeIndex], | |
bottom: foregroundBottom[friezeIndex], | |
right: foregroundRight[friezeIndex], | |
left: foregroundLeft[friezeIndex], | |
child: Image.asset( | |
"assets/images/[email protected]", | |
// width: size.width, | |
// height: size.height, | |
scale: scale, //foregroundScale[friezeIndex], | |
//fit: BoxFit., | |
)), | |
// == Add title is required | |
if (name != null) | |
// Padding( | |
// padding: const EdgeInsets.all(5), | |
Center( | |
child: Text( | |
name.toUpperCase(), | |
textAlign: TextAlign.center, | |
style: Format.overlayTextStyle( | |
context, | |
style: Theme.of(context) | |
.textTheme | |
.titleSmall | |
?.copyWith(fontWeight: FontWeight.bold), | |
), | |
)), | |
]))); | |
} | |
} | |
*/ | |
//Avi's categories | |
// The classified ad category | |
enum ClassifiedAdSuperCategory { | |
vehicle, | |
realEstate, | |
vacation, | |
job, | |
fashion, | |
home, | |
multimedia, | |
hobby, | |
animal, | |
professional, | |
service, | |
food, | |
donation, | |
other, | |
; | |
factory ClassifiedAdSuperCategory.fromName(String name) => | |
values.firstWhere((x) => x.name == name, orElse: () => other); | |
/// Returns the name corresponding to the enum | |
@override | |
String toString() | |
=> this.name; | |
/*{ | |
switch (this) { | |
case vehicle: | |
return i18n_vehicle.i18n; | |
case realEstate: | |
return i18n_realEstate.i18n; | |
case job: | |
return i18n_job.i18n; | |
case vacation: | |
return i18n_vacation.i18n; | |
case fashion: | |
return i18n_fashion.i18n; | |
case home: | |
return i18n_home.i18n; | |
case multimedia: | |
return i18n_multimedia.i18n; | |
case hobby: | |
return i18n_hobby.i18n; | |
case animal: | |
return i18n_animal.i18n; | |
case professional: | |
return i18n_professional.i18n; | |
case service: | |
return i18n_service.i18n; | |
case food: | |
return i18n_food.i18n; | |
case donation: | |
return i18n_donation.i18n; | |
case other: | |
return i18n_other.i18n; | |
} | |
} | |
*/ | |
/// Returns the icon | |
IconData get iconData { | |
switch (this) { | |
case vehicle: | |
return Icons.drive_eta_sharp; | |
case realEstate: | |
return Icons.house; | |
case job: | |
return Icons.work; | |
case vacation: | |
return Icons.surfing; | |
case fashion: | |
return Icons.accessibility; | |
case home: | |
return Icons.blender; | |
case multimedia: | |
return Icons.devices_other; | |
case hobby: | |
return Icons.catching_pokemon; | |
case animal: | |
return Icons.bug_report; | |
case professional: | |
return Icons.agriculture; | |
case service: | |
return Icons.room_service; | |
case food: | |
return Icons.food_bank; | |
case donation: | |
return Icons.money; | |
case other: | |
return Icons.miscellaneous_services; | |
} | |
} | |
/// Returns the image url of the related image | |
String? get imageUrl { | |
switch (this) { | |
case vehicle: | |
return null; | |
//'assets/images/vehicle.jpg'; | |
case realEstate: | |
return 'assets/images/[email protected]'; //assets/images/realEstate.jpeg'; | |
case job: | |
return null; | |
//'assets/images/job.jpg'; | |
case vacation: | |
return null; | |
//"assets/images/other.jpg"; | |
case fashion: | |
return "assets/images/[email protected]"; //"assets/images/man.jpg"; | |
case home: | |
return null; | |
//'assets/images/house.jpg'; | |
case multimedia: | |
return "assets/images/[email protected]"; //'assets/images/entertainment.jpg'; | |
case hobby: | |
return null; | |
//"assets/images/other.jpg"; | |
case animal: | |
return null; | |
//"assets/images/animal.jpg"; | |
case professional: | |
case service: | |
case food: | |
case donation: | |
case other: | |
return null; | |
//"assets/images/other.jpg"; | |
} | |
} | |
/// Returns the list of all categories for this super category | |
List<ClassifiedAdCategory> get allCategories { | |
return ClassifiedAdCategory.values | |
.where((c) => c.superCategory == this) | |
.toList(); | |
} | |
/* | |
/// Returns the gallery widgets of the category ad | |
Widget asGalleryWidget( | |
BuildContext context, { | |
required int index, | |
void Function()? onTap, | |
}) { | |
return CategoryGalleryWidget( | |
superCategory: this, | |
category: null, | |
imageUrl: imageUrl, | |
index: index, | |
onTap: onTap, | |
); | |
}*/ | |
} | |
/// The classified ad category | |
enum ClassifiedAdCategory { | |
// vehicle | |
car, | |
motorcycle, | |
caravanning, | |
utility, | |
electricScooter, | |
bike, | |
truck, | |
boat, | |
autoMotoEquipment, | |
// realEstate | |
realEstateSale, | |
rental, | |
flatsharing, | |
officeAndShop, | |
// vacation | |
rentalAndGite, | |
guestRoom, | |
campsite, | |
unusualAccommodation, | |
hotel, | |
//Job | |
jobOffer, | |
application, | |
//Fashion | |
clothe, | |
shoe, | |
accessoryAndJewelry, | |
//home | |
furnishing, | |
homeAppliance, | |
tableArt, | |
decoration, | |
householdLinen, | |
diy, | |
gardening, | |
//multimedia | |
computerScience, | |
consoleAndVideoGame, | |
pictureAndSound, | |
telephone, | |
//Hobbies | |
cdDvd, | |
book, | |
musicInstrument, | |
gameAndToy, | |
animal, | |
//professionnalHArdware | |
professionalMaterial, | |
medicalEquipment, | |
agriculturalMaterial, | |
constructionEquipmentStructuralWork, | |
officeSupply, | |
//services, | |
plumber, | |
locksmith, | |
glazier, | |
gardener, | |
cleaning, | |
//restoration | |
fastFood, | |
gastronomy, | |
donation, | |
other, | |
; | |
factory ClassifiedAdCategory.fromName(String name) => | |
values.firstWhere((x) => x.name == name, orElse: () => other); | |
/// Returns the name corresponding to the enum | |
@override | |
String toString() | |
=> this.name; | |
/*{ | |
switch (this) { | |
// vehicle | |
case car: | |
return i18n_car.i18n; | |
case motorcycle: | |
return i18n_motorcycle.i18n; | |
case caravanning: | |
return i18n_caravanning.i18n; | |
case utility: | |
return i18n_utility.i18n; | |
case electricScooter: | |
return i18n_electricScooter.i18n; | |
case bike: | |
return i18n_bike.i18n; | |
case truck: | |
return i18n_truck.i18n; | |
case boat: | |
return i18n_boat.i18n; | |
case autoMotoEquipment: | |
return i18n_autoMotoEquipment.i18n; | |
// realEstate | |
case realEstateSale: | |
return i18n_realEstateSale.i18n; | |
case rental: | |
return i18n_rental.i18n; | |
case flatsharing: | |
return i18n_flatsharing.i18n; | |
case officeAndShop: | |
return i18n_officeAndShop.i18n; | |
// vacation | |
case rentalAndGite: | |
return i18n_rentalAndGite.i18n; | |
case guestRoom: | |
return i18n_guestRoom.i18n; | |
case campsite: | |
return i18n_campsite.i18n; | |
case unusualAccommodation: | |
return i18n_unusualAccommodation.i18n; | |
case hotel: | |
return i18n_hotel.i18n; | |
//Job | |
case jobOffer: | |
return i18n_jobOffer.i18n; | |
case application: | |
return i18n_application.i18n; | |
//Fashion | |
case clothe: | |
return i18n_clothe.i18n; | |
case shoe: | |
return i18n_shoe.i18n; | |
case accessoryAndJewelry: | |
return i18n_accessoryAndJewelry.i18n; | |
//home | |
case furnishing: | |
return i18n_furnishing.i18n; | |
case homeAppliance: | |
return i18n_homeAppliance.i18n; | |
case tableArt: | |
return i18n_tableArt.i18n; | |
case decoration: | |
return i18n_decoration.i18n; | |
case householdLinen: | |
return i18n_householdLinen.i18n; | |
case diy: | |
return i18n_diy.i18n; | |
case gardening: | |
return i18n_gardening.i18n; | |
//multimedia | |
case computerScience: | |
return i18n_computerScience.i18n; | |
case consoleAndVideoGame: | |
return i18n_consoleAndVideoGame.i18n; | |
case pictureAndSound: | |
return i18n_pictureAndSound.i18n; | |
case telephone: | |
return i18n_telephone.i18n; | |
//Hobbies | |
case cdDvd: | |
return i18n_cdDvd.i18n; | |
case book: | |
return i18n_book.i18n; | |
case musicInstrument: | |
return i18n_musicInstrument.i18n; | |
case gameAndToy: | |
return i18n_gameAndToy.i18n; | |
//animal, | |
case animal: | |
return i18n_animal.i18n; | |
// professionnalHardware | |
case professionalMaterial: | |
return i18n_professionalHardware.i18n; | |
case medicalEquipment: | |
return i18n_medicalEquipment.i18n; | |
case agriculturalMaterial: | |
return i18n_agriculturalHardware.i18n; | |
case constructionEquipmentStructuralWork: | |
return i18n_constructionEquipmentStructuralWork.i18n; | |
case officeSupply: | |
return i18n_officeSupply.i18n; | |
//services, | |
case plumber: | |
return i18n_plumber.i18n; | |
case locksmith: | |
return i18n_locksmith.i18n; | |
case glazier: | |
return i18n_glazier.i18n; | |
case gardener: | |
return i18n_gardener.i18n; | |
case cleaning: | |
return i18n_cleaning.i18n; | |
//restoration | |
case fastFood: | |
return i18n_fastFood.i18n; | |
case gastronomy: | |
return i18n_gastronomy.i18n; | |
// donation | |
case donation: | |
return i18n_donation.i18n; | |
// other | |
case other: | |
return i18n_other.i18n; | |
} | |
} | |
*/ | |
/// Returns the super category of the category | |
ClassifiedAdSuperCategory get superCategory { | |
switch (this) { | |
// vehicle | |
case car: | |
case motorcycle: | |
case caravanning: | |
case utility: | |
case electricScooter: | |
case bike: | |
case truck: | |
case boat: | |
case autoMotoEquipment: | |
return ClassifiedAdSuperCategory.vehicle; | |
// realEstate | |
case realEstateSale: | |
case rental: | |
case flatsharing: | |
case officeAndShop: | |
return ClassifiedAdSuperCategory.realEstate; | |
// vacation | |
case rentalAndGite: | |
case guestRoom: | |
case campsite: | |
case unusualAccommodation: | |
case hotel: | |
return ClassifiedAdSuperCategory.vacation; | |
//Job | |
case jobOffer: | |
case application: | |
return ClassifiedAdSuperCategory.job; | |
//Fashion | |
case clothe: | |
case shoe: | |
case accessoryAndJewelry: | |
return ClassifiedAdSuperCategory.fashion; | |
//home | |
case furnishing: | |
case homeAppliance: | |
case tableArt: | |
case decoration: | |
case householdLinen: | |
case diy: | |
case gardening: | |
return ClassifiedAdSuperCategory.home; | |
//multimedia | |
case computerScience: | |
case consoleAndVideoGame: | |
case pictureAndSound: | |
case telephone: | |
return ClassifiedAdSuperCategory.multimedia; | |
//Hobbies | |
case cdDvd: | |
case book: | |
case musicInstrument: | |
case gameAndToy: | |
return ClassifiedAdSuperCategory.hobby; | |
//animal, | |
case animal: | |
return ClassifiedAdSuperCategory.animal; | |
// professional | |
case professionalMaterial: | |
case medicalEquipment: | |
case agriculturalMaterial: | |
case constructionEquipmentStructuralWork: | |
case officeSupply: | |
return ClassifiedAdSuperCategory.professional; | |
//services, | |
case plumber: | |
case locksmith: | |
case glazier: | |
case gardener: | |
case cleaning: | |
return ClassifiedAdSuperCategory.service; | |
//food | |
case fastFood: | |
case gastronomy: | |
return ClassifiedAdSuperCategory.food; | |
// donation | |
case donation: | |
return ClassifiedAdSuperCategory.donation; | |
// other | |
case other: | |
return ClassifiedAdSuperCategory.other; | |
} | |
} | |
/// Returns the image url of the related image | |
String? get imageUrl { | |
final category = superCategory; | |
return category.imageUrl; | |
} | |
/// Returns the enum picker widget | |
static Widget dropDownPicker( | |
{required ClassifiedAdCategory? value, | |
required void Function(ClassifiedAdCategory?)? onChanged}) { | |
return DropdownButton<ClassifiedAdCategory>( | |
hint: const Text("Category"), | |
value: value, | |
items: ClassifiedAdCategory.values.map((value) { | |
return DropdownMenuItem<ClassifiedAdCategory>( | |
value: value, | |
child: Text(value.toString()), | |
); | |
}).toList(), | |
onChanged: onChanged, | |
); | |
} | |
/// Retuns the wheel enum picker | |
static Widget wheelPicker( | |
{required ClassifiedAdCategory? value, | |
required void Function(ClassifiedAdCategory?)? onChanged}) { | |
const list = ClassifiedAdCategory.values; | |
return ListWheelScrollView( | |
physics: const BouncingScrollPhysics(), | |
itemExtent: 50, | |
diameterRatio: 0.6, | |
//offAxisFraction: -0.4, | |
squeeze: 1.8, | |
//useMagnifier: true, | |
//overAndUnderCenterOpacity: 0.8, | |
clipBehavior: Clip.antiAlias, | |
onSelectedItemChanged: (value) => onChanged?.call(list[value]), | |
children: list.map((c) => Text("$c")).toList()); | |
} | |
/// Returns the list picker with folding super category | |
static Widget foldingSuperCategoryListPicker(BuildContext context, | |
{ClassifiedAdCategory? value, | |
required Function(ClassifiedAdCategory) onTap}) { | |
return /*Expanded( | |
child:*/ ListView( | |
physics: const BouncingScrollPhysics(), | |
children: ClassifiedAdSuperCategory.values.map((s) { | |
// == The categories | |
final children = ClassifiedAdCategory.values | |
.where((c) => c.superCategory == s) | |
.map((c) => ListTile( | |
leading: Icon(s.iconData), | |
title: Text("$c", | |
style: Theme.of(context).textTheme.headline6), | |
onTap: () { | |
Navigator.of(context).pop(); | |
onTap(c); | |
})) | |
.toList(); | |
// == The super category | |
bool initiallyExpanded = false; | |
if (value != null) { | |
initiallyExpanded = value.superCategory == s; | |
} | |
return ExpansionTile( | |
initiallyExpanded: initiallyExpanded, | |
leading: Icon(s.iconData), | |
childrenPadding: const EdgeInsets.only(left: 20), | |
title: | |
Text("$s", style: Theme.of(context).textTheme.headline6), | |
children: children); | |
}).toList(), | |
//) | |
); | |
} | |
/// Open the list picker in a modal bottom sheet with super category being unfoldable by the user | |
static showModalBottomSheetListPicker(BuildContext context, | |
{ClassifiedAdCategory? value, | |
required Function(ClassifiedAdCategory) onTap}) { | |
showModalBottomSheet(context:context, builder:(context)=> | |
Column(children:[ | |
Text("Select a category",style:Theme.of(context).textTheme.headlineSmall), | |
foldingSuperCategoryListPicker(context, value: value, onTap: (c) { | |
Navigator.pop(context); | |
// == Tell the caller | |
onTap(c); | |
// == Tell the user | |
ScaffoldMessenger.of(context).showSnackBar(SnackBar( | |
content: Text("You selected the ”$c” (${c.name}) category", | |
style: const TextStyle(color: Colors.white)), | |
backgroundColor: Colors.green, | |
)); | |
}), | |
])); | |
} | |
/// ================== NATHAN ==================== | |
/// ================== NATHAN ==================== | |
/// ================== NATHAN ==================== | |
/// Returns category deinition metadata | |
Map<String, Map<String, dynamic>> metaData() { | |
final colors = { | |
"type": "enum", | |
"values": [ | |
"black", | |
"white", | |
"grey", | |
"blue", | |
"red", | |
"green", | |
"pink", | |
"orange", | |
"yellow", | |
"brown", | |
"purple" | |
] | |
}; | |
final states = { | |
"type": "enum", | |
"values": [ | |
"used", | |
"new", | |
] | |
}; | |
switch (this) { | |
case car: | |
const energies = { | |
"type": "enum", | |
"values": { | |
"electric", | |
"hybrid", | |
"reloaded hybrid", | |
"diesel", | |
"gas", | |
"hydrogen", | |
"gpl", | |
"lng", | |
"other" | |
}, | |
}; | |
const brands = { | |
"type": "enum", | |
"values": { | |
"mercedes-benz", | |
"bmw", | |
"renault", | |
"citroën", | |
"peugeot", | |
"opel", | |
"vw", | |
"simca", | |
"ford", | |
"gm", | |
"cadillac", | |
"other" | |
}, | |
}; | |
const categories = { | |
"type": "enum", | |
"values": { | |
"sedan", | |
"suv", | |
"pickup", | |
"truck", | |
"semi truck", | |
"bicycle", | |
"motocycle", | |
"other" | |
}, | |
}; | |
return { | |
"category": categories, | |
"energy": energies, | |
"brand": brands, | |
"model": {"type": "string"}, | |
"date": { | |
"type": "dateTime", | |
}, | |
}; | |
case realEstateSale: | |
const roomSizes = { | |
"type": "enum", | |
"values": {"1", "2", "3", "4", "5", "6", "more than 6"}, | |
"unit": "room" | |
}; | |
return { | |
"surface": { | |
"type": "double", | |
"unit": "m2", | |
"icon": Icons.shopping_cart_outlined, | |
}, | |
"build date": { | |
"type": "dateTime", | |
}, | |
//"price": {"type": "double", "unit": "€"}, | |
"categories": { | |
"house": roomSizes, | |
"appartement": roomSizes, | |
"terrain": { | |
"type": "enum", | |
"values": {"buildable", "not buildable"} | |
}, | |
"parking": { | |
"size": { | |
"type": "enum", | |
"values": {"normal", "disabled", "double"} | |
} | |
}, | |
"exception": roomSizes, | |
}, | |
}; | |
case jobOffer: | |
case application: | |
return { | |
"type": { | |
"type": "enum", | |
"values": [ | |
"CDI", | |
"CDD", | |
"stage", | |
"freelance", | |
] | |
} | |
}; | |
case computerScience: | |
return { | |
"brand": {"type": "string"}, | |
"build date": { | |
"type": "dateTime", | |
}, | |
//"price": {"type": "double", "unit": "€"}, | |
"type": { | |
"type": "enum", | |
"values": [ | |
"laptop", | |
"desktop", | |
"tablet", | |
"phone", | |
"watch", | |
"headphone", | |
"others", | |
] | |
} | |
}; | |
case furnishing: | |
return { | |
"long": { | |
"type": "double", | |
}, | |
"width": {"type": "double"}, | |
"height": {"type": "double"}, | |
}; | |
case clothe: | |
//case man: | |
final shoeSizes = { | |
"type": "enum", | |
"values": List<int>.generate(47 - 36, (index) => 36 + index) | |
.map((e) => "EU: $e") | |
.toList() | |
}; | |
const clotheSize = { | |
"type": "enum", | |
"values": [ | |
"XXS", | |
"XS", | |
"S", | |
"M", | |
"L", | |
"XL", | |
"XXL", | |
] | |
}; | |
final shoeSettings = { | |
"color": colors, | |
"size": shoeSizes, | |
"state": states | |
}; | |
final clotheSettings = { | |
"color": colors, | |
"size": clotheSize, | |
"state": states | |
}; | |
final snearkerBrand = { | |
"addidas": shoeSettings, | |
"nike": shoeSettings, | |
"new balance": shoeSettings, | |
"le coc sportif": shoeSettings | |
}; | |
//.map((brand) => e: shoeSettings) | |
final c = { | |
"shoe": { | |
"sneaker": snearkerBrand, | |
"boot": shoeSettings, | |
"others": shoeSettings, | |
}, | |
"jeans": clotheSettings, | |
"trousses": clotheSettings, | |
"jacket": clotheSettings, | |
"accessories": { | |
"glasses": {"state": states}, | |
"cape": {"state": states}, | |
"casket": {"state": states}, | |
} | |
}; | |
return c; | |
/* | |
case baby: | |
return { | |
"size": { | |
"type": "enum", | |
"values": [ | |
"0 month", | |
"1 month", | |
"3 months", | |
"6 months", | |
"9 months", | |
"12 months", | |
"18 months", | |
"24 months", | |
"36 months" | |
], | |
"unit": "months" | |
}, | |
"color": { | |
"type": "color", | |
}, | |
"type": { | |
"type": "enum", | |
"values": [ | |
"used", | |
"new", | |
] | |
}, | |
};*/ | |
case animal: | |
return { | |
"type": { | |
"type": "enum", | |
"values": [ | |
"cat", | |
"dog", | |
"rodent", | |
"bird", | |
"reptile", | |
"insect", | |
"other" | |
] | |
}, | |
"color": { | |
"type": "color", | |
}, | |
}; /* | |
case hobby: | |
return { | |
"type": { | |
"type": "enum", | |
"values": [ | |
"disk", | |
"book", | |
"video game", | |
"game", | |
"concert", | |
"sport", | |
"other" | |
] | |
}, | |
};*/ | |
case other: | |
default: | |
return {}; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment