forked from eatvio/eatvio_app
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
1
android/.idea/gradle.xml
generated
1
android/.idea/gradle.xml
generated
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
|
||||
45
android/.idea/workspace.xml
generated
45
android/.idea/workspace.xml
generated
@@ -5,8 +5,9 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="48538bf9-f01e-4931-b825-e9023d9f83f3" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/app/build.gradle" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/settings.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/settings.gradle" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -19,33 +20,33 @@
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="ProjectColorInfo"><![CDATA[{
|
||||
"associatedIndex": 0
|
||||
}]]></component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 0
|
||||
}</component>
|
||||
<component name="ProjectId" id="2ogeByQ5QpkVqOhNR7IKHeDp4Dx" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||
"android.gradle.sync.needed": "true",
|
||||
"cf.first.check.clang-format": "false",
|
||||
"cidr.known.project.marker": "true",
|
||||
"dart.analysis.tool.window.visible": "false",
|
||||
"git-widget-placeholder": "main",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/mso7nueh/eatvio_app/android",
|
||||
"project.structure.last.edited": "Suggestions",
|
||||
"project.structure.proportion": "0.17",
|
||||
"project.structure.side.proportion": "0.2",
|
||||
"settings.editor.selected.configurable": "reference.settingsdialog.project.gradle",
|
||||
"show.migrate.to.gradle.popup": "false"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||
"android.gradle.sync.needed": "true",
|
||||
"cf.first.check.clang-format": "false",
|
||||
"cidr.known.project.marker": "true",
|
||||
"dart.analysis.tool.window.visible": "false",
|
||||
"git-widget-placeholder": "main",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/mso7nueh/eatvio_app/android",
|
||||
"project.structure.last.edited": "Suggestions",
|
||||
"project.structure.proportion": "0.17",
|
||||
"project.structure.side.proportion": "0.2",
|
||||
"settings.editor.selected.configurable": "reference.settingsdialog.project.gradle",
|
||||
"show.migrate.to.gradle.popup": "false"
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="PsdUISettings">
|
||||
<option name="MODULE_TAB" value="Signing Configs" />
|
||||
<option name="LAST_EDITED_SIGNING_CONFIG" value="debug" />
|
||||
|
||||
@@ -6,8 +6,8 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "com.eatvioapp.app"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
compileSdk = 35
|
||||
ndkVersion = "28.0.12433566"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
@@ -21,7 +21,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId = "com.eatvioapp.app"
|
||||
minSdk = flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
targetSdk = 35
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-all.zip
|
||||
|
||||
45
lib/core/image_compressing/image_compress_utility.dart
Normal file
45
lib/core/image_compressing/image_compress_utility.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
abstract class ImageCompressUtility {
|
||||
static Future<List<File>> compressFilesList(List<File> files) async {
|
||||
final List<File> compressedFilesList = [];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
compressedFilesList.add(await compressFile(files[i]));
|
||||
}
|
||||
return compressedFilesList;
|
||||
}
|
||||
|
||||
static Future<File> compressFile(File file) async {
|
||||
final image = img.decodeImage(file.readAsBytesSync())!;
|
||||
int width = image.width;
|
||||
int height = image.height;
|
||||
|
||||
if (width > height) {
|
||||
if (width > 1080) {
|
||||
height = (height * 1080) ~/ width;
|
||||
width = 1080;
|
||||
}
|
||||
} else {
|
||||
if (height > 1080) {
|
||||
width = (width * 1080) ~/ height;
|
||||
height = 1080;
|
||||
}
|
||||
}
|
||||
|
||||
String filePathWithoutExtension = p.withoutExtension(file.path);
|
||||
String compressedFilePath = '${filePathWithoutExtension}_compressed.jpg';
|
||||
|
||||
final result = await FlutterImageCompress.compressAndGetFile(
|
||||
file.absolute.path,
|
||||
compressedFilePath,
|
||||
quality: 90,
|
||||
minHeight: height,
|
||||
minWidth: width,
|
||||
);
|
||||
|
||||
return File(result!.path);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart';
|
||||
import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
@@ -144,7 +145,7 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
await chatRepository.sendMessage(
|
||||
chatId: chatId,
|
||||
data: data,
|
||||
files: files,
|
||||
files: files != null ? await ImageCompressUtility.compressFilesList(files) : null,
|
||||
);
|
||||
AudioPlayer().play((AssetSource('audio/send_message.wav')));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart';
|
||||
@@ -38,6 +39,6 @@ class RegisterConsultantCubit extends Cubit<RegisterConsultantState> {
|
||||
}
|
||||
|
||||
Future<List<String>> uploadPhotos(List<File> files) async {
|
||||
return await consultantRepository.uploadPhotos(files: files);
|
||||
return await consultantRepository.uploadPhotos(files: await ImageCompressUtility.compressFilesList(files));
|
||||
}
|
||||
}
|
||||
|
||||
16
lib/features/diary/models/finish_diary_day_model.dart
Normal file
16
lib/features/diary/models/finish_diary_day_model.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'finish_diary_day_model.freezed.dart';
|
||||
|
||||
part 'finish_diary_day_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class FinishDiaryDayModel with _$FinishDiaryDayModel {
|
||||
const factory FinishDiaryDayModel({
|
||||
required String wakeUp,
|
||||
required String retire,
|
||||
required String comment,
|
||||
}) = _FinishDiaryDayModel;
|
||||
|
||||
factory FinishDiaryDayModel.fromJson(Map<String, Object?> json) => _$FinishDiaryDayModelFromJson(json);
|
||||
}
|
||||
201
lib/features/diary/models/finish_diary_day_model.freezed.dart
Normal file
201
lib/features/diary/models/finish_diary_day_model.freezed.dart
Normal file
@@ -0,0 +1,201 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'finish_diary_day_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
FinishDiaryDayModel _$FinishDiaryDayModelFromJson(Map<String, dynamic> json) {
|
||||
return _FinishDiaryDayModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$FinishDiaryDayModel {
|
||||
String get wakeUp => throw _privateConstructorUsedError;
|
||||
String get retire => throw _privateConstructorUsedError;
|
||||
String get comment => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this FinishDiaryDayModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$FinishDiaryDayModelCopyWith<FinishDiaryDayModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $FinishDiaryDayModelCopyWith<$Res> {
|
||||
factory $FinishDiaryDayModelCopyWith(
|
||||
FinishDiaryDayModel value, $Res Function(FinishDiaryDayModel) then) =
|
||||
_$FinishDiaryDayModelCopyWithImpl<$Res, FinishDiaryDayModel>;
|
||||
@useResult
|
||||
$Res call({String wakeUp, String retire, String comment});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$FinishDiaryDayModelCopyWithImpl<$Res, $Val extends FinishDiaryDayModel>
|
||||
implements $FinishDiaryDayModelCopyWith<$Res> {
|
||||
_$FinishDiaryDayModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? wakeUp = null,
|
||||
Object? retire = null,
|
||||
Object? comment = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
wakeUp: null == wakeUp
|
||||
? _value.wakeUp
|
||||
: wakeUp // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
retire: null == retire
|
||||
? _value.retire
|
||||
: retire // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FinishDiaryDayModelImplCopyWith<$Res>
|
||||
implements $FinishDiaryDayModelCopyWith<$Res> {
|
||||
factory _$$FinishDiaryDayModelImplCopyWith(_$FinishDiaryDayModelImpl value,
|
||||
$Res Function(_$FinishDiaryDayModelImpl) then) =
|
||||
__$$FinishDiaryDayModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String wakeUp, String retire, String comment});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FinishDiaryDayModelImplCopyWithImpl<$Res>
|
||||
extends _$FinishDiaryDayModelCopyWithImpl<$Res, _$FinishDiaryDayModelImpl>
|
||||
implements _$$FinishDiaryDayModelImplCopyWith<$Res> {
|
||||
__$$FinishDiaryDayModelImplCopyWithImpl(_$FinishDiaryDayModelImpl _value,
|
||||
$Res Function(_$FinishDiaryDayModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? wakeUp = null,
|
||||
Object? retire = null,
|
||||
Object? comment = null,
|
||||
}) {
|
||||
return _then(_$FinishDiaryDayModelImpl(
|
||||
wakeUp: null == wakeUp
|
||||
? _value.wakeUp
|
||||
: wakeUp // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
retire: null == retire
|
||||
? _value.retire
|
||||
: retire // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
comment: null == comment
|
||||
? _value.comment
|
||||
: comment // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$FinishDiaryDayModelImpl implements _FinishDiaryDayModel {
|
||||
const _$FinishDiaryDayModelImpl(
|
||||
{required this.wakeUp, required this.retire, required this.comment});
|
||||
|
||||
factory _$FinishDiaryDayModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$FinishDiaryDayModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String wakeUp;
|
||||
@override
|
||||
final String retire;
|
||||
@override
|
||||
final String comment;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FinishDiaryDayModel(wakeUp: $wakeUp, retire: $retire, comment: $comment)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FinishDiaryDayModelImpl &&
|
||||
(identical(other.wakeUp, wakeUp) || other.wakeUp == wakeUp) &&
|
||||
(identical(other.retire, retire) || other.retire == retire) &&
|
||||
(identical(other.comment, comment) || other.comment == comment));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, wakeUp, retire, comment);
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FinishDiaryDayModelImplCopyWith<_$FinishDiaryDayModelImpl> get copyWith =>
|
||||
__$$FinishDiaryDayModelImplCopyWithImpl<_$FinishDiaryDayModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$FinishDiaryDayModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _FinishDiaryDayModel implements FinishDiaryDayModel {
|
||||
const factory _FinishDiaryDayModel(
|
||||
{required final String wakeUp,
|
||||
required final String retire,
|
||||
required final String comment}) = _$FinishDiaryDayModelImpl;
|
||||
|
||||
factory _FinishDiaryDayModel.fromJson(Map<String, dynamic> json) =
|
||||
_$FinishDiaryDayModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get wakeUp;
|
||||
@override
|
||||
String get retire;
|
||||
@override
|
||||
String get comment;
|
||||
|
||||
/// Create a copy of FinishDiaryDayModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FinishDiaryDayModelImplCopyWith<_$FinishDiaryDayModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
23
lib/features/diary/models/finish_diary_day_model.g.dart
Normal file
23
lib/features/diary/models/finish_diary_day_model.g.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'finish_diary_day_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$FinishDiaryDayModelImpl _$$FinishDiaryDayModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$FinishDiaryDayModelImpl(
|
||||
wakeUp: json['wakeUp'] as String,
|
||||
retire: json['retire'] as String,
|
||||
comment: json['comment'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$FinishDiaryDayModelImplToJson(
|
||||
_$FinishDiaryDayModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'wakeUp': instance.wakeUp,
|
||||
'retire': instance.retire,
|
||||
'comment': instance.comment,
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
||||
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
@@ -34,6 +35,19 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
}
|
||||
}
|
||||
|
||||
finishDiaryDay({
|
||||
required String date,
|
||||
required int diaryId,
|
||||
}) async {
|
||||
await diaryRepository.finishDiaryDay(
|
||||
diaryId: diaryId,
|
||||
wakeUp: '',
|
||||
retire: '',
|
||||
comment: '',
|
||||
);
|
||||
await getDiaryDay(date, false);
|
||||
}
|
||||
|
||||
Future<NutritionDataModel> getNutrition(int index) async {
|
||||
return (await diaryRepository.getNutritionData(index));
|
||||
}
|
||||
@@ -101,7 +115,7 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
required String date,
|
||||
}) async {
|
||||
await diaryRepository.uploadPhotos(
|
||||
files: files,
|
||||
files: await ImageCompressUtility.compressFilesList(files),
|
||||
diaryId: diaryId,
|
||||
mealId: mealId,
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
||||
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/finish_day_button_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/satiety_rating_widget.dart';
|
||||
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
@@ -33,6 +34,7 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
CalendarFormat _calendarFormat = CalendarFormat.month;
|
||||
DateTime _focusedDay = DateTime.now();
|
||||
DateTime? _selectedDay = DateTime.now();
|
||||
late final DateTime? today;
|
||||
int currentSelectedMealNumber = 1;
|
||||
GlossaryModel? selectedGlossary;
|
||||
final productNameController = TextEditingController();
|
||||
@@ -40,6 +42,13 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
int currentSelectedPhotoIndex = 0;
|
||||
String time = "${DateTime.now().hour.toString().padLeft(2, '0')}:${DateTime.now().minute.toString().padLeft(2, '0')}";
|
||||
DateTime _time = DateTime.now();
|
||||
bool enableQuantity = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
today = _selectedDay;
|
||||
}
|
||||
|
||||
_showDatePicker() {
|
||||
showModalBottomSheet<void>(
|
||||
@@ -65,12 +74,6 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
useSafeArea: false,
|
||||
context: context,
|
||||
builder: (context) => GlossaryModerationRequestModalWidget(),
|
||||
);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
@@ -128,6 +131,11 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
state.currentSelectedSatietyRating,
|
||||
),
|
||||
if (state is DiaryStateLoaded) _chart(state.nutrition),
|
||||
if (state is DiaryStateLoaded && state.diary.closed == 0 && _selectedDay == today)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: FinishDayButtonWidget(diaryDay: state.diary),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
@@ -164,13 +172,20 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
_nextCalendarFormat() {
|
||||
setState(() {
|
||||
_calendarFormat = CalendarFormat.values[(_calendarFormat.index - 1) % CalendarFormat.values.length];
|
||||
});
|
||||
}
|
||||
|
||||
_arrowDown() {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onVerticalDragStart: (_) {
|
||||
setState(() {
|
||||
_calendarFormat = CalendarFormat.values[(_calendarFormat.index - 1) % CalendarFormat.values.length];
|
||||
});
|
||||
_nextCalendarFormat();
|
||||
},
|
||||
onTap: () {
|
||||
_nextCalendarFormat();
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
@@ -504,17 +519,27 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
_chartData('Калории',
|
||||
'${nutrition.dailyNutritionIntake.energy.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.energy.toStringAsFixed(0)} ккал',),
|
||||
_chartData(
|
||||
'Калории',
|
||||
'${nutrition.dailyNutritionIntake.energy.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.energy.toStringAsFixed(0)} ккал',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_chartData('Белки',
|
||||
'${nutrition.dailyNutritionIntake.proteins.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.proteins.toStringAsFixed(0)} грамм',),
|
||||
_chartData(
|
||||
'Белки',
|
||||
'${nutrition.dailyNutritionIntake.proteins.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.proteins.toStringAsFixed(
|
||||
0,
|
||||
)} грамм',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_chartData('Жиры',
|
||||
'${nutrition.dailyNutritionIntake.fats.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.fats.toStringAsFixed(0)} грамм',),
|
||||
_chartData(
|
||||
'Жиры',
|
||||
'${nutrition.dailyNutritionIntake.fats.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.fats.toStringAsFixed(0)} грамм',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_chartData('Углеводы',
|
||||
'${nutrition.dailyNutritionIntake.carbohydrates.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.carbohydrates.toStringAsFixed(0)} грамм',),
|
||||
_chartData(
|
||||
'Углеводы',
|
||||
'${nutrition.dailyNutritionIntake.carbohydrates.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.carbohydrates.toStringAsFixed(0)} грамм',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -835,7 +860,10 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, void Function(void Function()) setState) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16) + EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
||||
padding: const EdgeInsets.all(16) +
|
||||
EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -878,6 +906,11 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
selectedGlossary = suggestionsList.first;
|
||||
});
|
||||
}
|
||||
if (suggestionsList.length == 0) {
|
||||
setState(() {
|
||||
enableQuantity = true;
|
||||
});
|
||||
}
|
||||
return suggestionsList;
|
||||
},
|
||||
builder: (context, controller, focusNode) {
|
||||
@@ -888,21 +921,31 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
hintText: 'Введите название продукта/блюда',
|
||||
);
|
||||
},
|
||||
emptyBuilder: (context) => const SizedBox.shrink(),
|
||||
emptyBuilder: (context) {
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
errorBuilder: (context, object) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text('Нет подходящих вариантов'),
|
||||
),
|
||||
),
|
||||
if (selectedGlossary != null)
|
||||
if (selectedGlossary != null || enableQuantity)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: CustomTextFormField(
|
||||
controller: quantityController,
|
||||
keyboardType: TextInputType.number,
|
||||
hintText: selectedGlossary!.grInPortion == 0 ? '100' : '1',
|
||||
hintText: selectedGlossary == null
|
||||
? '100'
|
||||
: selectedGlossary!.grInPortion == 0
|
||||
? '100'
|
||||
: '1',
|
||||
autofocus: true,
|
||||
suffixText: selectedGlossary!.grInPortion == 0 ? 'гр' : 'шт',
|
||||
suffixText: selectedGlossary == null
|
||||
? 'гр'
|
||||
: selectedGlossary?.grInPortion == 0
|
||||
? 'гр'
|
||||
: 'шт',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -941,7 +984,11 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
diaryId: diaryDay.id,
|
||||
mealId: diaryDay.meals[currentSelectedMealNumber - 1].id,
|
||||
productName: productNameController.text,
|
||||
portion: selectedGlossary!.grInPortion == 0 ? 'gr' : 'pcs',
|
||||
portion: selectedGlossary == null
|
||||
? 'gr'
|
||||
: selectedGlossary!.grInPortion == 0
|
||||
? 'gr'
|
||||
: 'pcs',
|
||||
quantity: int.parse(quantityController.text),
|
||||
date: _selectedDay.toString(),
|
||||
);
|
||||
@@ -951,12 +998,32 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
mealId: diaryDay.meals[currentSelectedMealNumber - 1].id,
|
||||
portionId: portionId,
|
||||
productName: productNameController.text,
|
||||
portion: selectedGlossary!.grInPortion == 0 ? 'gr' : 'pcs',
|
||||
portion: selectedGlossary == null
|
||||
? 'gr'
|
||||
: selectedGlossary!.grInPortion == 0
|
||||
? 'gr'
|
||||
: 'pcs',
|
||||
quantity: int.parse(quantityController.text),
|
||||
date: _selectedDay.toString(),
|
||||
);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
if (enableQuantity) {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: GlossaryModerationRequestModalWidget(productName: productNameController.text),
|
||||
),
|
||||
);
|
||||
}
|
||||
setState(() {
|
||||
enableQuantity = false;
|
||||
});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
@@ -994,6 +1061,7 @@ class _DiaryScreenState extends State<DiaryScreen> {
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedGlossary = null;
|
||||
enableQuantity = false;
|
||||
productNameController.clear();
|
||||
quantityController.clear();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class FinishDayButtonWidget extends StatefulWidget {
|
||||
final DiaryDayModel diaryDay;
|
||||
|
||||
const FinishDayButtonWidget({
|
||||
super.key,
|
||||
required this.diaryDay,
|
||||
});
|
||||
|
||||
@override
|
||||
State<FinishDayButtonWidget> createState() => _FinishDayButtonWidgetState();
|
||||
}
|
||||
|
||||
class _FinishDayButtonWidgetState extends State<FinishDayButtonWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => context.read<DiaryCubit>().finishDiaryDay(
|
||||
diaryId: widget.diaryDay.id,
|
||||
date: widget.diaryDay.date,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Закончить день',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,222 @@
|
||||
import 'package:eatvio_app/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/widgets/custom_text_form_field.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GlossaryModerationRequestModalWidget extends StatefulWidget {
|
||||
const GlossaryModerationRequestModalWidget({super.key});
|
||||
final String productName;
|
||||
|
||||
const GlossaryModerationRequestModalWidget({
|
||||
super.key,
|
||||
required this.productName,
|
||||
});
|
||||
|
||||
@override
|
||||
State<GlossaryModerationRequestModalWidget> createState() => _GlossaryModerationRequestModalWidgetState();
|
||||
}
|
||||
|
||||
enum GlossaryState { alert, addNewProduct, finish }
|
||||
|
||||
class _GlossaryModerationRequestModalWidgetState extends State<GlossaryModerationRequestModalWidget> {
|
||||
GlossaryState glossaryState = GlossaryState.alert;
|
||||
final productNameController = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Column(),
|
||||
if (glossaryState == GlossaryState.alert) {
|
||||
return _alert();
|
||||
} else {
|
||||
return _addNewGlossaryProduct();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
productNameController.text = widget.productName;
|
||||
}
|
||||
|
||||
_alert() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Добавление нового продукта',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Оу... а у нас нет в базе калорийности такого продукта. Если вы знаете, давайте её запишем?',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFF6F6F6),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'В другой раз',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
glossaryState = GlossaryState.addNewProduct;
|
||||
});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Записать',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_addNewGlossaryProduct() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Добавление нового продукта',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Если у вас данные по нему\nпросим заполнить значения на 100гр.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
CustomTextFormField(
|
||||
hintText: 'Сырный суп',
|
||||
controller: productNameController,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
hintText: 'Калории',
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
hintText: 'Белки',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
hintText: 'Жиры',
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
hintText: 'Углеводы',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Сохранить',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,4 +107,20 @@ class DiaryRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> finishDiaryDay({
|
||||
required int diaryId,
|
||||
required String wakeUp,
|
||||
required String retire,
|
||||
required String comment,
|
||||
}) async {
|
||||
return await diaryService.finishDiaryDay(
|
||||
diaryId: diaryId,
|
||||
// finishDiaryDayModel: FinishDiaryDayModel(
|
||||
// wakeUp: wakeUp,
|
||||
// retire: retire,
|
||||
// comment: comment,
|
||||
// ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,4 +65,10 @@ abstract class DiaryService {
|
||||
@Path('meal_id') required int mealId,
|
||||
@Path('portion_id') required int portionId,
|
||||
});
|
||||
|
||||
@POST('/api/diary/{diary_id}/finishDay')
|
||||
Future<void> finishDiaryDay({
|
||||
@Path('diary_id') required int diaryId,
|
||||
// @Body() required FinishDiaryDayModel finishDiaryDayModel,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -292,6 +292,31 @@ class _DiaryService implements DiaryService {
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> finishDiaryDay({required int diaryId}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
const Map<String, dynamic>? _data = null;
|
||||
final _options = _setStreamType<void>(Options(
|
||||
method: 'POST',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/diary/${diaryId}/finishDay',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
)));
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/app_router.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
import 'package:eatvio_app/locator_service.dart';
|
||||
import 'package:eatvio_app/old/feed/blog_post_create_screen/models/blog_post_create_model.dart';
|
||||
@@ -81,7 +83,7 @@ class BlogPostCreateBloc extends Bloc<BlogPostCreateEvent, BlogPostCreateState>
|
||||
'description': description,
|
||||
'state': 'active',
|
||||
'youtube_url': youtubeURL,
|
||||
'image': image != null ? await MultipartFile.fromFile(image.path, filename: image.name) : null,
|
||||
'image': image != null ? await MultipartFile.fromFile((await ImageCompressUtility.compressFile(File(image.path))).path, filename: image.name) : null,
|
||||
});
|
||||
|
||||
final response = await sl<Dio>().post(
|
||||
|
||||
@@ -54,6 +54,8 @@ dependencies:
|
||||
flutter_portal: ^1.1.4
|
||||
fluttertoast: ^8.2.8
|
||||
flutter_rating_bar: ^4.0.1
|
||||
flutter_image_compress: ^2.3.0
|
||||
image: ^4.3.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.13
|
||||
|
||||
Reference in New Issue
Block a user