Skip to content

Commit

Permalink
[#25] feat: implement add recipe UX
Browse files Browse the repository at this point in the history
  • Loading branch information
Soogyo-In committed Jan 7, 2023
1 parent 5fdc4c4 commit c0b235c
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 107 deletions.
61 changes: 4 additions & 57 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,72 +1,19 @@
import 'package:collection/collection.dart';
import 'package:cooking_calulator/recipe_resource.dart';
import 'package:cooking_calulator/page/recipe/recipe_page.dart';
import 'package:domain/domain.dart';
import 'package:cooking_calulator/page/recipe/recipe_list_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
runApp(const ProviderScope(child: App()));
}

class App extends StatefulWidget {
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);

@override
State<App> createState() => _AppState();
}

class _AppState extends State<App> {
List<Recipe> recipes = [];
Map<int, Ingredient> ingredientById = {};

@override
Widget build(BuildContext context) {
return MaterialApp(
return const MaterialApp(
title: 'Cooking Calculator',
home: Builder(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: const Text('레시피'),
),
body: ListView.separated(
shrinkWrap: true,
itemCount: recipes.length,
itemBuilder: (context, index) {
final recipe = recipes[index];
final ingredientIdSet = {
...recipe.countByIngredientId.keys,
...recipe.massByIngredientId.keys,
...recipe.volumeByIngredientId.keys,
};
return Card(
child: InkWell(
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => RecipePage(
recipe: slowRoasetedPorkBellyRecipe,
),
)),
child: Column(
children: [
Text(recipe.name),
Wrap(
children: ingredientIdSet
.map((id) => ingredientById[id]?.name)
.whereNotNull()
.map((name) => Chip(label: Text(name)))
.toList(),
)
],
),
),
);
},
separatorBuilder: (context, index) => const Divider(),
),
);
},
),
home: RecipeListPage(),
);
}
}
83 changes: 83 additions & 0 deletions lib/page/recipe/add/recipe_add_direction_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';

class RecipeAddDirectionPage extends StatefulWidget {
const RecipeAddDirectionPage({super.key, this.stepCount = 0});

final int stepCount;

@override
State<RecipeAddDirectionPage> createState() => _RecipeAddDirectionPageState();
}

class _RecipeAddDirectionPageState extends State<RecipeAddDirectionPage> {
final _ingredientTextController = TextEditingController();
final _ingredientTextFieldFocusNode = FocusNode();
final _descriptionTextController = TextEditingController();
final _ingredients = <String>{};

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('단계 ${widget.stepCount}')),
body: SafeArea(
child: Column(
children: [
TextField(
controller: _ingredientTextController,
focusNode: _ingredientTextFieldFocusNode,
decoration: const InputDecoration(hintText: '재료'),
autofocus: true,
onSubmitted: (value) {
setState(() {
_ingredients.add(value);
});
_ingredientTextController.clear();
_ingredientTextFieldFocusNode.requestFocus();
},
),
Wrap(
spacing: 8.0,
children: _ingredients
.map(
(name) => Chip(label: Text(name)),
)
.toList(),
),
Expanded(
child: TextField(
controller: _descriptionTextController,
decoration: const InputDecoration(hintText: '설명'),
maxLines: null,
expands: true,
),
),
ButtonBar(
children: [
OutlinedButton(
onPressed: _onNextButtonPressed,
child: const Text('단계 추가'),
),
ElevatedButton(
onPressed: _onSubmitButtonPressed,
child: const Text('완료'),
),
],
),
],
),
),
);
}

void _onNextButtonPressed() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => RecipeAddDirectionPage(
stepCount: widget.stepCount + 1,
),
));
}

void _onSubmitButtonPressed() {
Navigator.of(context).popUntil((route) => route.isFirst);
}
}
56 changes: 56 additions & 0 deletions lib/page/recipe/add/recipe_add_title_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'package:cooking_calulator/page/recipe/add/recipe_add_direction_page.dart';
import 'package:flutter/material.dart';

class RecipeAddTitlePage extends StatefulWidget {
const RecipeAddTitlePage({super.key});

@override
State<RecipeAddTitlePage> createState() => _RecipeAddTitlePageState();
}

class _RecipeAddTitlePageState extends State<RecipeAddTitlePage> {
final _titleTextController = TextEditingController();
final _descriptionTextController = TextEditingController();
final _descriptionTextFieldFocusNode = FocusNode();

bool get _nextButtonEnabled => _titleTextController.text.isNotEmpty;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('레시피 추가')),
body: SafeArea(
child: Column(
children: [
TextField(
controller: _titleTextController,
decoration: const InputDecoration(hintText: '이름'),
autofocus: true,
onChanged: (_) => setState(() {}),
onSubmitted: (_) => _descriptionTextFieldFocusNode.requestFocus(),
),
Expanded(
child: TextField(
controller: _descriptionTextController,
focusNode: _descriptionTextFieldFocusNode,
decoration: const InputDecoration(hintText: '설명'),
maxLines: null,
expands: true,
),
),
ElevatedButton(
onPressed: _nextButtonEnabled ? _onNextButtonPressed : null,
child: const Text('다음'),
),
],
),
),
);
}

void _onNextButtonPressed() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const RecipeAddDirectionPage(),
));
}
}
50 changes: 0 additions & 50 deletions lib/page/recipe/recipe_edit_page.dart

This file was deleted.

73 changes: 73 additions & 0 deletions lib/page/recipe/recipe_list_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:collection/collection.dart';
import 'package:cooking_calulator/page/recipe/recipe_page.dart';
import 'package:domain/domain.dart';
import 'package:flutter/material.dart';

import 'add/recipe_add_title_page.dart';

class RecipeListPage extends StatefulWidget {
const RecipeListPage({super.key});

@override
State<RecipeListPage> createState() => _RecipeListPageState();
}

class _RecipeListPageState extends State<RecipeListPage> {
List<Recipe> recipes = [];
Map<int, Ingredient> ingredientById = {};

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('레시피'),
),
body: ListView.separated(
shrinkWrap: true,
itemCount: recipes.length,
itemBuilder: (context, index) {
final recipe = recipes[index];
final ingredientIdSet = {
...recipe.countByIngredientId.keys,
...recipe.massByIngredientId.keys,
...recipe.volumeByIngredientId.keys,
};
return Card(
child: InkWell(
onTap: () => _onRecipeCardTapped(recipe),
child: Column(
children: [
Text(recipe.name),
Wrap(
children: ingredientIdSet
.map((id) => ingredientById[id]?.name)
.whereNotNull()
.map((name) => Chip(label: Text(name)))
.toList(),
)
],
),
),
);
},
separatorBuilder: (context, index) => const Divider(),
),
floatingActionButton: FloatingActionButton(
onPressed: _onAddRecpieButtonPressed,
child: const Icon(Icons.add),
),
);
}

void _onRecipeCardTapped(Recipe recipe) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => RecipePage(recipe: recipe),
));
}

void _onAddRecpieButtonPressed() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const RecipeAddTitlePage(),
));
}
}

0 comments on commit c0b235c

Please sign in to comment.