MEnambahkan fitur tutorial
This commit is contained in:
parent
1a5cc31678
commit
e81d566892
|
@ -67,7 +67,7 @@ class RecipeFullItem extends StatelessWidget {
|
||||||
const Icon(Icons.timer, size: 16),
|
const Icon(Icons.timer, size: 16),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
'${recipe.cookTime ?? 0} menit',
|
'${recipe.prepTime ?? 0} menit',
|
||||||
style: TTCommonsTextStyles.textSm.textRegular(),
|
style: TTCommonsTextStyles.textSm.textRegular(),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
|
@ -12,6 +12,8 @@ class RecipeModel {
|
||||||
String? title;
|
String? title;
|
||||||
String? description;
|
String? description;
|
||||||
String? image;
|
String? image;
|
||||||
|
String? difficulity;
|
||||||
|
double? confidence;
|
||||||
List<Ingredient>? ingredients;
|
List<Ingredient>? ingredients;
|
||||||
List<String>? instructions;
|
List<String>? instructions;
|
||||||
int? prepTime;
|
int? prepTime;
|
||||||
|
@ -49,6 +51,8 @@ class RecipeModel {
|
||||||
cookTime: cookTime,
|
cookTime: cookTime,
|
||||||
servings: servings,
|
servings: servings,
|
||||||
utensils: utensils,
|
utensils: utensils,
|
||||||
|
difficulity: difficulity,
|
||||||
|
confidence: confidence
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ RecipeModel _$RecipeModelFromJson(Map<String, dynamic> json) => RecipeModel(
|
||||||
utensils: (json['utensils'] as List<dynamic>?)
|
utensils: (json['utensils'] as List<dynamic>?)
|
||||||
?.map((e) => e as String)
|
?.map((e) => e as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
)
|
||||||
|
..difficulity = json['difficulity'] as String?
|
||||||
|
..confidence = (json['confidence'] as num?)?.toDouble();
|
||||||
|
|
||||||
Map<String, dynamic> _$RecipeModelToJson(RecipeModel instance) =>
|
Map<String, dynamic> _$RecipeModelToJson(RecipeModel instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
|
@ -31,6 +33,8 @@ Map<String, dynamic> _$RecipeModelToJson(RecipeModel instance) =>
|
||||||
'title': instance.title,
|
'title': instance.title,
|
||||||
'description': instance.description,
|
'description': instance.description,
|
||||||
'image': instance.image,
|
'image': instance.image,
|
||||||
|
'difficulity': instance.difficulity,
|
||||||
|
'confidence': instance.confidence,
|
||||||
'ingredients': instance.ingredients,
|
'ingredients': instance.ingredients,
|
||||||
'instructions': instance.instructions,
|
'instructions': instance.instructions,
|
||||||
'prepTime': instance.prepTime,
|
'prepTime': instance.prepTime,
|
||||||
|
|
|
@ -8,6 +8,8 @@ class Recipe {
|
||||||
String? title;
|
String? title;
|
||||||
String? description;
|
String? description;
|
||||||
String? image;
|
String? image;
|
||||||
|
String? difficulity;
|
||||||
|
double? confidence;
|
||||||
List<Ingredient>? ingredients;
|
List<Ingredient>? ingredients;
|
||||||
List<String>? instructions;
|
List<String>? instructions;
|
||||||
int? prepTime;
|
int? prepTime;
|
||||||
|
@ -26,5 +28,7 @@ class Recipe {
|
||||||
this.cookTime,
|
this.cookTime,
|
||||||
this.servings,
|
this.servings,
|
||||||
this.utensils,
|
this.utensils,
|
||||||
|
this.difficulity,
|
||||||
|
this.confidence
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
|
|
||||||
|
List<TargetFocus> createTargets({
|
||||||
|
required GlobalKey keyBottomNavigation1,
|
||||||
|
required GlobalKey keyBottomNavigation2,
|
||||||
|
required GlobalKey keyBottomNavigation3,
|
||||||
|
}) {
|
||||||
|
List<TargetFocus> targets = [];
|
||||||
|
targets.add(
|
||||||
|
TargetFocus(
|
||||||
|
identify: "keyBottomNavigation1",
|
||||||
|
keyTarget: keyBottomNavigation1,
|
||||||
|
color: Colors.black38,
|
||||||
|
alignSkip: Alignment.topRight,
|
||||||
|
contents: [
|
||||||
|
TargetContent(
|
||||||
|
align: ContentAlign.top,
|
||||||
|
builder: (context, controller) {
|
||||||
|
return const Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Deteksi Resep",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8,),
|
||||||
|
Text(
|
||||||
|
"Tekan tombol berikut untuk mengambil foto bahan makanan dari kamera ataupun galeri",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
targets.add(
|
||||||
|
TargetFocus(
|
||||||
|
identify: "keyBottomNavigation3",
|
||||||
|
keyTarget: keyBottomNavigation3,
|
||||||
|
color: Colors.black38,
|
||||||
|
alignSkip: Alignment.topLeft,
|
||||||
|
contents: [
|
||||||
|
TargetContent(
|
||||||
|
align: ContentAlign.bottom,
|
||||||
|
builder: (context, controller) {
|
||||||
|
return const Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Pengaturan Alat Memasak Yang Dimiliki",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8,),
|
||||||
|
Text(
|
||||||
|
"Tekan tombol berikut untuk mengatur dan menambahkan alat-alat memasak yang kamu miliki di dapurmu",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return targets;
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
@override
|
@override
|
||||||
Widget? floatingActionButton() {
|
Widget? floatingActionButton() {
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
|
key: controller.cameraKey,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
controller.navigateToRecipeDetection();
|
controller.navigateToRecipeDetection();
|
||||||
},
|
},
|
||||||
|
@ -33,6 +34,11 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
controller.getPageContext(context);
|
||||||
|
return _buildBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBody(){
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -43,7 +49,7 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
|
@ -51,11 +57,12 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
Text(
|
Text(
|
||||||
'Selamat Datang',
|
'Selamat Datang',
|
||||||
style: TTCommonsTextStyles.textLg.textRegular().copyWith(
|
style: TTCommonsTextStyles.textLg.textRegular().copyWith(
|
||||||
color: AppColors.heroWhite,
|
color: AppColors.heroWhite,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
key: controller.settingKey,
|
||||||
onPressed: controller.navigateToUtensilPage,
|
onPressed: controller.navigateToUtensilPage,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.settings,
|
Icons.settings,
|
||||||
|
@ -64,6 +71,7 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SearchTextField(
|
SearchTextField(
|
||||||
|
key: controller.searchKey,
|
||||||
controller: controller.searchController,
|
controller: controller.searchController,
|
||||||
hintText: 'Cari Resep..',
|
hintText: 'Cari Resep..',
|
||||||
inputType: TextInputType.text,
|
inputType: TextInputType.text,
|
||||||
|
@ -89,8 +97,8 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
RecipeRecommendationWidget(),
|
const RecipeRecommendationWidget(),
|
||||||
SizedBox(height: 64,)
|
const SizedBox(height: 64,)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -128,7 +136,7 @@ class HomeView extends BaseView<HomeViewModel> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
Text('Data 1'),
|
const Text('Data 1'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,17 +1,30 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:snap_and_cook_mobile/domain/use_case/general/recipe_use_case.dart';
|
import 'package:snap_and_cook_mobile/domain/use_case/general/recipe_use_case.dart';
|
||||||
|
import 'package:snap_and_cook_mobile/resources/constants/session_constants.dart';
|
||||||
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
|
|
||||||
import '../../../domain/entities/recipe.dart';
|
import '../../../domain/entities/recipe.dart';
|
||||||
import '../../../resources/arguments/argument_constants.dart';
|
import '../../../resources/arguments/argument_constants.dart';
|
||||||
import '../../../routes/routes/main_route.dart';
|
import '../../../routes/routes/main_route.dart';
|
||||||
|
import '../../../utils/session/session.dart';
|
||||||
import '../../base/base_view_model.dart';
|
import '../../base/base_view_model.dart';
|
||||||
|
import '../components/tutorial_home_items.dart';
|
||||||
|
|
||||||
class HomeViewModel extends BaseViewModel {
|
class HomeViewModel extends BaseViewModel {
|
||||||
TextEditingController searchController = TextEditingController();
|
TextEditingController searchController = TextEditingController();
|
||||||
final RecipeUseCase _recipeUseCase = RecipeUseCase();
|
final RecipeUseCase _recipeUseCase = RecipeUseCase();
|
||||||
|
|
||||||
final RxList<Recipe> recipes = RxList<Recipe>();
|
final RxList<Recipe> recipes = RxList<Recipe>();
|
||||||
|
late TutorialCoachMark tutorialCoachMark;
|
||||||
|
|
||||||
|
BuildContext? pageContext;
|
||||||
|
|
||||||
|
final cameraKey = GlobalKey();
|
||||||
|
final searchKey = GlobalKey();
|
||||||
|
final settingKey = GlobalKey();
|
||||||
|
|
||||||
void onSearchSubmitted(String value) {
|
void onSearchSubmitted(String value) {
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
|
@ -25,6 +38,51 @@ class HomeViewModel extends BaseViewModel {
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
_fetchAllRecipes();
|
_fetchAllRecipes();
|
||||||
|
createTutorial();
|
||||||
|
showTutorial();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getPageContext(BuildContext context){
|
||||||
|
pageContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createTutorial() {
|
||||||
|
tutorialCoachMark = TutorialCoachMark(
|
||||||
|
targets: createTargets(
|
||||||
|
keyBottomNavigation1: cameraKey,
|
||||||
|
keyBottomNavigation2: searchKey,
|
||||||
|
keyBottomNavigation3: settingKey),
|
||||||
|
colorShadow: Colors.black38,
|
||||||
|
textSkip: "SKIP",
|
||||||
|
paddingFocus: 10,
|
||||||
|
opacityShadow: 0.5,
|
||||||
|
imageFilter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||||
|
onFinish: () {
|
||||||
|
print("finish");
|
||||||
|
Session.set(SessionConstants.isAlreadyOnBoardingHome, "yes");
|
||||||
|
},
|
||||||
|
onClickTarget: (target) {
|
||||||
|
},
|
||||||
|
onClickTargetWithTapPosition: (target, tapDetails) {},
|
||||||
|
onClickOverlay: (target) {},
|
||||||
|
onSkip: () {
|
||||||
|
Session.set(SessionConstants.isAlreadyOnBoardingHome, "yes");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showTutorial() async {
|
||||||
|
Future.delayed(const Duration(seconds: 1));
|
||||||
|
String? isOnBoarded = await Session.get(SessionConstants.isAlreadyOnBoardingHome);
|
||||||
|
if (isOnBoarded != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageContext?.mounted ?? false){
|
||||||
|
tutorialCoachMark.show(context: pageContext!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchAllRecipes() async {
|
Future<void> _fetchAllRecipes() async {
|
||||||
|
|
|
@ -4,18 +4,37 @@ import 'package:snap_and_cook_mobile/presentation/recipe_detail/components/ingre
|
||||||
|
|
||||||
class IngredientListWidget extends StatelessWidget {
|
class IngredientListWidget extends StatelessWidget {
|
||||||
final List<Ingredient> ingredients;
|
final List<Ingredient> ingredients;
|
||||||
|
final List<String> selectedIngredient;
|
||||||
|
|
||||||
const IngredientListWidget({super.key, required this.ingredients});
|
const IngredientListWidget(
|
||||||
|
{super.key, required this.ingredients, required this.selectedIngredient});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return IngredientItem(ingredient: ingredients[index]);
|
return IngredientItem(
|
||||||
|
ingredient: ingredients[index],
|
||||||
|
isSelected: isSelectedIngredient(index),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
itemCount: ingredients.length,
|
itemCount: ingredients.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _toChecker(String data){
|
||||||
|
if (data == "daging ayam") return 'ayam';
|
||||||
|
if (data == "sayap ayam") return 'ayam';
|
||||||
|
if (data == "paha ayam") return 'ayam';
|
||||||
|
if (data == "dada ayam") return 'ayam';
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSelectedIngredient(int index){
|
||||||
|
return selectedIngredient.contains(_toChecker(ingredients[index].name?.toLowerCase() ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ import '../../../styles/colors.dart';
|
||||||
|
|
||||||
class IngredientItem extends StatelessWidget {
|
class IngredientItem extends StatelessWidget {
|
||||||
final Ingredient ingredient;
|
final Ingredient ingredient;
|
||||||
|
final bool? isSelected;
|
||||||
|
|
||||||
const IngredientItem({super.key, required this.ingredient});
|
const IngredientItem({super.key, required this.ingredient, this.isSelected});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -58,12 +59,14 @@ class IngredientItem extends StatelessWidget {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Widget _circleWidget() {
|
Widget _circleWidget() {
|
||||||
|
print("IS SLECTED = $isSelected");
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: 8.0,
|
width: 8.0,
|
||||||
height: 8.0,
|
height: 8.0,
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: AppColors.copper,
|
color: (isSelected ?? false) ? Colors.green : AppColors.copper,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:snap_and_cook_mobile/components/recipe/utensils.dart';
|
import 'package:snap_and_cook_mobile/components/recipe/utensils.dart';
|
||||||
|
|
||||||
|
import '../../../data/remote/models/utensil_model.dart';
|
||||||
|
|
||||||
class UtensilsListWidget extends StatelessWidget {
|
class UtensilsListWidget extends StatelessWidget {
|
||||||
final List<String> utensils;
|
final List<String> utensils;
|
||||||
|
final List<String> selectedUtensil;
|
||||||
|
|
||||||
const UtensilsListWidget({super.key, required this.utensils});
|
const UtensilsListWidget(
|
||||||
|
{super.key, required this.utensils, required this.selectedUtensil});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -13,7 +17,10 @@ class UtensilsListWidget extends StatelessWidget {
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return UtensilItem(name: utensils[index], isSelected: false,);
|
return UtensilItem(
|
||||||
|
name: utensils[index],
|
||||||
|
isSelected: selectedUtensil.contains(utensils[index]),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
itemCount: utensils.length,
|
itemCount: utensils.length,
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
|
|
|
@ -75,13 +75,16 @@ class RecipeDetailView extends BaseView<RecipeDetailViewModel> {
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => IngredientListWidget(
|
() => IngredientListWidget(
|
||||||
|
selectedIngredient: controller.selectedIngredientName,
|
||||||
ingredients: controller.recipe.value?.ingredients ?? [],
|
ingredients: controller.recipe.value?.ingredients ?? [],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const RecipeDetailDividerWidget(
|
const RecipeDetailDividerWidget(
|
||||||
title: 'Alat Memasak',
|
title: 'Alat Memasak',
|
||||||
),
|
),
|
||||||
UtensilsListWidget(utensils: controller.recipe.value?.utensils ?? [],),
|
UtensilsListWidget(
|
||||||
|
selectedUtensil: controller.selectedUtensil,
|
||||||
|
utensils: controller.recipe.value?.utensils ?? [],),
|
||||||
const RecipeDetailDividerWidget(
|
const RecipeDetailDividerWidget(
|
||||||
title: 'Langkah-langkah',
|
title: 'Langkah-langkah',
|
||||||
),
|
),
|
||||||
|
@ -89,13 +92,6 @@ class RecipeDetailView extends BaseView<RecipeDetailViewModel> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
BasicButton(
|
|
||||||
onPress: () {},
|
|
||||||
bgColor: AppColors.copper,
|
|
||||||
text: 'Mulai Memasak'),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../data/remote/models/ingredient_model.dart';
|
||||||
import '../../../domain/entities/recipe.dart';
|
import '../../../domain/entities/recipe.dart';
|
||||||
import '../../../domain/use_case/general/recipe_use_case.dart';
|
import '../../../domain/use_case/general/recipe_use_case.dart';
|
||||||
import '../../../resources/arguments/argument_constants.dart';
|
import '../../../resources/arguments/argument_constants.dart';
|
||||||
|
@ -8,7 +9,10 @@ import '../../base/base_view_model.dart';
|
||||||
class RecipeDetailViewModel extends BaseViewModel {
|
class RecipeDetailViewModel extends BaseViewModel {
|
||||||
final _arguments = Get.arguments;
|
final _arguments = Get.arguments;
|
||||||
String get recipeUuid => _arguments[ArgumentConstants.recipeUuid];
|
String get recipeUuid => _arguments[ArgumentConstants.recipeUuid];
|
||||||
|
List<String> get selectedUtensil => _arguments[ArgumentConstants.selectedUtensil];
|
||||||
|
List<Ingredient> get selectedIngredient => _arguments[ArgumentConstants.selectedIngredient];
|
||||||
|
|
||||||
|
List<String> selectedIngredientName = [];
|
||||||
final RecipeUseCase _recipeUseCase = RecipeUseCase();
|
final RecipeUseCase _recipeUseCase = RecipeUseCase();
|
||||||
final Rxn<Recipe> recipe = Rxn<Recipe>();
|
final Rxn<Recipe> recipe = Rxn<Recipe>();
|
||||||
|
|
||||||
|
@ -16,6 +20,9 @@ class RecipeDetailViewModel extends BaseViewModel {
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
_fetchRecipeDetail();
|
_fetchRecipeDetail();
|
||||||
|
selectedIngredient.forEach((element) {
|
||||||
|
selectedIngredientName.add((element.name ?? '').toLowerCase());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchRecipeDetail() async {
|
Future<void> _fetchRecipeDetail() async {
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
|
|
||||||
|
List<TargetFocus> createDetectionIdleTutorialTargets({
|
||||||
|
required GlobalKey keyBottomNavigation1,
|
||||||
|
}) {
|
||||||
|
List<TargetFocus> targets = [];
|
||||||
|
targets.add(
|
||||||
|
TargetFocus(
|
||||||
|
identify: "keyBottomNavigation1",
|
||||||
|
keyTarget: keyBottomNavigation1,
|
||||||
|
color: Colors.black38,
|
||||||
|
alignSkip: Alignment.topRight,
|
||||||
|
contents: [
|
||||||
|
TargetContent(
|
||||||
|
align: ContentAlign.custom,
|
||||||
|
customPosition: CustomTargetContentPosition(
|
||||||
|
top: 56,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
),
|
||||||
|
builder: (context, controller) {
|
||||||
|
return const Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Ambil Gambar",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8,),
|
||||||
|
Text(
|
||||||
|
"Tekan tombol berikut untuk mengambil foto bahan makanan dari kamera ataupun galeri",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return targets;
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ class RecipeDetectionView extends BaseView<RecipeDetectionViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
controller.getPageContext(context);
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
if (controller.isShowDetectionResult.value) {
|
if (controller.isShowDetectionResult.value) {
|
||||||
return _detection(context);
|
return _detection(context);
|
||||||
|
@ -69,7 +70,10 @@ class RecipeDetectionView extends BaseView<RecipeDetectionViewModel> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
BasicButton(
|
BasicButton(
|
||||||
onPress: controller.pickImage, height: 42, text: "Ambil Gambar")
|
key: controller.buttonKey,
|
||||||
|
onPress: controller.pickImage,
|
||||||
|
height: 42,
|
||||||
|
text: "Ambil Gambar")
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
@ -86,11 +90,14 @@ class RecipeDetectionView extends BaseView<RecipeDetectionViewModel> {
|
||||||
|
|
||||||
Widget _detection(BuildContext context) {
|
Widget _detection(BuildContext context) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
final bboxesColors = List<Color>.generate(
|
final bboxesColors = [
|
||||||
6,
|
Colors.green,
|
||||||
(_) =>
|
Colors.blue,
|
||||||
Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
|
Colors.redAccent,
|
||||||
);
|
Colors.purpleAccent,
|
||||||
|
Colors.amberAccent,
|
||||||
|
Colors.tealAccent
|
||||||
|
];
|
||||||
|
|
||||||
final double displayWidth = MediaQuery.of(context).size.width;
|
final double displayWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
@ -108,7 +115,6 @@ class RecipeDetectionView extends BaseView<RecipeDetectionViewModel> {
|
||||||
for (int i = 0; i < controller.bboxes.length; i++) {
|
for (int i = 0; i < controller.bboxes.length; i++) {
|
||||||
final box = controller.bboxes[i];
|
final box = controller.bboxes[i];
|
||||||
final boxClass = controller.classes[i];
|
final boxClass = controller.classes[i];
|
||||||
print("boxClass ${boxClass}");
|
|
||||||
bboxesWidgets.add(
|
bboxesWidgets.add(
|
||||||
Bbox(
|
Bbox(
|
||||||
box[0] * resizeFactor,
|
box[0] * resizeFactor,
|
||||||
|
@ -127,7 +133,8 @@ class RecipeDetectionView extends BaseView<RecipeDetectionViewModel> {
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
if (controller.imageFile.value != null) Image.file(controller.imageFile.value!),
|
if (controller.imageFile.value != null)
|
||||||
|
Image.file(controller.imageFile.value!),
|
||||||
...bboxesWidgets,
|
...bboxesWidgets,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
@ -9,15 +10,20 @@ import 'package:snap_and_cook_mobile/data/remote/models/ingredient_model.dart';
|
||||||
import 'package:snap_and_cook_mobile/resources/arguments/argument_constants.dart';
|
import 'package:snap_and_cook_mobile/resources/arguments/argument_constants.dart';
|
||||||
import 'package:snap_and_cook_mobile/routes/routes/main_route.dart';
|
import 'package:snap_and_cook_mobile/routes/routes/main_route.dart';
|
||||||
import 'package:snap_and_cook_mobile/utils/detection/labels.dart';
|
import 'package:snap_and_cook_mobile/utils/detection/labels.dart';
|
||||||
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
|
|
||||||
import '../../../components/camera/custom_camera.dart';
|
import '../../../components/camera/custom_camera.dart';
|
||||||
import '../../../domain/use_case/utensils/utensil_use_case.dart';
|
import '../../../domain/use_case/utensils/utensil_use_case.dart';
|
||||||
|
import '../../../resources/constants/session_constants.dart';
|
||||||
import '../../../utils/detection/yolo.dart';
|
import '../../../utils/detection/yolo.dart';
|
||||||
|
import '../../../utils/session/session.dart';
|
||||||
import '../../base/base_view_model.dart';
|
import '../../base/base_view_model.dart';
|
||||||
|
import '../components/tutorial_detection_idle_items.dart';
|
||||||
|
|
||||||
class RecipeDetectionViewModel extends BaseViewModel {
|
class RecipeDetectionViewModel extends BaseViewModel {
|
||||||
RxList<Map<String, dynamic>> modelResults = RxList();
|
RxList<Map<String, dynamic>> modelResults = RxList();
|
||||||
final _utensilUseCase = UtensilUseCase();
|
final _utensilUseCase = UtensilUseCase();
|
||||||
|
final buttonKey = GlobalKey();
|
||||||
|
|
||||||
|
|
||||||
Rxn<File> imageFile = Rxn<File>();
|
Rxn<File> imageFile = Rxn<File>();
|
||||||
|
@ -35,8 +41,8 @@ class RecipeDetectionViewModel extends BaseViewModel {
|
||||||
|
|
||||||
double maxImageWidgetHeight = 400;
|
double maxImageWidgetHeight = 400;
|
||||||
|
|
||||||
double confidenceThreshold = 0.25;
|
double confidenceThreshold = 0.3;
|
||||||
double iouThreshold = 0.40;
|
double iouThreshold = 0.4;
|
||||||
|
|
||||||
RxList<List<double>> inferenceOutput = RxList();
|
RxList<List<double>> inferenceOutput = RxList();
|
||||||
RxList<int> classes = RxList();
|
RxList<int> classes = RxList();
|
||||||
|
@ -49,16 +55,62 @@ class RecipeDetectionViewModel extends BaseViewModel {
|
||||||
DraggableScrollableController();
|
DraggableScrollableController();
|
||||||
|
|
||||||
final YoloModel model = YoloModel(
|
final YoloModel model = YoloModel(
|
||||||
'assets/yolov8s_snapcook.tflite',
|
'assets/yolov8m_snapcook.tflite',
|
||||||
inModelWidth,
|
inModelWidth,
|
||||||
inModelHeight,
|
inModelHeight,
|
||||||
numClasses,
|
numClasses,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
late TutorialCoachMark tutorialCoachMark;
|
||||||
|
|
||||||
|
BuildContext? pageContext;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
_loadMachineLearningModel();
|
_loadMachineLearningModel();
|
||||||
|
createTutorial();
|
||||||
|
showTutorial();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getPageContext(BuildContext context){
|
||||||
|
pageContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createTutorial() {
|
||||||
|
tutorialCoachMark = TutorialCoachMark(
|
||||||
|
targets: createDetectionIdleTutorialTargets(
|
||||||
|
keyBottomNavigation1: buttonKey,),
|
||||||
|
colorShadow: Colors.black38,
|
||||||
|
textSkip: "SKIP",
|
||||||
|
paddingFocus: 10,
|
||||||
|
opacityShadow: 0.5,
|
||||||
|
imageFilter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||||
|
onFinish: () {
|
||||||
|
print("finish");
|
||||||
|
Session.set(SessionConstants.isAlreadyOnBoardingDetectIngredient, "yes");
|
||||||
|
},
|
||||||
|
onClickTarget: (target) {
|
||||||
|
},
|
||||||
|
onClickTargetWithTapPosition: (target, tapDetails) {},
|
||||||
|
onClickOverlay: (target) {},
|
||||||
|
onSkip: () {
|
||||||
|
Session.set(SessionConstants.isAlreadyOnBoardingDetectIngredient, "yes");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showTutorial() async {
|
||||||
|
Future.delayed(const Duration(seconds: 1));
|
||||||
|
String? isOnBoarded = await Session.get(SessionConstants.isAlreadyOnBoardingDetectIngredient);
|
||||||
|
if (isOnBoarded != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageContext?.mounted ?? false){
|
||||||
|
tutorialCoachMark.show(context: pageContext!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadMachineLearningModel() async {
|
Future<void> _loadMachineLearningModel() async {
|
||||||
|
|
|
@ -48,7 +48,11 @@ class RecipeDetectionResultViewModel extends BaseViewModel {
|
||||||
|
|
||||||
void navigateToRecipeDetail(String uuid) {
|
void navigateToRecipeDetail(String uuid) {
|
||||||
Get.toNamed(MainRoute.detail,
|
Get.toNamed(MainRoute.detail,
|
||||||
arguments: {ArgumentConstants.recipeUuid: uuid});
|
arguments: {
|
||||||
|
ArgumentConstants.recipeUuid: uuid,
|
||||||
|
ArgumentConstants.selectedIngredient: ingredients,
|
||||||
|
ArgumentConstants.selectedUtensil: selectedUtensil.value
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:snap_and_cook_mobile/styles/colors.dart';
|
||||||
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
|
|
||||||
|
List<TargetFocus> createUtensilTutorialTargets({
|
||||||
|
required GlobalKey keyBottomNavigation1,
|
||||||
|
}) {
|
||||||
|
List<TargetFocus> targets = [];
|
||||||
|
targets.add(
|
||||||
|
TargetFocus(
|
||||||
|
identify: "keyBottomNavigation1",
|
||||||
|
keyTarget: keyBottomNavigation1,
|
||||||
|
color: Colors.black38,
|
||||||
|
alignSkip: Alignment.topRight,
|
||||||
|
contents: [
|
||||||
|
TargetContent(
|
||||||
|
align: ContentAlign.custom,
|
||||||
|
customPosition: CustomTargetContentPosition(
|
||||||
|
top: Get.height * 0.25,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
),
|
||||||
|
builder: (context, controller) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
"Pilih Alat Memasak",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8,),
|
||||||
|
const Text(
|
||||||
|
"Tekan tombol alat memasak yang kamu miliki, dan tekan lagi untuk membatalkan pilihan",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16,),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
color: AppColors.copper,
|
||||||
|
height: 22,
|
||||||
|
width: 22,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8,),
|
||||||
|
const Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Warna oranye berarti kamu telah memilih dan miliki",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8,),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 22,
|
||||||
|
width: 22,
|
||||||
|
color: AppColors.heroWhite,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8,),
|
||||||
|
const Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Warna putih berarti tidak kamu pilih",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return targets;
|
||||||
|
}
|
|
@ -21,18 +21,31 @@ class UtensilView extends BaseView<UtensilViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
controller.getPageContext(context);
|
||||||
return Obx(
|
return Obx(
|
||||||
() => Wrap(
|
() => Stack(
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < controller.utensils.length; i++)
|
Wrap(
|
||||||
GestureDetector(
|
children: [
|
||||||
onTap: () {
|
for (int i = 0; i < controller.utensils.length; i++)
|
||||||
controller.onSelectUtensil(controller.utensils[i], i);
|
GestureDetector(
|
||||||
},
|
onTap: () {
|
||||||
child: UtensilItem(
|
controller.onSelectUtensil(controller.utensils[i], i);
|
||||||
name: controller.utensils[i].name ?? '',
|
},
|
||||||
isSelected: controller.utensils[i].isSelected == 1),
|
child: UtensilItem(
|
||||||
)
|
name: controller.utensils[i].name ?? '',
|
||||||
|
isSelected: controller.utensils[i].isSelected == 1),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: SizedBox(
|
||||||
|
key: controller.buttonKey,
|
||||||
|
height: 20,
|
||||||
|
width: 60,
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,20 +1,75 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:snap_and_cook_mobile/domain/use_case/utensils/utensil_use_case.dart';
|
import 'package:snap_and_cook_mobile/domain/use_case/utensils/utensil_use_case.dart';
|
||||||
|
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
||||||
|
|
||||||
import '../../../data/remote/models/utensil_model.dart';
|
import '../../../data/remote/models/utensil_model.dart';
|
||||||
|
import '../../../resources/constants/session_constants.dart';
|
||||||
|
import '../../../utils/session/session.dart';
|
||||||
import '../../base/base_view_model.dart';
|
import '../../base/base_view_model.dart';
|
||||||
|
import '../components/tutorial_utensils_items.dart';
|
||||||
|
|
||||||
class UtensilViewModel extends BaseViewModel {
|
class UtensilViewModel extends BaseViewModel {
|
||||||
final _useCase = UtensilUseCase();
|
final _useCase = UtensilUseCase();
|
||||||
|
|
||||||
RxList<Utensil> utensils = RxList();
|
RxList<Utensil> utensils = RxList();
|
||||||
|
final buttonKey = GlobalKey();
|
||||||
|
|
||||||
|
|
||||||
|
late TutorialCoachMark tutorialCoachMark;
|
||||||
|
BuildContext? pageContext;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
_fetchUtensils();
|
_fetchUtensils();
|
||||||
|
createTutorial();
|
||||||
|
showTutorial();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getPageContext(BuildContext context){
|
||||||
|
pageContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createTutorial() {
|
||||||
|
tutorialCoachMark = TutorialCoachMark(
|
||||||
|
targets: createUtensilTutorialTargets(
|
||||||
|
keyBottomNavigation1: buttonKey,),
|
||||||
|
colorShadow: Colors.black38,
|
||||||
|
textSkip: "SKIP",
|
||||||
|
paddingFocus: 10,
|
||||||
|
opacityShadow: 0.5,
|
||||||
|
imageFilter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||||
|
onFinish: () {
|
||||||
|
print("finish");
|
||||||
|
Session.set(SessionConstants.isAlreadyOnBoardingUtensil, "yes");
|
||||||
|
},
|
||||||
|
onClickTarget: (target) {
|
||||||
|
},
|
||||||
|
onClickTargetWithTapPosition: (target, tapDetails) {},
|
||||||
|
onClickOverlay: (target) {},
|
||||||
|
onSkip: () {
|
||||||
|
Session.set(SessionConstants.isAlreadyOnBoardingUtensil, "yes");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showTutorial() async {
|
||||||
|
Future.delayed(const Duration(seconds: 1));
|
||||||
|
String? isOnBoarded = await Session.get(SessionConstants.isAlreadyOnBoardingUtensil);
|
||||||
|
if (isOnBoarded != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageContext?.mounted ?? false){
|
||||||
|
tutorialCoachMark.show(context: pageContext!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _fetchUtensils() async {
|
Future<void> _fetchUtensils() async {
|
||||||
showLoadingContainer();
|
showLoadingContainer();
|
||||||
utensils.value = await _useCase.fetchUtensils();
|
utensils.value = await _useCase.fetchUtensils();
|
||||||
|
|
|
@ -2,6 +2,8 @@ class ArgumentConstants {
|
||||||
static const String receivedFile = "received_file_args";
|
static const String receivedFile = "received_file_args";
|
||||||
static const String ingredients = "ingredients_args";
|
static const String ingredients = "ingredients_args";
|
||||||
static const String recipeUuid = "recipe_uuid_args";
|
static const String recipeUuid = "recipe_uuid_args";
|
||||||
|
static const String selectedUtensil = "selected_utensil_args";
|
||||||
|
static const String selectedIngredient = "selected_ingredient_args";
|
||||||
static const String search = "search_args";
|
static const String search = "search_args";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
class SessionConstants {
|
class SessionConstants {
|
||||||
static const String token = "session_token";
|
static const String isAlreadyOnBoardingHome =
|
||||||
static const String isAlreadyOnBoarding = "session_is_already_on_boarding";
|
"session_is_already_on_boarding_home";
|
||||||
|
static const String isAlreadyOnBoardingDetectIngredient =
|
||||||
|
"session_is_already_on_boarding_detect_ingredient";
|
||||||
|
static const String isAlreadyOnBoardingUtensil =
|
||||||
|
"session_is_already_on_boarding_utensil";
|
||||||
}
|
}
|
||||||
|
|
20
pubspec.lock
20
pubspec.lock
|
@ -21,10 +21,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265
|
sha256: "6bd38d335f0954f5fad9c79e614604fbf03a0e5b975923dd001b6ea965ef5b4b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.1"
|
version: "3.6.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -415,10 +415,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_screenutil
|
name: flutter_screenutil
|
||||||
sha256: "8cf100b8e4973dc570b6415a2090b0bfaa8756ad333db46939efc3e774ee100d"
|
sha256: b372c35a772a1dc84142a3b9c5ee89a390834bd258e5e6a450d9b975b985d1c9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.9.0"
|
version: "5.9.1"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -505,10 +505,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.7"
|
version: "4.2.0"
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1146,6 +1146,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
|
tutorial_coach_mark:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: tutorial_coach_mark
|
||||||
|
sha256: "1f1fd234790afb929dec7391a4d90aa54ffe8c8e4d278d9283df8e3f5ac5d63e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.11"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.0+5
|
version: 1.0.0+6
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.2 <4.0.0'
|
sdk: '>=3.0.2 <4.0.0'
|
||||||
|
@ -55,6 +55,7 @@ dependencies:
|
||||||
chucker_flutter:
|
chucker_flutter:
|
||||||
sqflite: ^2.2.8+4
|
sqflite: ^2.2.8+4
|
||||||
tflite_flutter: ^0.10.4
|
tflite_flutter: ^0.10.4
|
||||||
|
tutorial_coach_mark: ^1.2.11
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in New Issue