Merge pull request 'diary' (#15) from diary into main

Reviewed-on: maxxkim/eatvio_app#15
This commit is contained in:
2024-02-28 09:03:35 +00:00
20 changed files with 1552 additions and 490 deletions

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
SERVER_ROOT='https://ohngeeri3ien-dev3.eatvio.ru/api'
STORAGE_URL='https://ohngeeri3ien-dev3.eatvio.ru/storage/'

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

44
ios/Podfile Normal file
View File

@@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

View File

@@ -41,5 +41,9 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@@ -3,7 +3,8 @@ import 'package:flutter/material.dart';
// This functions are responsible to make UI responsive across all the mobile devices.
MediaQueryData mediaQueryData = MediaQueryData.fromWindow(ui.window);
// ignore: deprecated_member_use
MediaQueryData mediaQueryData = MediaQueryData.fromView(ui.window);
// These are the Viewport values of your Figma Design.
// These are used in the code as a reference to create your UI Responsively.

View File

@@ -68,6 +68,14 @@ class AuthScreen extends StatelessWidget {
Navigator.pushNamed(
context, AppRoutes.languageSelectScreen);
}),
NextStepButton(
text: "Тест дневника".toUpperCase(),
margin:
EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v),
buttonStyle: CustomButtonStyles.outlinePrimaryTL15,
onPressed: () {
Navigator.pushNamed(context, AppRoutes.diaryEdit);
}),
BlocBuilder<AuthBloc, AuthState>(builder: (context, state) {
return NextStepButton(
text: "authentificate".tr.toUpperCase(),
@@ -95,7 +103,7 @@ class AuthScreen extends StatelessWidget {
box.put('token', token);
Navigator.pushNamed(
context,
AppRoutes.diaryEdit,
AppRoutes.myProfile,
);
} else {
showDialog(

View File

@@ -1,10 +1,12 @@
import 'dart:async';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import '/core/app_export.dart';
import 'package:image_picker/image_picker.dart';
import 'package:eatvio_app/presentation/diary/diary_edit_screen/models/diary_edit_model.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:hive/hive.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
part 'diary_edit_event.dart';
@@ -14,6 +16,22 @@ part 'diary_edit_state.dart';
class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
DiaryEditBloc(DiaryEditState initialState) : super(initialState) {
on<DiaryEditInitialEvent>(_onInitialize);
on<ChangeSatiety>(_changeSatiety); // пользователь нажимает на шкалу сытости
on<ChangeMood>(_changeMood); // пользователь нажимает на шкалу настроения
on<ChangeMealTime>(
_changeMealTime); // пользователь изменяет время приема пиши
on<ChangeMeal>(_changeMeal);
on<WakeupEvent>(_changeWakeup); // пользователь выбирает время пробуждения
on<RetireEvent>(_changeRetire); // пользователь выбирает время отхода ко сну
on<ToggleMoodExpandedEvent>(_toggleMood);
on<ToggleWakeupExpandedEvent>(_toggleWakeup);
on<AddPortionEvent>(_addPortion); //пользователь нажимает "Добавить продукт"
on<RemovePortionEvent>(
_removePortion); // пользователь нажимает на крестик около продукта
on<UploadImages>(_uploadImages); //пользователь нажимает "Добавить фото"
on<AddComment>(_addComment); //пользователь нажимает "Добавить комментарий"
on<ProductInput>(
_inputProduct); //пользователь нажимает "Добавить комментарий"
}
Future<void> _onInitialize(
@@ -21,8 +39,8 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
Emitter<DiaryEditState> emit,
) async {
try {
final box = await Hive.openBox('token');
final token = box.get('token');
final token =
"laravel_sanctum_Q22zOtJhQUcJnh0kseZFblFv5XAPaKbG3gTM5hga71ecbb49";
final response = await http.get(
Uri.parse(dotenv.env['SERVER_ROOT']! + '/diary/index'),
headers: {
@@ -32,18 +50,78 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// Проверка наличия ключевых полей в JSON
if (data is Map<String, dynamic> && data.containsKey('id')) {
// Все ключевые поля присутствуют, продолжаем обработку
if (state is DiaryEditLoadedState) {
// Если текущее состояние уже загружено, обновляем его
var currentState = state as DiaryEditLoadedState;
// Обновляем значения контроллеров только если они уже были созданы
emit((currentState).copyWith());
} else {
// Если текущее состояние - начальное, создаем новое загруженное состояние
emit(DiaryEditLoadedState());
final int diaryId = data['id'];
try {
final response = await http.get(
Uri.parse(dotenv.env['SERVER_ROOT']! + '/diary/show/$diaryId'),
headers: {
'Authorization': 'Bearer $token',
},
);
final diary = jsonDecode(response.body)['diary'];
if (diary is Map<String, dynamic>) {
print(diary['meals'][1].runtimeType);
final String diaryDate =
diary['date'] ?? DateTime.now().toString();
// Продолжайте обработку данных дневника
if (state is DiaryEditLoadedState) {
// Если текущее состояние уже загружено, обновляем его
var currentState = state as DiaryEditLoadedState;
emit((currentState).copyWith(
currentMeal: currentState.currentMeal,
wakeupExpanded: currentState.wakeupExpanded,
moodExpanded: currentState.moodExpanded,
token: currentState.token,
meals: currentState.meals,
wakeupController: currentState.wakeupController,
retireController: currentState.retireController,
commentController: currentState.commentController,
mealTimeController: currentState.mealTimeController,
productNameController: currentState.productNameController,
selectedSatiety: currentState.selectedSatiety,
selectedMood: currentState.selectedMood,
diaryDate: currentState.diaryDate,
diaryId: currentState.diaryId,
productQuantityController:
currentState.productQuantityController,
autocompleteList: currentState.autocompleteList,
diaryEditModelObj: currentState.diaryEditModelObj));
} else {
// Если текущее состояние - начальное, создаем новое загруженное состояние
emit(DiaryEditLoadedState(
currentMeal: SelectionPopupModel(
id: 0, title: "Прием пищи 1", isSelected: true),
wakeupExpanded: true,
moodExpanded: true,
token: token,
meals: diary['meals'],
portions: diary['meals'][0]['portions'],
wakeupController: toTime(diary['wakeup'] ?? "09:00"),
retireController: toTime(diary['retire'] ?? "23:00"),
mealTimeController:
toTime(diary['meals'][0]['time'] ?? "10:00"),
selectedSatiety: diary['meals'][0]['satiety'],
selectedMood: diary['meals'][0]['mood'],
commentController:
TextEditingController(text: diary['comment']),
productNameController: TextEditingController(),
productQuantityController: TextEditingController(),
diaryId: diaryId,
diaryDate: diaryDate,
autocompleteList: [],
diaryEditModelObj: state.diaryEditModelObj
?.copyWith(mealList: fillMealList())));
}
} else {
// Ошибка при декодировании JSON
emit(DiaryEditErrorState(
'Ошибка при декодировании данных дневника'));
}
} catch (e) {
// Ошибка при получении данных дневника
emit(DiaryEditErrorState(
'Ошибка при получении данных дневника: $e'));
}
} else {
// Один или несколько ключевых полей отсутствуют, обрабатываем ошибку
@@ -55,8 +133,386 @@ class DiaryEditBloc extends Bloc<DiaryEditEvent, DiaryEditState> {
emit(DiaryEditErrorState('Ошибка сервера: ${response.statusCode}'));
}
} catch (e) {
// Ошибка при декодировании JSON или другая ошибка выполнения
emit(DiaryEditErrorState('Ошибка при получении данных профиля: $e'));
// Ошибка при получении данных дневника
emit(DiaryEditErrorState('Ошибка при получении данных дневника: $e'));
}
}
Future<void> _changeSatiety(
ChangeSatiety event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState =
currentState.copyWith(selectedSatiety: event.selectedElement);
emit(updatedState); // Передаем обновленное состояние в emit
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendSatietyData(
currentState.token,
event.selectedElement,
currentState.currentMeal?.id,
currentState.diaryId);
if (response.statusCode == 200) {
currentState.selectedSatiety = event.selectedElement;
emit(currentState); // Передаем обновленное состояние в emit
}
}
}
Future<http.Response> sendSatietyData(
String? token,
int selectedSatiety,
int? mealID,
int diaryID,
) async {
String url =
dotenv.env['SERVER_ROOT']! + '$diaryID/meal/$mealID/satiety/fill';
final credentials = {
'satiety': selectedSatiety,
'meal_id': mealID,
'diary_id': diaryID,
};
var response = await http.post(Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8);
return response;
}
Future<void> _changeMood(
ChangeMood event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState =
currentState.copyWith(selectedMood: event.selectedElement);
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendMoodData(
currentState.token,
event.selectedElement,
currentState.currentMeal?.id,
currentState.diaryId);
if (response.statusCode == 200) {
updatedState.selectedMood = event.selectedElement;
emit(updatedState); // Передаем обновленное состояние в emit
}
}
}
Future<http.Response> sendMoodData(
String? token,
int selectedMood,
int? mealID,
int diaryID,
) async {
String url =
dotenv.env['SERVER_ROOT']! + '/$diaryID/meal/$mealID/mood/fill';
final credentials = {
'mood': selectedMood,
'meal_id': mealID,
'diary_id': diaryID,
};
var response = await http.post(Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8);
return response;
}
FutureOr<void> _changeWakeup(
WakeupEvent event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState =
currentState.copyWith(wakeupController: event.selectedTime);
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendWakeupData(
currentState.token, event.selectedTime, currentState.diaryId);
if (response.statusCode == 200) {
updatedState.wakeupController = event.selectedTime;
emit(updatedState); // Передаем обновленное состояние в emit
}
}
}
Future<http.Response> sendWakeupData(
String? token,
TimeOfDay wakeup,
int diaryID,
) async {
String url = dotenv.env['SERVER_ROOT']! + '/diary/???';
final credentials = {
'wakeup': wakeup,
'diary_id': diaryID,
};
var response = await http.post(Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8);
return response;
}
FutureOr<void> _changeRetire(
RetireEvent event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState =
currentState.copyWith(retireController: event.selectedTime);
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendRetireData(
currentState.token, event.selectedTime, currentState.diaryId);
if (response.statusCode == 200) {
updatedState.retireController = event.selectedTime;
emit(updatedState); // Передаем обновленное состояние в emit
}
}
}
Future<http.Response> sendRetireData(
String? token, TimeOfDay retire, int diaryID) async {
String url = dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/retire/fill';
final credentials = {
'retire': retire,
};
var response = await http.post(Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8);
return response;
}
FutureOr<void> _changeMealTime(
ChangeMealTime event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
var updatedState = currentState.copyWith(mealTimeController: event.time);
emit(updatedState); // Передаем обновленное состояние в emit
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendMealTimeData(currentState.token, event.time,
currentState.currentMeal?.id, currentState.diaryId);
if (response.statusCode == 200) {
currentState.retireController = event.time;
emit(currentState); // Передаем обновленное состояние в emit
}
}
}
Future<http.Response> sendMealTimeData(
String? token,
TimeOfDay mealTime,
int? mealID,
int diaryID,
) async {
String url = dotenv.env['SERVER_ROOT']! + '/diary/???';
final credentials = {
'time': mealTime,
'meal_id': mealID,
'diary_id': diaryID,
};
var response = await http.post(Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8);
return response;
}
FutureOr<void> _changeMeal(ChangeMeal event, Emitter<DiaryEditState> emit) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
int? id = event.value.id;
emit(currentState.copyWith(
currentMeal: event.value,
portions: event.meals?[event.value.id ?? 0]['portions'],
mealTimeController:
toTime(event.meals?[event.value.id ?? 0]['time'] ?? "1$id:00"),
selectedMood: event.meals?[event.value.id ?? 0]['mood'],
selectedSatiety: event.meals?[event.value.id ?? 0]['satiety']));
currentState.currentMeal = event.value;
}
}
FutureOr<void> _toggleMood(
ToggleMoodExpandedEvent event, Emitter<DiaryEditState> emit) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
emit(currentState.copyWith(moodExpanded: !currentState.moodExpanded));
currentState.moodExpanded = !currentState.moodExpanded;
}
}
FutureOr<void> _toggleWakeup(
ToggleWakeupExpandedEvent event, Emitter<DiaryEditState> emit) {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
emit(currentState.copyWith(wakeupExpanded: !currentState.wakeupExpanded));
currentState.wakeupExpanded = !currentState.wakeupExpanded;
}
}
FutureOr<void> _addPortion(
AddPortionEvent event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
int? id = currentState.currentMeal?.id;
var updatedState = currentState.copyWith(
currentMeal: currentState.diaryEditModelObj?.mealList[id ?? 0],
portions: currentState.meals?[id ?? 0]['portions'],
mealTimeController:
toTime(currentState.meals?[id ?? 0]['time'] ?? "1$id:00"),
selectedMood: currentState.meals?[id ?? 0]['mood'],
selectedSatiety: currentState.meals?[id ?? 0]['satiety']);
emit(updatedState); // Передаем обновленное состояние в emit
// Отправляем данные по HTTP маршруту и ждем ответ
var response = await sendPortionData(
currentState.token,
event.name,
event.portion,
event.quantity,
currentState.currentMeal!.id,
currentState.diaryId);
if (response.statusCode == 200) {
emit(currentState); // Передаем обновленное состояние в emit
}
}
}
Future<http.Response> sendPortionData(
String? token,
String name,
String portion,
int quantity,
int? mealID,
int diaryID,
) async {
String url =
dotenv.env['SERVER_ROOT']! + '/$diaryID/meal/$mealID/portions/create';
final credentials = {
'name': name,
'portion': portion,
'quantity': quantity,
'meal_id': mealID,
'diary_id': diaryID,
};
var response = await http.post(Uri.parse(url),
headers: {
'Authorization': 'Bearer $token',
},
body: json.encode(credentials),
encoding: utf8);
return response;
}
FutureOr<void> _inputProduct(
ProductInput event, Emitter<DiaryEditState> emit) async {
if (state is DiaryEditLoadedState) {
var currentState = state as DiaryEditLoadedState;
String? token = currentState.token;
final credentials = {
'name': event.input,
};
final uri = Uri.parse(dotenv.env['SERVER_ROOT']! +
'/diary/product_nutritional_values/filter?' +
Uri(queryParameters: credentials).query);
final response = await http.get(
uri,
headers: {
'Authorization': 'Bearer $token',
},
);
final productNutritionalValues =
jsonDecode(response.body)['productNutritionalValue'];
if (productNutritionalValues is Map<String, dynamic>) {
var updatedState = currentState.copyWith(
autocompleteList: productNutritionalValues.values
.map((value) => value['name'])
.toList());
emit(updatedState);
}
}
}
FutureOr<void> _removePortion(
RemovePortionEvent event, Emitter<DiaryEditState> emit) {}
Future<FutureOr<void>> _uploadImages(
UploadImages event, Emitter<DiaryEditState> emit) async {
String imageUrl = await uploadImageToServer(event.image.path);
print(imageUrl);
}
FutureOr<void> _addComment(AddComment event, Emitter<DiaryEditState> emit) {}
Future<String> uploadImageToServer(String imagePath) async {
var request = http.MultipartRequest(
'POST',
Uri.parse(
'http://your-api-url.com/upload'), // Замените на ваш маршрут API
);
request.files.add(await http.MultipartFile.fromPath('image', imagePath));
var response = await request.send();
if (response.statusCode == 200) {
var responseData = await response.stream.bytesToString();
return responseData;
} else {
throw Exception('Ошибка при загрузке изображения');
}
}
TimeOfDay toTime(String timeStr) {
List<String> timeParts = timeStr.split(":");
int hour = int.parse(timeParts[0]);
int minute = int.parse(timeParts[1]);
TimeOfDay timeOfDay = TimeOfDay(hour: hour, minute: minute);
return timeOfDay;
}
List<SelectionPopupModel> fillMealList() {
return [
SelectionPopupModel(id: 0, title: "Прием пищи 1", isSelected: true),
SelectionPopupModel(id: 1, title: "Прием пищи 2"),
SelectionPopupModel(id: 2, title: "Прием пищи 3"),
SelectionPopupModel(id: 3, title: "Прием пищи 4"),
SelectionPopupModel(id: 4, title: "Прием пищи 5"),
SelectionPopupModel(id: 5, title: "Прием пищи 6"),
];
}
}

