forked from eatvio/eatvio_app
Merge pull request 'diary' (#15) from diary into main
Reviewed-on: maxxkim/eatvio_app#15
This commit is contained in:
2
.env.example
Normal file
2
.env.example
Normal 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
44
ios/Podfile
Normal 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
|
||||
@@ -41,5 +41,9 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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});
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
152
lib/widgets/custom_edit_text_form_field.dart
Normal file
152
lib/widgets/custom_edit_text_form_field.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -96,7 +96,6 @@ class CustomImageView extends StatelessWidget {
|
||||
height: height,
|
||||
width: width,
|
||||
fit: fit ?? BoxFit.contain,
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
case ImageType.file:
|
||||
|
||||
28
lib/widgets/custom_scale_element.dart
Normal file
28
lib/widgets/custom_scale_element.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user