-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a9c82b4
commit 8131668
Showing
4 changed files
with
152 additions
and
91 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,108 +1,150 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:spotkin_flutter/app_core.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
class IngredientManagementWidget extends StatefulWidget { | ||
class IngredientForm extends StatefulWidget { | ||
final List<Ingredient> initialIngredients; | ||
final Function(List<Ingredient>) onIngredientsChanged; | ||
|
||
const IngredientManagementWidget({ | ||
const IngredientForm({ | ||
Key? key, | ||
required this.initialIngredients, | ||
required this.onIngredientsChanged, | ||
}) : super(key: key); | ||
|
||
@override | ||
_IngredientManagementWidgetState createState() => _IngredientManagementWidgetState(); | ||
_IngredientFormState createState() => _IngredientFormState(); | ||
} | ||
|
||
class _IngredientManagementWidgetState extends State<IngredientManagementWidget> { | ||
late List<Ingredient> _ingredients; | ||
class _IngredientFormState extends State<IngredientForm> { | ||
final _formKey = GlobalKey<FormState>(); | ||
late List<IngredientFormRow> _ingredientRows; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_ingredients = List.from(widget.initialIngredients); | ||
_initIngredientRows(); | ||
} | ||
|
||
void _initIngredientRows() { | ||
_ingredientRows = widget.initialIngredients.map((ingredient) => | ||
IngredientFormRow( | ||
playlistController: TextEditingController(text: ingredient.sourcePlaylistId), | ||
quantityController: TextEditingController(text: ingredient.quantity.toString()), | ||
) | ||
).toList(); | ||
if (_ingredientRows.isEmpty) { | ||
_addNewRow(); | ||
} | ||
} | ||
|
||
@override | ||
void didUpdateWidget(IngredientManagementWidget oldWidget) { | ||
void didUpdateWidget(IngredientForm oldWidget) { | ||
super.didUpdateWidget(oldWidget); | ||
if (widget.initialIngredients != oldWidget.initialIngredients) { | ||
setState(() { | ||
_ingredients = List.from(widget.initialIngredients); | ||
}); | ||
_initIngredientRows(); | ||
} | ||
} | ||
|
||
void _updateIngredient(int index, Ingredient updatedIngredient) { | ||
void _addNewRow() { | ||
setState(() { | ||
_ingredients[index] = updatedIngredient; | ||
widget.onIngredientsChanged(_ingredients); | ||
_ingredientRows.add(IngredientFormRow( | ||
playlistController: TextEditingController(), | ||
quantityController: TextEditingController(), | ||
)); | ||
}); | ||
} | ||
|
||
void _removeIngredient(int index) { | ||
setState(() { | ||
_ingredients.removeAt(index); | ||
widget.onIngredientsChanged(_ingredients); | ||
_ingredientRows.removeAt(index); | ||
}); | ||
} | ||
|
||
void _submitAndAddIngredient() { | ||
if (_formKey.currentState!.validate()) { | ||
List<Ingredient> updatedIngredients = _ingredientRows.map((row) => | ||
Ingredient( | ||
sourcePlaylistName: '', // You might want to update this if needed | ||
sourcePlaylistId: row.playlistController.text, | ||
quantity: int.tryParse(row.quantityController.text) ?? 0, | ||
) | ||
).toList(); | ||
|
||
widget.onIngredientsChanged(updatedIngredients); | ||
_addNewRow(); | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
Text('Ingredients', style: Theme.of(context).textTheme.titleMedium), | ||
..._ingredients.asMap().entries.map((entry) { | ||
int idx = entry.key; | ||
Ingredient ingredient = entry.value; | ||
return Row( | ||
children: [ | ||
Expanded( | ||
child: TextFormField( | ||
key: ValueKey('sourcePlaylistId_$idx'), | ||
initialValue: ingredient.sourcePlaylistId, | ||
decoration: const InputDecoration( | ||
labelText: 'Source playlist link', | ||
hintText: 'Enter Spotify playlist link or ID', | ||
return Form( | ||
key: _formKey, | ||
child: Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
Text('Ingredients', style: Theme.of(context).textTheme.titleMedium), | ||
..._ingredientRows.asMap().entries.map((entry) { | ||
int idx = entry.key; | ||
IngredientFormRow row = entry.value; | ||
return Row( | ||
children: [ | ||
Expanded( | ||
child: TextFormField( | ||
controller: row.playlistController, | ||
decoration: const InputDecoration( | ||
labelText: 'Source playlist link', | ||
hintText: 'Enter Spotify playlist link or ID', | ||
), | ||
validator: Utils.validateSpotifyPlaylistInput, | ||
), | ||
validator: Utils.validateSpotifyPlaylistInput, | ||
onChanged: (value) { | ||
_updateIngredient(idx, ingredient.copyWith(sourcePlaylistId: value)); | ||
}, | ||
), | ||
), | ||
const SizedBox(width: 10), | ||
Expanded( | ||
child: TextFormField( | ||
key: ValueKey('quantity_$idx'), | ||
initialValue: ingredient.quantity.toString(), | ||
decoration: const InputDecoration(labelText: 'Quantity'), | ||
keyboardType: TextInputType.number, | ||
onChanged: (value) { | ||
_updateIngredient(idx, ingredient.copyWith(quantity: int.tryParse(value) ?? 0)); | ||
}, | ||
const SizedBox(width: 10), | ||
Expanded( | ||
child: TextFormField( | ||
controller: row.quantityController, | ||
decoration: const InputDecoration(labelText: 'Quantity'), | ||
keyboardType: TextInputType.number, | ||
validator: (value) { | ||
if (value == null || value.isEmpty || int.tryParse(value) == null) { | ||
return 'Please enter a valid number'; | ||
} | ||
return null; | ||
}, | ||
), | ||
), | ||
), | ||
IconButton( | ||
icon: const Icon(Icons.delete), | ||
onPressed: () => _removeIngredient(idx), | ||
), | ||
|
||
], | ||
); | ||
}), | ||
ElevatedButton( | ||
onPressed: () { | ||
setState(() { | ||
_ingredients.add(Ingredient(sourcePlaylistName: '', sourcePlaylistId: '', quantity: 0)); | ||
widget.onIngredientsChanged(_ingredients); | ||
}); | ||
}, | ||
child: const Text('Add Ingredient'), | ||
), | ||
], | ||
IconButton( | ||
icon: const Icon(Icons.delete), | ||
onPressed: () => _removeIngredient(idx), | ||
), | ||
], | ||
); | ||
}), | ||
ElevatedButton( | ||
onPressed: _submitAndAddIngredient, | ||
child: const Text('Add Ingredient'), | ||
), | ||
], | ||
), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
for (var row in _ingredientRows) { | ||
row.playlistController.dispose(); | ||
row.quantityController.dispose(); | ||
} | ||
super.dispose(); | ||
} | ||
} | ||
|
||
class IngredientFormRow { | ||
final TextEditingController playlistController; | ||
final TextEditingController quantityController; | ||
|
||
IngredientFormRow({ | ||
required this.playlistController, | ||
required this.quantityController, | ||
}); | ||
} |
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