View File

@@ -14,3 +14,105 @@ class DiaryEditInitialEvent extends DiaryEditEvent {
@override
List<Object?> get props => [];
}
class ChangeSatiety extends DiaryEditEvent {
ChangeSatiety(
this.selectedElement,
);
final int selectedElement;
@override
List<Object> get props => [selectedElement];
}
class ChangeMood extends DiaryEditEvent {
ChangeMood(
this.selectedElement,
);
final int selectedElement;
@override
List<Object> get props => [selectedElement];
}
class ChangeMealTime extends DiaryEditEvent {
ChangeMealTime(this.time);
final TimeOfDay time;
@override
List<Object> get props => [time];
}
class AddComment extends DiaryEditEvent {
AddComment(this.diaryId, this.comment);
final String comment;
final int diaryId;
@override
List<Object> get props => [comment, diaryId];
}
class WakeupEvent extends DiaryEditEvent {
WakeupEvent(this.selectedTime);
final TimeOfDay selectedTime;
@override
List<Object> get props => [selectedTime];
}
class RetireEvent extends DiaryEditEvent {
RetireEvent(this.selectedTime);
final TimeOfDay selectedTime;
@override
List<Object> get props => [selectedTime];
}
class ToggleMoodExpandedEvent extends DiaryEditEvent {
@override
List<Object?> get props => [];
}
class ToggleWakeupExpandedEvent extends DiaryEditEvent {
@override
List<Object?> get props => [];
}
class AddPortionEvent extends DiaryEditEvent {
AddPortionEvent(this.name, this.quantity, this.portion);
final String name;
final int quantity;
final String portion;
@override
List<Object> get props => [name, quantity, portion];
}
class RemovePortionEvent extends DiaryEditEvent {
RemovePortionEvent(this.portionId);
final int portionId;
@override
List<Object> get props => [portionId];
}
class UploadImages extends DiaryEditEvent {
UploadImages(this.image);
final XFile image;
@override
List<Object> get props => [image];
}
class ProductInput extends DiaryEditEvent {
ProductInput(this.input);
final String input;
@override
List<Object> get props => [input];
}
class ChangeMeal extends DiaryEditEvent {
ChangeMeal({required this.value, required this.meals});
SelectionPopupModel value;
List<dynamic>? meals;
@override
List<Object?> get props => [value, meals];
}

View File

@@ -18,20 +18,106 @@ class DiaryEditInitialState extends DiaryEditState {
/// Represents the state of DiaryEdit in the application.
class DiaryEditLoadedState extends DiaryEditState {
DiaryEditLoadedState({this.diaryEditModelObj})
DiaryEditLoadedState(
{this.diaryEditModelObj,
this.diaryDate,
this.token,
this.meals,
this.portions,
this.autocompleteList,
this.wakeupController,
this.retireController,
this.commentController,
this.mealTimeController,
this.productNameController,
this.productQuantityController,
this.selectedMood,
this.currentMeal,
required this.diaryId,
required this.selectedSatiety,
required this.wakeupExpanded,
required this.moodExpanded})
: super(diaryEditModelObj: null);
DiaryEditModel? diaryEditModelObj;
String? diaryDate;
String? token;
List<dynamic>? meals;
List<dynamic>? portions;
List<dynamic>? autocompleteList;
SelectionPopupModel? currentMeal;
TimeOfDay? wakeupController;
TimeOfDay? retireController;
TimeOfDay? mealTimeController;
TextEditingController? commentController;
TextEditingController? productNameController;
TextEditingController? productQuantityController;
int? selectedMood;
int selectedSatiety;
int diaryId;
bool wakeupExpanded;
bool moodExpanded;
@override
List<Object?> get props => [
diaryEditModelObj,
diaryDate,
token,
meals,
autocompleteList,
wakeupController,
retireController,
mealTimeController,
commentController,
productNameController,
productQuantityController,
selectedMood,
selectedSatiety,
diaryId,
wakeupExpanded,
moodExpanded,
currentMeal
];
DiaryEditLoadedState copyWith({
DiaryEditModel? diaryEditModelObj,
SelectionPopupModel? currentMeal,
String? diaryDate,
String? token,
List<dynamic>? meals,
List<dynamic>? portions,
List<dynamic>? autocompleteList,
TimeOfDay? wakeupController,
TimeOfDay? retireController,
TimeOfDay? mealTimeController,
TextEditingController? commentController,
TextEditingController? productNameController,
TextEditingController? productQuantityController,
int? selectedMood,
int? selectedSatiety,
int? diaryId,
bool? wakeupExpanded,
bool? moodExpanded,
}) {
return DiaryEditLoadedState(
diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj,
);
diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj,
diaryDate: diaryDate ?? this.diaryDate,
token: token ?? this.token,
meals: meals ?? this.meals,
autocompleteList: autocompleteList ?? this.autocompleteList,
portions: portions ?? this.portions,
wakeupController: wakeupController ?? this.wakeupController,
retireController: retireController ?? this.retireController,
mealTimeController: mealTimeController ?? this.mealTimeController,
commentController: commentController ?? this.commentController,
productNameController:
productNameController ?? this.productNameController,
productQuantityController:
productQuantityController ?? this.productQuantityController,
selectedMood: selectedMood ?? this.selectedMood,
selectedSatiety: selectedSatiety ?? this.selectedSatiety,
diaryId: diaryId ?? this.diaryId,
currentMeal: currentMeal ?? this.currentMeal,
wakeupExpanded: wakeupExpanded ?? this.wakeupExpanded,
moodExpanded: moodExpanded ?? this.moodExpanded);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,22 @@
// ignore_for_file: must_be_immutable
import 'package:equatable/equatable.dart';
import 'package:eatvio_app/data/models/selectionPopupModel/selection_popup_model.dart';
/// This class defines the variables used in the [k0_page],
/// and is typically used to hold data that is passed between different parts of the application.
class DiaryEditModel extends Equatable {
DiaryEditModel();
DiaryEditModel({this.mealList = const []});
DiaryEditModel copyWith() {
return DiaryEditModel();
List<SelectionPopupModel> mealList;
DiaryEditModel copyWith({
List<SelectionPopupModel>? mealList,
}) {
return DiaryEditModel(
mealList: mealList ?? this.mealList,
);
}
@override
List<Object?> get props => [];
List<Object?> get props => [mealList];
}

View File

@@ -1,5 +1,3 @@
import 'dart:ffi';
import 'bloc/my_profile_bloc.dart';
import 'models/my_profile_model.dart';
import 'package:eatvio_app/core/app_export.dart';

View File

@@ -8,7 +8,7 @@ class CustomButtonStyles {
backgroundColor: appTheme.blueA400,
side: BorderSide(
color: theme.colorScheme.primary,
width: 1,
width: 0,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.h),

View File

@@ -1,6 +1,7 @@
import 'package:eatvio_app/core/app_export.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class CustomBottomBar extends StatefulWidget {
CustomBottomBar({this.onChanged});

View File

@@ -1,3 +1,4 @@
import 'package:eatvio_app/core/app_export.dart';
import 'package:flutter/material.dart';
class CustomDropDown extends StatelessWidget {
@@ -22,6 +23,7 @@ class CustomDropDown extends StatelessWidget {
this.filled = true,
this.validator,
this.onChanged,
this.defaultValue,
}) : super(
key: key,
);
@@ -38,7 +40,7 @@ class CustomDropDown extends StatelessWidget {
final TextStyle? textStyle;
final List<String>? items;
final List<SelectionPopupModel>? items;
final String? hintText;
@@ -60,9 +62,11 @@ class CustomDropDown extends StatelessWidget {
final bool? filled;
final FormFieldValidator<String>? validator;
final SelectionPopupModel? defaultValue;
final Function(String)? onChanged;
final FormFieldValidator<SelectionPopupModel>? validator;
final Function(SelectionPopupModel)? onChanged;
@override
Widget build(BuildContext context) {
@@ -76,29 +80,32 @@ class CustomDropDown extends StatelessWidget {
Widget get dropDownWidget => SizedBox(
width: width ?? double.maxFinite,
child: DropdownButtonFormField(
child: DropdownButtonFormField<SelectionPopupModel>(
focusNode: focusNode ?? FocusNode(),
icon: icon,
autofocus: autofocus!,
items: items?.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
style: textStyle ?? theme.textTheme.titleMedium,
items: items?.map((SelectionPopupModel item) {
return DropdownMenuItem<SelectionPopupModel>(
value: item,
child: Text(
value,
item.title,
overflow: TextOverflow.ellipsis,
style: hintStyle ?? theme.textTheme.titleMedium,
),
);
}).toList(),
decoration: decoration,
validator: validator,
value: defaultValue,
onChanged: (value) {
onChanged!(value.toString());
onChanged!(value!);
},
),
);
InputDecoration get decoration => InputDecoration(
hintText: hintText ?? "",
hintStyle: hintStyle,
hintStyle: hintStyle ?? theme.textTheme.titleMedium,
prefixIcon: prefix,
prefixIconConstraints: prefixConstraints,
suffixIcon: suffix,
@@ -106,27 +113,33 @@ class CustomDropDown extends StatelessWidget {
isDense: true,
contentPadding: contentPadding ??
EdgeInsets.only(
left: 17,
top: 17,
bottom: 17,
left: 6.h,
top: 6.v,
bottom: 6.v,
),
fillColor: fillColor,
fillColor: fillColor ?? theme.colorScheme.onPrimary,
filled: filled,
border: borderDecoration ??
OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(8.h),
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
enabledBorder: borderDecoration ??
OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(8.h),
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
focusedBorder: borderDecoration ??
OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderRadius: BorderRadius.circular(8.h),
borderSide: BorderSide(
color: Colors.blue,
color: Colors.grey,
width: 1,
),
),

View File

@@ -0,0 +1,152 @@
import 'package:eatvio_app/core/app_export.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CustomTextFormField extends StatelessWidget {
CustomTextFormField({
Key? key,
this.alignment,
this.width,
this.controller,
this.focusNode,
this.autofocus = true,
this.textStyle,
this.obscureText = false,
this.textInputAction = TextInputAction.next,
this.textInputType = TextInputType.text,
this.maxLines,
this.hintText,
this.hintStyle,
this.prefix,
this.prefixConstraints,
this.suffix,
this.suffixConstraints,
this.initialValue,
this.contentPadding,
this.inputFormatters,
this.borderDecoration,
this.fillColor,
this.filled = true,
this.validator,
this.keyboardType,
this.onChanged,
this.onSaved,
}) : super(
key: key,
);
final Alignment? alignment;
final double? width;
final TextEditingController? controller;
final FocusNode? focusNode;
final bool? autofocus;
final TextStyle? textStyle;
final bool? obscureText;
final List<TextInputFormatter>? inputFormatters;
final TextInputAction? textInputAction;
final TextInputType? textInputType;
final int? maxLines;
final String? hintText;
final TextStyle? hintStyle;
final Widget? prefix;
final BoxConstraints? prefixConstraints;
final Widget? suffix;
final BoxConstraints? suffixConstraints;
final EdgeInsets? contentPadding;
final InputBorder? borderDecoration;
final Color? fillColor;
final bool? filled;
final TextInputType? keyboardType;
final String? initialValue;
final FormFieldValidator<String>? validator;
final void Function(String?)? onSaved;
final ValueChanged<String>? onChanged;
@override
Widget build(BuildContext context) {
return alignment != null
? Align(
alignment: alignment ?? Alignment.center,
child: textFormFieldWidget,
)
: textFormFieldWidget;
}
Widget get textFormFieldWidget => SizedBox(
width: width ?? double.maxFinite,
child: TextFormField(
controller: controller,
focusNode: focusNode ?? FocusNode(),
autofocus: autofocus!,
style: textStyle ?? theme.textTheme.titleMedium,
obscureText: obscureText!,
textInputAction: textInputAction,
maxLines: maxLines ?? 1,
decoration: decoration,
validator: validator,
keyboardType: keyboardType,
onSaved: onSaved,
onChanged: onChanged,
inputFormatters: inputFormatters,
initialValue: initialValue,
),
);
InputDecoration get decoration => InputDecoration(
hintText: hintText ?? "",
hintStyle: hintStyle ?? theme.textTheme.bodyLarge,
prefixIcon: prefix,
prefixIconConstraints: prefixConstraints,
suffixIcon: suffix,
suffixIconConstraints: suffixConstraints,
isDense: true,
contentPadding: contentPadding ?? EdgeInsets.all(6.h),
fillColor: fillColor ?? theme.colorScheme.onPrimary,
filled: filled,
border: borderDecoration ??
OutlineInputBorder(
borderRadius: BorderRadius.circular(8.h),
borderSide: BorderSide(color: Colors.grey, width: 1),
),
enabledBorder: borderDecoration ??
OutlineInputBorder(
borderRadius: BorderRadius.circular(8.h),
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
focusedBorder: borderDecoration ??
OutlineInputBorder(
borderRadius: BorderRadius.circular(8.h),
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
);
}

View File

@@ -96,7 +96,6 @@ class CustomImageView extends StatelessWidget {
height: height,
width: width,
fit: fit ?? BoxFit.contain,
color: color,
),
);
case ImageType.file:

View File

@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
class ScaleElement extends StatelessWidget {
final Color color;
final bool isSelected;
final VoidCallback onTap;
const ScaleElement({
required this.color,
required this.isSelected,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
width: isSelected ? 40 : 20,
height: isSelected ? 40 : 20,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
),
);
}
}

View File

@@ -23,6 +23,9 @@ dependencies:
flutter_spinkit: ^5.0.0
flutter_dotenv: ^5.1.0
carousel_slider: ^4.2.1
flutter_form_builder: ^9.2.1
image_picker: ^1.0.7
flutter_typeahead: ^5.2.0
dev_dependencies:
dart_code_metrics: ^5.7.6