From 6312de5aa86543e5449317f546f01a3bfae3013a Mon Sep 17 00:00:00 2001 From: maxxkim Date: Thu, 25 Jul 2024 14:16:13 +0300 Subject: [PATCH 1/5] feat(calendar): Initial layouts models and API for calendar --- lib/app_router.dart | 6 + .../calendar/models/calendar_model.dart | 10 +- .../models/calendar_model.freezed.dart | 200 +++--------------- .../calendar/models/calendar_model.g.dart | 20 +- .../presentation/pages/calendar_screen.dart | 109 ++++++++++ .../repositories/calendar_repository.dart | 5 +- .../calendar/services/calendar_service.dart | 2 +- .../calendar/services/calendar_service.g.dart | 11 +- lib/locator_service.dart | 8 + lib/main.dart | 25 ++- lib/widgets/custom_navigation_menu.dart | 13 +- pubspec.yaml | 1 + 12 files changed, 190 insertions(+), 220 deletions(-) create mode 100644 lib/features/calendar/presentation/pages/calendar_screen.dart diff --git a/lib/app_router.dart b/lib/app_router.dart index 50f7968f..9d51f9c9 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -1,4 +1,5 @@ import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/features/calendar/presentation/pages/calendar_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; @@ -245,6 +246,11 @@ class AppRouter { name: 'diaryScreen', builder: (context, state) => DiaryScreen(), ), + GoRoute( + path: '/calendar-screen', + name: 'calendarScreen', + builder: (context, state) => CalendarScreen(), + ), GoRoute( path: '/chat-select-screen', name: 'chatSelectScreen', diff --git a/lib/features/calendar/models/calendar_model.dart b/lib/features/calendar/models/calendar_model.dart index c206175b..c13d5c5d 100644 --- a/lib/features/calendar/models/calendar_model.dart +++ b/lib/features/calendar/models/calendar_model.dart @@ -6,14 +6,8 @@ part 'calendar_model.g.dart'; @freezed class CalendarModel with _$CalendarModel { const factory CalendarModel({ - required int id, - required String state, - required String image, - required String description, - @JsonKey(name: "youtube_url") required String youtubeUrl, - @JsonKey(name: "created_at") required DateTime createdAt, - @JsonKey(name: "updated_at") required DateTime updatedAt, - required String title, + required String date, + Object? diary, }) = _CalendarModel; factory CalendarModel.fromJson(Map json) => diff --git a/lib/features/calendar/models/calendar_model.freezed.dart b/lib/features/calendar/models/calendar_model.freezed.dart index 7f0d3209..fd8f7ea6 100644 --- a/lib/features/calendar/models/calendar_model.freezed.dart +++ b/lib/features/calendar/models/calendar_model.freezed.dart @@ -20,17 +20,8 @@ CalendarModel _$CalendarModelFromJson(Map json) { /// @nodoc mixin _$CalendarModel { - int get id => throw _privateConstructorUsedError; - String get state => throw _privateConstructorUsedError; - String get image => throw _privateConstructorUsedError; - String get description => throw _privateConstructorUsedError; - @JsonKey(name: "youtube_url") - String get youtubeUrl => throw _privateConstructorUsedError; - @JsonKey(name: "created_at") - DateTime get createdAt => throw _privateConstructorUsedError; - @JsonKey(name: "updated_at") - DateTime get updatedAt => throw _privateConstructorUsedError; - String get title => throw _privateConstructorUsedError; + String get date => throw _privateConstructorUsedError; + Object? get diary => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -44,15 +35,7 @@ abstract class $CalendarModelCopyWith<$Res> { CalendarModel value, $Res Function(CalendarModel) then) = _$CalendarModelCopyWithImpl<$Res, CalendarModel>; @useResult - $Res call( - {int id, - String state, - String image, - String description, - @JsonKey(name: "youtube_url") String youtubeUrl, - @JsonKey(name: "created_at") DateTime createdAt, - @JsonKey(name: "updated_at") DateTime updatedAt, - String title}); + $Res call({String date, Object? diary}); } /// @nodoc @@ -68,48 +51,15 @@ class _$CalendarModelCopyWithImpl<$Res, $Val extends CalendarModel> @pragma('vm:prefer-inline') @override $Res call({ - Object? id = null, - Object? state = null, - Object? image = null, - Object? description = null, - Object? youtubeUrl = null, - Object? createdAt = null, - Object? updatedAt = null, - Object? title = null, + Object? date = null, + Object? diary = freezed, }) { return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - state: null == state - ? _value.state - : state // ignore: cast_nullable_to_non_nullable - as String, - image: null == image - ? _value.image - : image // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - youtubeUrl: null == youtubeUrl - ? _value.youtubeUrl - : youtubeUrl // ignore: cast_nullable_to_non_nullable - as String, - createdAt: null == createdAt - ? _value.createdAt - : createdAt // ignore: cast_nullable_to_non_nullable - as DateTime, - updatedAt: null == updatedAt - ? _value.updatedAt - : updatedAt // ignore: cast_nullable_to_non_nullable - as DateTime, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable as String, + diary: freezed == diary ? _value.diary : diary, ) as $Val); } } @@ -122,15 +72,7 @@ abstract class _$$CalendarModelImplCopyWith<$Res> __$$CalendarModelImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {int id, - String state, - String image, - String description, - @JsonKey(name: "youtube_url") String youtubeUrl, - @JsonKey(name: "created_at") DateTime createdAt, - @JsonKey(name: "updated_at") DateTime updatedAt, - String title}); + $Res call({String date, Object? diary}); } /// @nodoc @@ -144,48 +86,15 @@ class __$$CalendarModelImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? id = null, - Object? state = null, - Object? image = null, - Object? description = null, - Object? youtubeUrl = null, - Object? createdAt = null, - Object? updatedAt = null, - Object? title = null, + Object? date = null, + Object? diary = freezed, }) { return _then(_$CalendarModelImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - state: null == state - ? _value.state - : state // ignore: cast_nullable_to_non_nullable - as String, - image: null == image - ? _value.image - : image // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - youtubeUrl: null == youtubeUrl - ? _value.youtubeUrl - : youtubeUrl // ignore: cast_nullable_to_non_nullable - as String, - createdAt: null == createdAt - ? _value.createdAt - : createdAt // ignore: cast_nullable_to_non_nullable - as DateTime, - updatedAt: null == updatedAt - ? _value.updatedAt - : updatedAt // ignore: cast_nullable_to_non_nullable - as DateTime, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable as String, + diary: freezed == diary ? _value.diary : diary, )); } } @@ -193,42 +102,19 @@ class __$$CalendarModelImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$CalendarModelImpl implements _CalendarModel { - const _$CalendarModelImpl( - {required this.id, - required this.state, - required this.image, - required this.description, - @JsonKey(name: "youtube_url") required this.youtubeUrl, - @JsonKey(name: "created_at") required this.createdAt, - @JsonKey(name: "updated_at") required this.updatedAt, - required this.title}); + const _$CalendarModelImpl({required this.date, this.diary}); factory _$CalendarModelImpl.fromJson(Map json) => _$$CalendarModelImplFromJson(json); @override - final int id; + final String date; @override - final String state; - @override - final String image; - @override - final String description; - @override - @JsonKey(name: "youtube_url") - final String youtubeUrl; - @override - @JsonKey(name: "created_at") - final DateTime createdAt; - @override - @JsonKey(name: "updated_at") - final DateTime updatedAt; - @override - final String title; + final Object? diary; @override String toString() { - return 'CalendarModel(id: $id, state: $state, image: $image, description: $description, youtubeUrl: $youtubeUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title)'; + return 'CalendarModel(date: $date, diary: $diary)'; } @override @@ -236,24 +122,14 @@ class _$CalendarModelImpl implements _CalendarModel { return identical(this, other) || (other.runtimeType == runtimeType && other is _$CalendarModelImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.state, state) || other.state == state) && - (identical(other.image, image) || other.image == image) && - (identical(other.description, description) || - other.description == description) && - (identical(other.youtubeUrl, youtubeUrl) || - other.youtubeUrl == youtubeUrl) && - (identical(other.createdAt, createdAt) || - other.createdAt == createdAt) && - (identical(other.updatedAt, updatedAt) || - other.updatedAt == updatedAt) && - (identical(other.title, title) || other.title == title)); + (identical(other.date, date) || other.date == date) && + const DeepCollectionEquality().equals(other.diary, diary)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, id, state, image, description, - youtubeUrl, createdAt, updatedAt, title); + int get hashCode => Object.hash( + runtimeType, date, const DeepCollectionEquality().hash(diary)); @JsonKey(ignore: true) @override @@ -271,37 +147,15 @@ class _$CalendarModelImpl implements _CalendarModel { abstract class _CalendarModel implements CalendarModel { const factory _CalendarModel( - {required final int id, - required final String state, - required final String image, - required final String description, - @JsonKey(name: "youtube_url") required final String youtubeUrl, - @JsonKey(name: "created_at") required final DateTime createdAt, - @JsonKey(name: "updated_at") required final DateTime updatedAt, - required final String title}) = _$CalendarModelImpl; + {required final String date, final Object? diary}) = _$CalendarModelImpl; factory _CalendarModel.fromJson(Map json) = _$CalendarModelImpl.fromJson; @override - int get id; + String get date; @override - String get state; - @override - String get image; - @override - String get description; - @override - @JsonKey(name: "youtube_url") - String get youtubeUrl; - @override - @JsonKey(name: "created_at") - DateTime get createdAt; - @override - @JsonKey(name: "updated_at") - DateTime get updatedAt; - @override - String get title; + Object? get diary; @override @JsonKey(ignore: true) _$$CalendarModelImplCopyWith<_$CalendarModelImpl> get copyWith => diff --git a/lib/features/calendar/models/calendar_model.g.dart b/lib/features/calendar/models/calendar_model.g.dart index d675f9b1..c12dd961 100644 --- a/lib/features/calendar/models/calendar_model.g.dart +++ b/lib/features/calendar/models/calendar_model.g.dart @@ -8,24 +8,12 @@ part of 'calendar_model.dart'; _$CalendarModelImpl _$$CalendarModelImplFromJson(Map json) => _$CalendarModelImpl( - id: (json['id'] as num).toInt(), - state: json['state'] as String, - image: json['image'] as String, - description: json['description'] as String, - youtubeUrl: json['youtube_url'] as String, - createdAt: DateTime.parse(json['created_at'] as String), - updatedAt: DateTime.parse(json['updated_at'] as String), - title: json['title'] as String, + date: json['date'] as String, + diary: json['diary'], ); Map _$$CalendarModelImplToJson(_$CalendarModelImpl instance) => { - 'id': instance.id, - 'state': instance.state, - 'image': instance.image, - 'description': instance.description, - 'youtube_url': instance.youtubeUrl, - 'created_at': instance.createdAt.toIso8601String(), - 'updated_at': instance.updatedAt.toIso8601String(), - 'title': instance.title, + 'date': instance.date, + 'diary': instance.diary, }; diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart new file mode 100644 index 00000000..7ef68dd8 --- /dev/null +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -0,0 +1,109 @@ +// ignore_for_file: unused_local_variable + +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; + +// ignore: must_be_immutable +class CalendarScreen extends StatelessWidget { + CalendarScreen({Key? key}) : super(key: key); + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is CalendarStateLoaded) { + return _buildCalendar(context, state); + } else if (state is CalendarStateLoading) { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } else if (state is CalendarStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text("Неопределенная ошибка"), + ), + ), + ); + }, + ); + } + + Widget _buildCalendar(BuildContext context, CalendarStateLoaded state) { + return Stack(alignment: Alignment.bottomCenter, children: [ + FormBuilder( + child: Scaffold( + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + backgroundColor: Color.fromARGB(255, 240, 242, 245), + resizeToAvoidBottomInset: true, + body: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(bottom: 5.v), + child: Column( + children: [ + SizedBox(height: 20.v), + _buildCalendarBody(context, state), + SizedBox(height: 20.v), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ]); + } + + _buildCalendarBody(BuildContext context, CalendarStateLoaded state) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: TableCalendar( + firstDay: DateTime.utc(2010, 10, 16), + lastDay: DateTime.utc(2030, 3, 14), + focusedDay: DateTime.now(), + ), + ); + } +} diff --git a/lib/features/calendar/repositories/calendar_repository.dart b/lib/features/calendar/repositories/calendar_repository.dart index 97a23dca..fd9f734c 100644 --- a/lib/features/calendar/repositories/calendar_repository.dart +++ b/lib/features/calendar/repositories/calendar_repository.dart @@ -8,10 +8,7 @@ class CalendarRepository { Future> getCalendar() async { try { - return (await calendarService.getCalendar()) - .entries - .map((entry) => entry.value) - .toList(); + return await calendarService.getCalendar(); } catch (e) { rethrow; } diff --git a/lib/features/calendar/services/calendar_service.dart b/lib/features/calendar/services/calendar_service.dart index 80b98e6d..d3e3c973 100644 --- a/lib/features/calendar/services/calendar_service.dart +++ b/lib/features/calendar/services/calendar_service.dart @@ -9,5 +9,5 @@ abstract class CalendarService { factory CalendarService(Dio dio, {String baseUrl}) = _CalendarService; @GET('/calendar/index') - Future> getCalendar(); + Future> getCalendar(); } diff --git a/lib/features/calendar/services/calendar_service.g.dart b/lib/features/calendar/services/calendar_service.g.dart index 57033789..f89b79e8 100644 --- a/lib/features/calendar/services/calendar_service.g.dart +++ b/lib/features/calendar/services/calendar_service.g.dart @@ -19,13 +19,13 @@ class _CalendarService implements CalendarService { String? baseUrl; @override - Future> getCalendar() async { + Future> getCalendar() async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _result = await _dio.fetch>( - _setStreamType>(Options( + final _result = await _dio + .fetch>(_setStreamType>(Options( method: 'GET', headers: _headers, extra: _extra, @@ -41,8 +41,9 @@ class _CalendarService implements CalendarService { _dio.options.baseUrl, baseUrl, )))); - var _value = _result.data!.map((k, dynamic v) => - MapEntry(k, CalendarModel.fromJson(v as Map))); + var _value = _result.data! + .map((dynamic i) => CalendarModel.fromJson(i as Map)) + .toList(); return _value; } diff --git a/lib/locator_service.dart b/lib/locator_service.dart index 7f2caf5d..fa54c505 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -3,6 +3,9 @@ import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/features/blog_post/presentation/bloc/blog_post_cubit.dart'; import 'package:eatvio_app/features/blog_post/repositories/blog_post_repository.dart'; import 'package:eatvio_app/features/blog_post/services/blog_post_service.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; +import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart'; +import 'package:eatvio_app/features/calendar/services/calendar_service.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; @@ -27,6 +30,8 @@ Future init() async { sl.registerFactory( () => BlogPostCubit(blogPostRepository: sl())); sl.registerFactory(() => DiaryBloc(diaryRepository: sl())); + sl.registerFactory( + () => CalendarCubit(calendarRepository: sl())); // Repository sl.registerLazySingleton( @@ -37,12 +42,15 @@ Future init() async { () => BlogPostRepository(blogPostService: sl())); sl.registerLazySingleton( () => DiaryRepository(diaryService: sl())); + sl.registerLazySingleton( + () => CalendarRepository(calendarService: sl())); // Services sl.registerLazySingleton(() => ChatService(sl())); sl.registerLazySingleton(() => FeedService(sl())); sl.registerLazySingleton(() => BlogPostService(sl())); sl.registerLazySingleton(() => DiaryService(sl())); + sl.registerLazySingleton(() => CalendarService(sl())); // External sl.registerLazySingleton( diff --git a/lib/main.dart b/lib/main.dart index f71b4a54..9ce1b92e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/app_router.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/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; @@ -41,13 +42,25 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider(create: (context) => InitializationCubit(chatRepository: sl())), - BlocProvider(create: (context) => ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))), - BlocProvider(create: (context) => sl()..loadFeedBlogPostList()), - BlocProvider(create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent())), - BlocProvider(create: (context) => sl()..add(LoadDiary())), + BlocProvider( + create: (context) => InitializationCubit(chatRepository: sl())), + BlocProvider( + create: (context) => + ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))), + BlocProvider( + create: (context) => sl()..loadFeedBlogPostList()), + BlocProvider( + create: (context) => sl()..loadCalendarList()), + BlocProvider( + create: (context) => MyProfileBloc( + MyProfileState(myProfileModelObj: MyProfileModel())) + ..add(MyProfileInitialEvent())), + BlocProvider( + create: (context) => sl()..add(LoadDiary())), BlocProvider( - create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()), + create: (context) => ChatSelectBloc( + ChatSelectState(chatSelectModelObj: ChatSelectModel())) + ..add(ChatSelectInitialEvent()), ), ], child: BlocListener( diff --git a/lib/widgets/custom_navigation_menu.dart b/lib/widgets/custom_navigation_menu.dart index 03d11a98..0a5d354d 100644 --- a/lib/widgets/custom_navigation_menu.dart +++ b/lib/widgets/custom_navigation_menu.dart @@ -23,19 +23,21 @@ class CustomNavigationMenu extends StatelessWidget { icon: ImageConstant.imgRecipes, text: 'Мои рецепты', onTap: () => GoRouter.of(context).push('/recipe-select-screen'), - // Действие при нажатии на "Мои рецепты" ), MenuItem( icon: ImageConstant.imgDiets, text: 'Мои диеты', onTap: () => GoRouter.of(context).push('/diet-select-screen'), - // Действие при нажатии на "Мои рецепты" ), MenuItem( icon: ImageConstant.imgPlans, text: 'Мои планы', onTap: () => GoRouter.of(context).push('/plan-select-screen'), - // Действие при нажатии на "Мои рецепты" + ), + MenuItem( + icon: ImageConstant.imgRecipes, + text: 'Календарь', + onTap: () => GoRouter.of(context).push('/calendar-screen'), ), MenuItem( icon: ImageConstant.imgFinance, @@ -45,15 +47,12 @@ class CustomNavigationMenu extends StatelessWidget { MenuItem( icon: ImageConstant.imgSupport, text: 'Поддержка', - onTap: () { - // Действие при нажатии на "Поддержка" - }, + onTap: () {}, ), MenuItem( icon: ImageConstant.imgExit, text: 'Выход', onTap: _onTapLogout(context), - // Действие при нажатии на "Выход" ), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 8a60729f..a7974983 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,7 @@ dependencies: # debounce easy_debounce: ^2.0.3 syncfusion_flutter_charts: ^26.1.42 + table_calendar: ^3.1.2 dev_dependencies: build_runner: ^2.4.11 From 102154ddb264ab7910555748e3996f1aecbb3800 Mon Sep 17 00:00:00 2001 From: maxxkim Date: Thu, 25 Jul 2024 15:29:30 +0300 Subject: [PATCH 2/5] feat(calendar): Calendar Event class --- .../presentation/pages/calendar_screen.dart | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart index 7ef68dd8..93179cb3 100644 --- a/lib/features/calendar/presentation/pages/calendar_screen.dart +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -7,6 +7,7 @@ import 'package:table_calendar/table_calendar.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'dart:collection'; // ignore: must_be_immutable class CalendarScreen extends StatelessWidget { @@ -103,7 +104,60 @@ class CalendarScreen extends StatelessWidget { firstDay: DateTime.utc(2010, 10, 16), lastDay: DateTime.utc(2030, 3, 14), focusedDay: DateTime.now(), + eventLoader: (day) { + if (day.weekday == DateTime.monday) { + return [Event('Cyclic event')]; + } + + return []; + }, ), ); } } + +/// Example event class. +class Event { + final String title; + + const Event(this.title); + + @override + String toString() => title; +} + +/// Example events. +/// +/// Using a [LinkedHashMap] is highly recommended if you decide to use a map. +final kEvents = LinkedHashMap>( + equals: isSameDay, + hashCode: getHashCode, +)..addAll(_kEventSource); + +final _kEventSource = Map.fromIterable(List.generate(50, (index) => index), + key: (item) => DateTime.utc(kFirstDay.year, kFirstDay.month, item * 5), + value: (item) => List.generate( + item % 4 + 1, (index) => Event('Event $item | ${index + 1}'))) + ..addAll({ + kToday: [ + Event('Today\'s Event 1'), + Event('Today\'s Event 2'), + ], + }); + +int getHashCode(DateTime key) { + return key.day * 1000000 + key.month * 10000 + key.year; +} + +/// Returns a list of [DateTime] objects from [first] to [last], inclusive. +List daysInRange(DateTime first, DateTime last) { + final dayCount = last.difference(first).inDays + 1; + return List.generate( + dayCount, + (index) => DateTime.utc(first.year, first.month, first.day + index), + ); +} + +final kToday = DateTime.now(); +final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); +final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); From 56e5cdbe168ff5ab0254337c4ed51bcdc4a13728 Mon Sep 17 00:00:00 2001 From: maxxkim Date: Thu, 25 Jul 2024 16:53:49 +0300 Subject: [PATCH 3/5] fix(calendar): Finished days fix --- .../presentation/pages/calendar_screen.dart | 80 +++-- .../diary/presentation/bloc/diary_bloc.dart | 115 ++----- .../diary/presentation/bloc/diary_state.dart | 4 +- .../bloc/diary_state.freezed.dart | 92 +++--- .../presentation/pages/diary_screen.dart | 284 ++---------------- .../diary/repositories/diary_repository.dart | 18 +- .../diary/services/diary_service.dart | 9 +- .../diary/services/diary_service.g.dart | 13 +- 8 files changed, 132 insertions(+), 483 deletions(-) diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart index 93179cb3..9dab6be2 100644 --- a/lib/features/calendar/presentation/pages/calendar_screen.dart +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -1,5 +1,6 @@ // ignore_for_file: unused_local_variable +import 'package:eatvio_app/features/calendar/models/calendar_model.dart'; import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart'; import 'package:eatvio_app/core/app_export.dart'; @@ -7,7 +8,6 @@ import 'package:table_calendar/table_calendar.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'dart:collection'; // ignore: must_be_immutable class CalendarScreen extends StatelessWidget { @@ -104,60 +104,48 @@ class CalendarScreen extends StatelessWidget { firstDay: DateTime.utc(2010, 10, 16), lastDay: DateTime.utc(2030, 3, 14), focusedDay: DateTime.now(), - eventLoader: (day) { - if (day.weekday == DateTime.monday) { - return [Event('Cyclic event')]; - } - - return []; - }, + startingDayOfWeek: StartingDayOfWeek.monday, + calendarBuilders: CalendarBuilders( + selectedBuilder: (context, day, focusedDay) => _buildCellDate(day, focusedDay: focusedDay, state), + defaultBuilder: (context, day, focusedDay) => _buildCellDate(day, state), + todayBuilder: (context, day, focusedDay) => _buildCellDate(day, state), + ), ), ); } } -/// Example event class. -class Event { - final String title; +Widget _buildCellDate(DateTime day, CalendarStateLoaded state, {DateTime? focusedDay}) { + final String dayString = day.toIso8601String().split('T').first; + final List calendarModels = state.calendarList; - const Event(this.title); + // Находим первую модель, соответствующую дате + final CalendarModel model = calendarModels.firstWhere((model) => model.date == dayString, orElse: () => CalendarModel(date: dayString, diary: {})); - @override - String toString() => title; -} + Color? bgclr; // Объявляем переменную bgclr здесь -/// Example events. -/// -/// Using a [LinkedHashMap] is highly recommended if you decide to use a map. -final kEvents = LinkedHashMap>( - equals: isSameDay, - hashCode: getHashCode, -)..addAll(_kEventSource); + if (model.diary is Map) { + final Map diary = model.diary as Map; -final _kEventSource = Map.fromIterable(List.generate(50, (index) => index), - key: (item) => DateTime.utc(kFirstDay.year, kFirstDay.month, item * 5), - value: (item) => List.generate( - item % 4 + 1, (index) => Event('Event $item | ${index + 1}'))) - ..addAll({ - kToday: [ - Event('Today\'s Event 1'), - Event('Today\'s Event 2'), - ], - }); + if (diary['state'] == "started") { + bgclr = Colors.grey; + } else if (diary['state'] == "finished") { + bgclr = Colors.green; + } else { + bgclr = Colors.white; + } + } else { + bgclr = Colors.white; // Значение по умолчанию, если diary не является Map + } -int getHashCode(DateTime key) { - return key.day * 1000000 + key.month * 10000 + key.year; -} - -/// Returns a list of [DateTime] objects from [first] to [last], inclusive. -List daysInRange(DateTime first, DateTime last) { - final dayCount = last.difference(first).inDays + 1; - return List.generate( - dayCount, - (index) => DateTime.utc(first.year, first.month, first.day + index), + return Container( + margin: const EdgeInsets.all(5), + alignment: Alignment.center, + decoration: BoxDecoration( + shape: (day == focusedDay) ? BoxShape.circle : BoxShape.rectangle, + color: bgclr, + borderRadius: (day == focusedDay) ? null : BorderRadius.circular(4), + ), + child: Text(day.day.toString(), style: TextStyle(color: Colors.black)), ); } - -final kToday = DateTime.now(); -final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); -final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); diff --git a/lib/features/diary/presentation/bloc/diary_bloc.dart b/lib/features/diary/presentation/bloc/diary_bloc.dart index e6903353..8ac0e8a2 100644 --- a/lib/features/diary/presentation/bloc/diary_bloc.dart +++ b/lib/features/diary/presentation/bloc/diary_bloc.dart @@ -9,9 +9,6 @@ import 'package:flutter/material.dart'; import '/core/app_export.dart'; import 'package:image_picker/image_picker.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; part 'diary_event.dart'; @@ -19,8 +16,7 @@ part 'diary_event.dart'; class DiaryBloc extends Bloc { final DiaryRepository diaryRepository; - DiaryBloc({required this.diaryRepository}) - : super(const DiaryState.loading()) { + DiaryBloc({required this.diaryRepository}) : super(const DiaryState.loading()) { on(loadDiary); on(_changeSatiety); // пользователь нажимает на шкалу сытости on(_changeMood); // пользователь нажимает на шкалу настроения @@ -57,29 +53,15 @@ class DiaryBloc extends Bloc { final DiaryModel diary = await diaryRepository.getDiary(diaryID ?? 45); final Meal currentMeal = diary.meals[0]; - List portionList = [ - SelectionPopupModel(title: "gr"), - SelectionPopupModel(title: "pcs") - ]; + List portionList = [SelectionPopupModel(title: "gr"), SelectionPopupModel(title: "pcs")]; - final Map chartData = - await diaryRepository.getChartData(diaryID ?? 45); - final Map dailyNutritionIntake = - chartData['dailyNutritionIntake']!; - final Map dailyNutritionRecommendations = - chartData['dailyNutritionRecommendation']!; - final double ccal = dailyNutritionIntake['energy']! / - dailyNutritionRecommendations['energy']! * - 100; - final double proteins = dailyNutritionIntake['proteins']! / - dailyNutritionRecommendations['proteins']! * - 100; - final double fats = dailyNutritionIntake['fats']! / - dailyNutritionRecommendations['fats']! * - 100; - final double carbs = dailyNutritionIntake['carbohydrates']! / - dailyNutritionRecommendations['carbohydrates']! * - 100; + final Map chartData = await diaryRepository.getChartData(diaryID ?? 45); + final Map dailyNutritionIntake = chartData['dailyNutritionIntake']!; + final Map dailyNutritionRecommendations = chartData['dailyNutritionRecommendation']!; + final double ccal = dailyNutritionIntake['energy']! / dailyNutritionRecommendations['energy']! * 100; + final double proteins = dailyNutritionIntake['proteins']! / dailyNutritionRecommendations['proteins']! * 100; + final double fats = dailyNutritionIntake['fats']! / dailyNutritionRecommendations['fats']! * 100; + final double carbs = dailyNutritionIntake['carbohydrates']! / dailyNutritionRecommendations['carbohydrates']! * 100; Color getColor(double value) { if (value >= 99.1) { @@ -105,8 +87,6 @@ class DiaryBloc extends Bloc { SelectionPopupModel(title: "Прием пищи 6", id: 6), ]; - print(dailyNutritionRecommendations); - print(dailyNutritionIntake); emit(DiaryState.loaded( diary: diary, currentMeal: currentMeal, @@ -117,6 +97,8 @@ class DiaryBloc extends Bloc { chartData: chartDataCounted, selectedMood: currentMeal.mood, selectedSatiety: currentMeal.satiety, + wakeupController: TimeOfDay.now(), + retireController: TimeOfDay.now(), commentController: TextEditingController(), product_nameController: TextEditingController(), productQuantityController: TextEditingController(), @@ -137,54 +119,6 @@ class DiaryBloc extends Bloc { } } - fetchChartValues( - String token, - int diaryID, - Emitter emit, - ) async { - final responseChart = await http.get( - Uri.parse( - dotenv.env['SERVER_ROOT']! + '/diary/$diaryID/dailyNutritionData/', - ), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $token', - }, - ); - - if (responseChart.statusCode == 200) { - final responseBody = jsonDecode(responseChart.body); - print(responseBody); - final recommendedChartValues = - responseBody['dailyNutritionRecommendation'] - .values - .map((value) => convertToInt(value)) - .toList(); - - final consumedChartValues = responseBody['dailyNutritionIntake'] - .values - .map((value) => convertToInt(value)) - .toList(); - - print([ - recommendedChartValues, - consumedChartValues, - ]); - return [ - recommendedChartValues, - consumedChartValues, - ]; - } else { - emit(DiaryStateError( - errorMessage: 'Ошибка при декодировании данных КБЖУ')); - print('fail'); - return [ - [], - [], - ]; - } - } - Future _changeSatiety( ChangeSatiety event, Emitter emit, @@ -229,11 +163,9 @@ class DiaryBloc extends Bloc { ) async { if (state is DiaryStateLoaded) { var currentState = state as DiaryStateLoaded; - var updatedState = - currentState.copyWith(wakeupController: event.selectedTime); + var updatedState = currentState.copyWith(wakeupController: event.selectedTime); final DateFormat formatter = DateFormat('HH:mm'); - final String wakeupString = formatter.format(DateTime( - 2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); + final String wakeupString = formatter.format(DateTime(2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); await diaryRepository.changeWakeup( currentState.diary.id, wakeupString, @@ -248,11 +180,9 @@ class DiaryBloc extends Bloc { ) async { if (state is DiaryStateLoaded) { var currentState = state as DiaryStateLoaded; - var updatedState = - currentState.copyWith(retireController: event.selectedTime); + var updatedState = currentState.copyWith(retireController: event.selectedTime); final DateFormat formatter = DateFormat('HH:mm'); - final String retireString = formatter.format(DateTime( - 2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); + final String retireString = formatter.format(DateTime(2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); await diaryRepository.changeRetire( currentState.diary.id, retireString, @@ -278,8 +208,7 @@ class DiaryBloc extends Bloc { ) async { if (state is DiaryStateLoaded) { final currentState = state as DiaryStateLoaded; - final Meal meal = currentState.diary.meals - .firstWhere((meal) => meal.type == event.value.id); + final Meal meal = currentState.diary.meals.firstWhere((meal) => meal.type == event.value.id); DiaryStateLoaded updatedState = currentState.copyWith( currentMeal: meal, portions: meal.portions, @@ -298,12 +227,10 @@ class DiaryBloc extends Bloc { if (state is DiaryStateLoaded) { var currentState = state as DiaryStateLoaded; - final Map> productNutritionalValues = - await diaryRepository.inputProduct(event.input); + final Map> productNutritionalValues = await diaryRepository.inputProduct(event.input); var updatedState = currentState.copyWith( product_nameController: TextEditingController(text: event.input), - autocompleteList: - productNutritionalValues['product_nutritional_value'] ?? [], + autocompleteList: productNutritionalValues['product_nutritional_value'] ?? [], ); if (event.input.length > 3) { updatedState = updatedState.copyWith(moderationExpanded: true); @@ -449,9 +376,9 @@ class DiaryBloc extends Bloc { await diaryRepository.finishDay( currentState.diary.id, - currentState.wakeupController, - currentState.retireController, - currentState.commentController.text, + // currentState.wakeupController, + // currentState.retireController, + // currentState.commentController.text, ); add(LoadDiary()); } diff --git a/lib/features/diary/presentation/bloc/diary_state.dart b/lib/features/diary/presentation/bloc/diary_state.dart index 6feb5f14..91565766 100644 --- a/lib/features/diary/presentation/bloc/diary_state.dart +++ b/lib/features/diary/presentation/bloc/diary_state.dart @@ -26,8 +26,8 @@ abstract class DiaryState with _$DiaryState { required List autocompleteList, required Meal currentMeal, required SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + required TimeOfDay wakeupController, + required TimeOfDay retireController, TimeOfDay? mealTimeController, required TextEditingController commentController, required TextEditingController product_nameController, diff --git a/lib/features/diary/presentation/bloc/diary_state.freezed.dart b/lib/features/diary/presentation/bloc/diary_state.freezed.dart index deda8724..a8cf8f18 100644 --- a/lib/features/diary/presentation/bloc/diary_state.freezed.dart +++ b/lib/features/diary/presentation/bloc/diary_state.freezed.dart @@ -31,8 +31,8 @@ mixin _$DiaryState { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -68,8 +68,8 @@ mixin _$DiaryState { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -105,8 +105,8 @@ mixin _$DiaryState { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -224,8 +224,8 @@ class _$DiaryStateImpl implements _DiaryState { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -264,8 +264,8 @@ class _$DiaryStateImpl implements _DiaryState { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -304,8 +304,8 @@ class _$DiaryStateImpl implements _DiaryState { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -425,8 +425,8 @@ class _$DiaryStateLoadingImpl implements DiaryStateLoading { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -465,8 +465,8 @@ class _$DiaryStateLoadingImpl implements DiaryStateLoading { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -505,8 +505,8 @@ class _$DiaryStateLoadingImpl implements DiaryStateLoading { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -592,8 +592,8 @@ abstract class _$$DiaryStateLoadedImplCopyWith<$Res> { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -636,8 +636,8 @@ class __$$DiaryStateLoadedImplCopyWithImpl<$Res> Object? autocompleteList = null, Object? currentMeal = null, Object? portionController = null, - Object? wakeupController = freezed, - Object? retireController = freezed, + Object? wakeupController = null, + Object? retireController = null, Object? mealTimeController = freezed, Object? commentController = null, Object? product_nameController = null, @@ -696,14 +696,14 @@ class __$$DiaryStateLoadedImplCopyWithImpl<$Res> ? _value.portionController : portionController // ignore: cast_nullable_to_non_nullable as SelectionPopupModel, - wakeupController: freezed == wakeupController + wakeupController: null == wakeupController ? _value.wakeupController : wakeupController // ignore: cast_nullable_to_non_nullable - as TimeOfDay?, - retireController: freezed == retireController + as TimeOfDay, + retireController: null == retireController ? _value.retireController : retireController // ignore: cast_nullable_to_non_nullable - as TimeOfDay?, + as TimeOfDay, mealTimeController: freezed == mealTimeController ? _value.mealTimeController : mealTimeController // ignore: cast_nullable_to_non_nullable @@ -802,8 +802,8 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { required final List autocompleteList, required this.currentMeal, required this.portionController, - this.wakeupController, - this.retireController, + required this.wakeupController, + required this.retireController, this.mealTimeController, required this.commentController, required this.product_nameController, @@ -888,9 +888,9 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { @override final SelectionPopupModel portionController; @override - final TimeOfDay? wakeupController; + final TimeOfDay wakeupController; @override - final TimeOfDay? retireController; + final TimeOfDay retireController; @override final TimeOfDay? mealTimeController; @override @@ -1052,8 +1052,8 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -1120,8 +1120,8 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -1188,8 +1188,8 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -1294,8 +1294,8 @@ abstract class DiaryStateLoaded implements DiaryState { required final List autocompleteList, required final Meal currentMeal, required final SelectionPopupModel portionController, - final TimeOfDay? wakeupController, - final TimeOfDay? retireController, + required final TimeOfDay wakeupController, + required final TimeOfDay retireController, final TimeOfDay? mealTimeController, required final TextEditingController commentController, required final TextEditingController product_nameController, @@ -1323,8 +1323,8 @@ abstract class DiaryStateLoaded implements DiaryState { List get autocompleteList; Meal get currentMeal; SelectionPopupModel get portionController; - TimeOfDay? get wakeupController; - TimeOfDay? get retireController; + TimeOfDay get wakeupController; + TimeOfDay get retireController; TimeOfDay? get mealTimeController; TextEditingController get commentController; TextEditingController get product_nameController; @@ -1425,8 +1425,8 @@ class _$DiaryStateErrorImpl implements DiaryStateError { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -1465,8 +1465,8 @@ class _$DiaryStateErrorImpl implements DiaryStateError { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, @@ -1505,8 +1505,8 @@ class _$DiaryStateErrorImpl implements DiaryStateError { List autocompleteList, Meal currentMeal, SelectionPopupModel portionController, - TimeOfDay? wakeupController, - TimeOfDay? retireController, + TimeOfDay wakeupController, + TimeOfDay retireController, TimeOfDay? mealTimeController, TextEditingController commentController, TextEditingController product_nameController, diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index 53937a94..8be9be46 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -278,9 +278,7 @@ class DiaryScreen extends StatelessWidget { borderRadius: BorderRadiusStyle.roundedBorder5, ), child: Center( - child: CircularProgressIndicator( - color: appTheme - .blueGray300), // Замените на свой прелоадер при необходимости + child: CircularProgressIndicator(color: appTheme.blueGray300), // Замените на свой прелоадер при необходимости ), ), ], @@ -304,8 +302,7 @@ class DiaryScreen extends StatelessWidget { _buildMeal(BuildContext context, DiaryStateLoaded state) { final digitsOnly = FilteringTextInputFormatter.digitsOnly; - List _options = - state.autocompleteList.map((Product item) => item.name).toList(); + List _options = state.autocompleteList.map((Product item) => item.name).toList(); FocusNode focusNodeName = FocusNode(); return Container( margin: EdgeInsets.symmetric(horizontal: 16.h), @@ -349,9 +346,7 @@ class DiaryScreen extends StatelessWidget { onTap: () => _selectMealTime(context, state), child: AbsorbPointer( child: CustomTextFormField( - hintText: state.mealTimeController - ?.format(context) - .toString(), + hintText: state.mealTimeController?.format(context).toString(), autofocus: false, ), ), @@ -487,9 +482,7 @@ class DiaryScreen extends StatelessWidget { SizedBox(height: 30.v), _buildAddProduct(context, state), SizedBox(height: 30.v), - ...state.portions - .map((portion) => _buildProduct(context, portion)) - .toList(), + ...state.portions.map((portion) => _buildProduct(context, portion)).toList(), SizedBox(height: 30.v), _buildCarousel(context, state), SizedBox(height: 20.v), @@ -638,8 +631,7 @@ class DiaryScreen extends StatelessWidget { popDialog(BuildContext dialogContext) { return () { - Navigator.of(dialogContext) - .pop(); // Dismiss the dialog on Cancel button press + Navigator.of(dialogContext).pop(); // Dismiss the dialog on Cancel button press }; } @@ -649,8 +641,7 @@ class DiaryScreen extends StatelessWidget { }; } - selectProduct(AutocompleteOnSelected onSelected, String option, - DiaryStateLoaded state) { + selectProduct(AutocompleteOnSelected onSelected, String option, DiaryStateLoaded state) { state.product_nameController.text = option; return () { onSelected(option); @@ -718,9 +709,7 @@ class DiaryScreen extends StatelessWidget { top: 5.v, ), child: Text( - portion.product_name.length > 8 - ? portion.product_name.substring(0, 8) - : portion.product_name, + portion.product_name.length > 8 ? portion.product_name.substring(0, 8) : portion.product_name, style: CustomTextStyles.titleMedium16, ), ), @@ -792,234 +781,10 @@ class DiaryScreen extends StatelessWidget { removePhoto(BuildContext context, Photo photo) { return () { - context - .read() - .add(RemoveImageEvent(photo.id.toString(), photo.path)); + context.read().add(RemoveImageEvent(photo.id.toString(), photo.path)); }; } - /*_buildNutritionChart(BuildContext context, DiaryStateLoaded state) { - final List recommendedValues = state - .recommendedChartValues; // Рекомендуемые значения: калории, жиры, белки, углеводы - final List consumedValues = state.consumedChartValues; // - return Container( - margin: EdgeInsets.symmetric(horizontal: 16.h), - padding: EdgeInsets.symmetric( - horizontal: 10.h, - vertical: 16.v, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: 3.v), - Text( - "Ваш КБЖУ", - style: theme.textTheme.titleMedium, - ), - SizedBox(height: 8.v), - Text( - "От дневной суточной нормы", - style: CustomTextStyles.bodyMediumBluegray800, - ), - SizedBox(height: 19.v), - Align( - alignment: Alignment.centerRight, - child: Padding( - padding: EdgeInsets.only( - left: 30.h, - right: 12.h, - ), - child: AspectRatio( - aspectRatio: 1.5, - child: BarChart( - BarChartData( - alignment: BarChartAlignment.spaceAround, - barTouchData: BarTouchData(enabled: false), - titlesData: FlTitlesData( - show: true, - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - //getTitlesWidget: (value, meta) => newMethod(value), - ), - ), - ), - borderData: FlBorderData(show: false), - barGroups: [ - BarChartGroupData( - x: 0, - barRods: [ - BarChartRodData( - toY: consumedValues[0] / recommendedValues[0] * 100, - color: checkConsumedValues( - [recommendedValues[0]], [consumedValues[1]]) - ? Colors.red - : Colors.blue, - ), - ], - ), - BarChartGroupData( - x: 1, - barRods: [ - BarChartRodData( - toY: consumedValues[1] / recommendedValues[1] * 100, - color: checkConsumedValues( - [recommendedValues[1]], [consumedValues[1]]) - ? Colors.red - : Colors.blue, - ), - ], - ), - BarChartGroupData( - x: 2, - barRods: [ - BarChartRodData( - toY: consumedValues[2] / recommendedValues[2] * 100, - color: checkConsumedValues( - [recommendedValues[2]], [consumedValues[2]]) - ? Colors.red - : Colors.blue, - ), - ], - ), - BarChartGroupData( - x: 3, - barRods: [ - BarChartRodData( - toY: consumedValues[3] / recommendedValues[3] * 100, - color: checkConsumedValues( - [recommendedValues[3]], [consumedValues[3]]) - ? Colors.red - : Colors.blue, - ), - ], - ), - ], - ), - ), - ), - ), - ), - SizedBox(height: 8.v), - SizedBox(height: 2.v), - Padding( - padding: EdgeInsets.only( - left: 10.h, - right: 2.h, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Калорий", - style: theme.textTheme.bodySmall, - ), - Padding( - padding: EdgeInsets.only( - left: 25.h, - bottom: 11.v, - ), - child: Text( - "Белков", - style: theme.textTheme.bodySmall, - ), - ), - Padding( - padding: EdgeInsets.only( - left: 19.h, - bottom: 11.v, - ), - child: Text( - "Жиров", - style: theme.textTheme.bodySmall, - ), - ), - Padding( - padding: EdgeInsets.only( - left: 14.h, - bottom: 11.v, - ), - child: Text( - "Углеводов", - style: theme.textTheme.bodySmall, - ), - ), - ], - ), - ), - SizedBox(height: 2.v), - Padding( - padding: EdgeInsets.only( - left: 10.h, - right: 2.h, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "${consumedValues[0].toInt()} из ${recommendedValues[0].toInt()}", - style: theme.textTheme.bodySmall, - ), - Padding( - padding: EdgeInsets.only( - left: 25.h, - bottom: 11.v, - ), - child: Text( - "${consumedValues[1].toInt()} из ${recommendedValues[1].toInt()}", - style: theme.textTheme.bodySmall, - ), - ), - Padding( - padding: EdgeInsets.only( - left: 19.h, - bottom: 11.v, - ), - child: Text( - "${consumedValues[2].toInt()} из ${recommendedValues[2].toInt()}", - style: theme.textTheme.bodySmall, - ), - ), - Padding( - padding: EdgeInsets.only( - left: 14.h, - bottom: 11.v, - ), - child: Text( - "${consumedValues[3].toInt()} из ${recommendedValues[3].toInt()}", - style: theme.textTheme.bodySmall, - ), - ), - ], - ), - ), - SizedBox(height: 19.v), - if (checkConsumedValues(recommendedValues, consumedValues)) - Text( - "*Превышенная суточная норма", - style: theme.textTheme.labelLarge, - ), - ], - ), - ); - }*/ - - /// Section Widget _buildComment(BuildContext context, DiaryStateLoaded state) { return Container( margin: EdgeInsets.symmetric(horizontal: 16.h), @@ -1094,9 +859,7 @@ class DiaryScreen extends StatelessWidget { r"Подъем \ отход ко сну", style: CustomTextStyles.bodyMediumBlack900, ), - Icon(state.wakeupExpanded - ? Icons.arrow_drop_up - : Icons.arrow_drop_down), + Icon(state.wakeupExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down), ], ), ), @@ -1110,8 +873,7 @@ class DiaryScreen extends StatelessWidget { onTap: () => _selectWakeupTime(context, state), child: AbsorbPointer( child: CustomTextFormField( - hintText: - state.wakeupController?.format(context).toString(), + hintText: state.wakeupController.format(context).toString(), prefix: Icon(Icons.sunny), autofocus: false, ), @@ -1122,8 +884,7 @@ class DiaryScreen extends StatelessWidget { onTap: () => _selectRetireTime(context, state), child: AbsorbPointer( child: CustomTextFormField( - hintText: - state.retireController?.format(context).toString(), + hintText: state.retireController.format(context).toString(), prefix: Icon(Icons.bed), autofocus: false, ), @@ -1170,8 +931,7 @@ class DiaryScreen extends StatelessWidget { }; } - Function() sendFinishDayData( - BuildContext dialogContext, BuildContext context) { + Function() sendFinishDayData(BuildContext dialogContext, BuildContext context) { return () { closeDialog(dialogContext); context.read().add(FinishDay()); @@ -1214,9 +974,7 @@ class DiaryScreen extends StatelessWidget { "Ваше настроение после приема пищи", style: CustomTextStyles.bodyMediumBlack900, ), - Icon(state.moodExpanded - ? Icons.arrow_drop_up - : Icons.arrow_drop_down), + Icon(state.moodExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down), ], ), ), @@ -1276,30 +1034,27 @@ class DiaryScreen extends StatelessWidget { }; } - Future _selectWakeupTime( - BuildContext context, DiaryStateLoaded state) async { + Future _selectWakeupTime(BuildContext context, DiaryStateLoaded state) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, - initialTime: state.wakeupController ?? TimeOfDay.now(), + initialTime: state.wakeupController, ); if (pickedTime != null && pickedTime != state.wakeupController) { context.read().add(WakeupEvent(pickedTime)); } } - Future _selectRetireTime( - BuildContext context, DiaryStateLoaded state) async { + Future _selectRetireTime(BuildContext context, DiaryStateLoaded state) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, - initialTime: state.retireController ?? TimeOfDay.now(), + initialTime: state.retireController, ); if (pickedTime != null && pickedTime != state.retireController) { context.read().add(RetireEvent(pickedTime)); } } - Future _selectMealTime( - BuildContext context, DiaryStateLoaded state) async { + Future _selectMealTime(BuildContext context, DiaryStateLoaded state) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: state.mealTimeController ?? TimeOfDay.now(), @@ -1310,8 +1065,7 @@ class DiaryScreen extends StatelessWidget { } } -bool checkConsumedValues( - List recommendedValues, List consumedValues) { +bool checkConsumedValues(List recommendedValues, List consumedValues) { for (int i = 0; i < recommendedValues.length; i++) { if (consumedValues[i] > recommendedValues[i]) { // Если хотя бы одно потребленное значение превышает рекомендованное diff --git a/lib/features/diary/repositories/diary_repository.dart b/lib/features/diary/repositories/diary_repository.dart index 56c9fbd6..599c0810 100644 --- a/lib/features/diary/repositories/diary_repository.dart +++ b/lib/features/diary/repositories/diary_repository.dart @@ -189,22 +189,12 @@ class DiaryRepository { Future finishDay( int diaryID, - TimeOfDay? wakeup, - TimeOfDay? retire, - String? comment, ) async { try { - final formatter = DateFormat('HH:mm'); - final wakeupString = - formatter.format(DateTime(2022, 1, 1, wakeup!.hour, wakeup.minute)); - final retireString = - formatter.format(DateTime(2022, 1, 1, retire!.hour, retire.minute)); - await diaryService.sendFinishDay( - diaryID, - wakeupString, - retireString, - comment ?? " ", - ); + /*final formatter = DateFormat('HH:mm'); + final wakeupString = formatter.format(DateTime(2022, 1, 1, wakeup.hour, wakeup.minute)); + final retireString = formatter.format(DateTime(2022, 1, 1, retire.hour, retire.minute));*/ + await diaryService.sendFinishDay(diaryID); } catch (e) { rethrow; } diff --git a/lib/features/diary/services/diary_service.dart b/lib/features/diary/services/diary_service.dart index 125db491..bf9a8900 100644 --- a/lib/features/diary/services/diary_service.dart +++ b/lib/features/diary/services/diary_service.dart @@ -22,8 +22,7 @@ abstract class DiaryService { Future getChart(@Path() int id); @GET('/diary/product_nutritional_values/filter') - Future>> getInputProduct( - @Query('name') String name); + Future>> getInputProduct(@Query('name') String name); @POST('/diary/{diary_id}/meal/{meal_id}/satiety/fill') Future> sendSatietyData( @@ -79,9 +78,9 @@ abstract class DiaryService { @POST('/diary/{diary_id}/finishDay') Future sendFinishDay( @Path() int diary_id, - @Query('wakeUp') String wakeup, - @Query('retire') String retire, - @Query('comment') String comment, + //@Query('wakeUp') String wakeup, + //@Query('retire') String retire, + //@Query('comment') String comment, ); @DELETE('/diary/{diary_id}/meal/{meal_id}/portions/{portion_id}/delete') diff --git a/lib/features/diary/services/diary_service.g.dart b/lib/features/diary/services/diary_service.g.dart index 01a34881..91e048e5 100644 --- a/lib/features/diary/services/diary_service.g.dart +++ b/lib/features/diary/services/diary_service.g.dart @@ -365,18 +365,9 @@ class _DiaryService implements DiaryService { } @override - Future sendFinishDay( - int diary_id, - String wakeup, - String retire, - String comment, - ) async { + Future sendFinishDay(int diary_id) async { final _extra = {}; - final queryParameters = { - r'wakeUp': wakeup, - r'retire': retire, - r'comment': comment, - }; + final queryParameters = {}; final _headers = {}; const Map? _data = null; await _dio.fetch(_setStreamType(Options( From a2360a1c1926a5d34c917822f1b4f65c47c057ff Mon Sep 17 00:00:00 2001 From: maxxkim Date: Wed, 31 Jul 2024 12:21:17 +0300 Subject: [PATCH 4/5] feat(diary): Nutrition chart looks like half-donut --- .../presentation/pages/calendar_screen.dart | 41 +++-- .../diary/presentation/bloc/diary_bloc.dart | 54 ++++-- .../presentation/pages/diary_screen.dart | 161 +++++++++++++----- .../diary/repositories/diary_repository.dart | 2 - lib/main.dart | 3 +- 5 files changed, 181 insertions(+), 80 deletions(-) diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart index 9dab6be2..646a3bb1 100644 --- a/lib/features/calendar/presentation/pages/calendar_screen.dart +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -4,6 +4,7 @@ import 'package:eatvio_app/features/calendar/models/calendar_model.dart'; import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:go_router/go_router.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; @@ -101,26 +102,34 @@ class CalendarScreen extends StatelessWidget { ], ), child: TableCalendar( + locale: 'ru_RU', firstDay: DateTime.utc(2010, 10, 16), lastDay: DateTime.utc(2030, 3, 14), focusedDay: DateTime.now(), startingDayOfWeek: StartingDayOfWeek.monday, calendarBuilders: CalendarBuilders( - selectedBuilder: (context, day, focusedDay) => _buildCellDate(day, focusedDay: focusedDay, state), - defaultBuilder: (context, day, focusedDay) => _buildCellDate(day, state), - todayBuilder: (context, day, focusedDay) => _buildCellDate(day, state), + selectedBuilder: (context, day, focusedDay) => + _buildCellDate(context, day, focusedDay: focusedDay, state), + defaultBuilder: (context, day, focusedDay) => + _buildCellDate(context, day, state), + todayBuilder: (context, day, focusedDay) => + _buildCellDate(context, day, state), ), ), ); } } -Widget _buildCellDate(DateTime day, CalendarStateLoaded state, {DateTime? focusedDay}) { +Widget _buildCellDate( + BuildContext context, DateTime day, CalendarStateLoaded state, + {DateTime? focusedDay}) { final String dayString = day.toIso8601String().split('T').first; final List calendarModels = state.calendarList; // Находим первую модель, соответствующую дате - final CalendarModel model = calendarModels.firstWhere((model) => model.date == dayString, orElse: () => CalendarModel(date: dayString, diary: {})); + final CalendarModel model = calendarModels.firstWhere( + (model) => model.date == dayString, + orElse: () => CalendarModel(date: dayString, diary: {})); Color? bgclr; // Объявляем переменную bgclr здесь @@ -138,14 +147,16 @@ Widget _buildCellDate(DateTime day, CalendarStateLoaded state, {DateTime? focuse bgclr = Colors.white; // Значение по умолчанию, если diary не является Map } - return Container( - margin: const EdgeInsets.all(5), - alignment: Alignment.center, - decoration: BoxDecoration( - shape: (day == focusedDay) ? BoxShape.circle : BoxShape.rectangle, - color: bgclr, - borderRadius: (day == focusedDay) ? null : BorderRadius.circular(4), - ), - child: Text(day.day.toString(), style: TextStyle(color: Colors.black)), - ); + return GestureDetector( + onTap: () => GoRouter.of(context).replace('/diary-screen'), + child: Container( + margin: const EdgeInsets.all(5), + alignment: Alignment.center, + decoration: BoxDecoration( + shape: (day == focusedDay) ? BoxShape.circle : BoxShape.rectangle, + color: bgclr, + borderRadius: (day == focusedDay) ? null : BorderRadius.circular(4), + ), + child: Text(day.day.toString(), style: TextStyle(color: Colors.black)), + )); } diff --git a/lib/features/diary/presentation/bloc/diary_bloc.dart b/lib/features/diary/presentation/bloc/diary_bloc.dart index 8ac0e8a2..e1b952b8 100644 --- a/lib/features/diary/presentation/bloc/diary_bloc.dart +++ b/lib/features/diary/presentation/bloc/diary_bloc.dart @@ -16,7 +16,8 @@ part 'diary_event.dart'; class DiaryBloc extends Bloc { final DiaryRepository diaryRepository; - DiaryBloc({required this.diaryRepository}) : super(const DiaryState.loading()) { + DiaryBloc({required this.diaryRepository}) + : super(const DiaryState.loading()) { on(loadDiary); on(_changeSatiety); // пользователь нажимает на шкалу сытости on(_changeMood); // пользователь нажимает на шкалу настроения @@ -53,15 +54,29 @@ class DiaryBloc extends Bloc { final DiaryModel diary = await diaryRepository.getDiary(diaryID ?? 45); final Meal currentMeal = diary.meals[0]; - List portionList = [SelectionPopupModel(title: "gr"), SelectionPopupModel(title: "pcs")]; + List portionList = [ + SelectionPopupModel(title: "gr"), + SelectionPopupModel(title: "pcs") + ]; - final Map chartData = await diaryRepository.getChartData(diaryID ?? 45); - final Map dailyNutritionIntake = chartData['dailyNutritionIntake']!; - final Map dailyNutritionRecommendations = chartData['dailyNutritionRecommendation']!; - final double ccal = dailyNutritionIntake['energy']! / dailyNutritionRecommendations['energy']! * 100; - final double proteins = dailyNutritionIntake['proteins']! / dailyNutritionRecommendations['proteins']! * 100; - final double fats = dailyNutritionIntake['fats']! / dailyNutritionRecommendations['fats']! * 100; - final double carbs = dailyNutritionIntake['carbohydrates']! / dailyNutritionRecommendations['carbohydrates']! * 100; + final Map chartData = + await diaryRepository.getChartData(diaryID ?? 45); + final Map dailyNutritionIntake = + chartData['dailyNutritionIntake']!; + final Map dailyNutritionRecommendations = + chartData['dailyNutritionRecommendation']!; + final double ccal = dailyNutritionIntake['energy']! / + dailyNutritionRecommendations['energy']! * + 50; + final double proteins = dailyNutritionIntake['proteins']! / + dailyNutritionRecommendations['proteins']! * + 50; + final double fats = dailyNutritionIntake['fats']! / + dailyNutritionRecommendations['fats']! * + 50; + final double carbs = dailyNutritionIntake['carbohydrates']! / + dailyNutritionRecommendations['carbohydrates']! * + 50; Color getColor(double value) { if (value >= 99.1) { @@ -163,9 +178,11 @@ class DiaryBloc extends Bloc { ) async { if (state is DiaryStateLoaded) { var currentState = state as DiaryStateLoaded; - var updatedState = currentState.copyWith(wakeupController: event.selectedTime); + var updatedState = + currentState.copyWith(wakeupController: event.selectedTime); final DateFormat formatter = DateFormat('HH:mm'); - final String wakeupString = formatter.format(DateTime(2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); + final String wakeupString = formatter.format(DateTime( + 2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); await diaryRepository.changeWakeup( currentState.diary.id, wakeupString, @@ -180,9 +197,11 @@ class DiaryBloc extends Bloc { ) async { if (state is DiaryStateLoaded) { var currentState = state as DiaryStateLoaded; - var updatedState = currentState.copyWith(retireController: event.selectedTime); + var updatedState = + currentState.copyWith(retireController: event.selectedTime); final DateFormat formatter = DateFormat('HH:mm'); - final String retireString = formatter.format(DateTime(2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); + final String retireString = formatter.format(DateTime( + 2022, 1, 1, event.selectedTime.hour, event.selectedTime.minute)); await diaryRepository.changeRetire( currentState.diary.id, retireString, @@ -208,7 +227,8 @@ class DiaryBloc extends Bloc { ) async { if (state is DiaryStateLoaded) { final currentState = state as DiaryStateLoaded; - final Meal meal = currentState.diary.meals.firstWhere((meal) => meal.type == event.value.id); + final Meal meal = currentState.diary.meals + .firstWhere((meal) => meal.type == event.value.id); DiaryStateLoaded updatedState = currentState.copyWith( currentMeal: meal, portions: meal.portions, @@ -227,10 +247,12 @@ class DiaryBloc extends Bloc { if (state is DiaryStateLoaded) { var currentState = state as DiaryStateLoaded; - final Map> productNutritionalValues = await diaryRepository.inputProduct(event.input); + final Map> productNutritionalValues = + await diaryRepository.inputProduct(event.input); var updatedState = currentState.copyWith( product_nameController: TextEditingController(text: event.input), - autocompleteList: productNutritionalValues['product_nutritional_value'] ?? [], + autocompleteList: + productNutritionalValues['product_nutritional_value'] ?? [], ); if (event.input.length > 3) { updatedState = updatedState.copyWith(moderationExpanded: true); diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index 8be9be46..e360f35b 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -111,35 +111,80 @@ class DiaryScreen extends StatelessWidget { _buildNutritionChart(BuildContext context, DiaryStateLoaded state) { return Container( - margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), - padding: EdgeInsets.symmetric( - horizontal: 24.h, - vertical: 12.v, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: SfCircularChart( - title: ChartTitle(text: 'График КБЖУ'), - legend: Legend(isVisible: true), - series: [ - RadialBarSeries( - dataSource: state.chartData, - xValueMapper: (NutritionData data, _) => data.category, - yValueMapper: (NutritionData data, _) => data.nutrition, - pointColorMapper: (NutritionData data, _) => data.color, - ) - ], - )); + margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: Column( + children: [ + Text( + "График КБЖУ", + style: theme.textTheme.titleMedium, + textAlign: TextAlign.center, + ), + Transform.rotate( + angle: -1.5708, + child: ClipRect( + child: Align( + alignment: Alignment.centerRight, + widthFactor: 0.5, + child: SfCircularChart( + legend: Legend(isVisible: false), + series: [ + RadialBarSeries( + dataSource: state.chartData, + xValueMapper: (NutritionData data, _) => data.category, + yValueMapper: (NutritionData data, _) => data.nutrition, + pointColorMapper: (NutritionData data, _) => data.color, + ) + ], + ), + ), + )), + SizedBox(height: 16.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Калории'), + Text('Белки'), + Text('Жиры'), + Text('Углеводы'), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '${state.chartData![0].nutrition.toStringAsFixed(1)}'), // Калории + Text( + '${state.chartData![1].nutrition.toStringAsFixed(1)}'), // Белки + Text( + '${state.chartData![2].nutrition.toStringAsFixed(1)}'), // Жиры + Text( + '${state.chartData![3].nutrition.toStringAsFixed(1)}'), // Углеводы + ], + ), + ], + ), + ], + ), + ); } _buildEndDay(BuildContext context) { @@ -278,7 +323,9 @@ class DiaryScreen extends StatelessWidget { borderRadius: BorderRadiusStyle.roundedBorder5, ), child: Center( - child: CircularProgressIndicator(color: appTheme.blueGray300), // Замените на свой прелоадер при необходимости + child: CircularProgressIndicator( + color: appTheme + .blueGray300), // Замените на свой прелоадер при необходимости ), ), ], @@ -302,7 +349,8 @@ class DiaryScreen extends StatelessWidget { _buildMeal(BuildContext context, DiaryStateLoaded state) { final digitsOnly = FilteringTextInputFormatter.digitsOnly; - List _options = state.autocompleteList.map((Product item) => item.name).toList(); + List _options = + state.autocompleteList.map((Product item) => item.name).toList(); FocusNode focusNodeName = FocusNode(); return Container( margin: EdgeInsets.symmetric(horizontal: 16.h), @@ -346,7 +394,9 @@ class DiaryScreen extends StatelessWidget { onTap: () => _selectMealTime(context, state), child: AbsorbPointer( child: CustomTextFormField( - hintText: state.mealTimeController?.format(context).toString(), + hintText: state.mealTimeController + ?.format(context) + .toString(), autofocus: false, ), ), @@ -482,7 +532,9 @@ class DiaryScreen extends StatelessWidget { SizedBox(height: 30.v), _buildAddProduct(context, state), SizedBox(height: 30.v), - ...state.portions.map((portion) => _buildProduct(context, portion)).toList(), + ...state.portions + .map((portion) => _buildProduct(context, portion)) + .toList(), SizedBox(height: 30.v), _buildCarousel(context, state), SizedBox(height: 20.v), @@ -631,7 +683,8 @@ class DiaryScreen extends StatelessWidget { popDialog(BuildContext dialogContext) { return () { - Navigator.of(dialogContext).pop(); // Dismiss the dialog on Cancel button press + Navigator.of(dialogContext) + .pop(); // Dismiss the dialog on Cancel button press }; } @@ -641,7 +694,8 @@ class DiaryScreen extends StatelessWidget { }; } - selectProduct(AutocompleteOnSelected onSelected, String option, DiaryStateLoaded state) { + selectProduct(AutocompleteOnSelected onSelected, String option, + DiaryStateLoaded state) { state.product_nameController.text = option; return () { onSelected(option); @@ -709,7 +763,9 @@ class DiaryScreen extends StatelessWidget { top: 5.v, ), child: Text( - portion.product_name.length > 8 ? portion.product_name.substring(0, 8) : portion.product_name, + portion.product_name.length > 8 + ? portion.product_name.substring(0, 8) + : portion.product_name, style: CustomTextStyles.titleMedium16, ), ), @@ -781,7 +837,9 @@ class DiaryScreen extends StatelessWidget { removePhoto(BuildContext context, Photo photo) { return () { - context.read().add(RemoveImageEvent(photo.id.toString(), photo.path)); + context + .read() + .add(RemoveImageEvent(photo.id.toString(), photo.path)); }; } @@ -859,7 +917,9 @@ class DiaryScreen extends StatelessWidget { r"Подъем \ отход ко сну", style: CustomTextStyles.bodyMediumBlack900, ), - Icon(state.wakeupExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down), + Icon(state.wakeupExpanded + ? Icons.arrow_drop_up + : Icons.arrow_drop_down), ], ), ), @@ -873,7 +933,8 @@ class DiaryScreen extends StatelessWidget { onTap: () => _selectWakeupTime(context, state), child: AbsorbPointer( child: CustomTextFormField( - hintText: state.wakeupController.format(context).toString(), + hintText: + state.wakeupController.format(context).toString(), prefix: Icon(Icons.sunny), autofocus: false, ), @@ -884,7 +945,8 @@ class DiaryScreen extends StatelessWidget { onTap: () => _selectRetireTime(context, state), child: AbsorbPointer( child: CustomTextFormField( - hintText: state.retireController.format(context).toString(), + hintText: + state.retireController.format(context).toString(), prefix: Icon(Icons.bed), autofocus: false, ), @@ -931,7 +993,8 @@ class DiaryScreen extends StatelessWidget { }; } - Function() sendFinishDayData(BuildContext dialogContext, BuildContext context) { + Function() sendFinishDayData( + BuildContext dialogContext, BuildContext context) { return () { closeDialog(dialogContext); context.read().add(FinishDay()); @@ -974,7 +1037,9 @@ class DiaryScreen extends StatelessWidget { "Ваше настроение после приема пищи", style: CustomTextStyles.bodyMediumBlack900, ), - Icon(state.moodExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down), + Icon(state.moodExpanded + ? Icons.arrow_drop_up + : Icons.arrow_drop_down), ], ), ), @@ -1034,7 +1099,8 @@ class DiaryScreen extends StatelessWidget { }; } - Future _selectWakeupTime(BuildContext context, DiaryStateLoaded state) async { + Future _selectWakeupTime( + BuildContext context, DiaryStateLoaded state) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: state.wakeupController, @@ -1044,7 +1110,8 @@ class DiaryScreen extends StatelessWidget { } } - Future _selectRetireTime(BuildContext context, DiaryStateLoaded state) async { + Future _selectRetireTime( + BuildContext context, DiaryStateLoaded state) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: state.retireController, @@ -1054,7 +1121,8 @@ class DiaryScreen extends StatelessWidget { } } - Future _selectMealTime(BuildContext context, DiaryStateLoaded state) async { + Future _selectMealTime( + BuildContext context, DiaryStateLoaded state) async { final TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: state.mealTimeController ?? TimeOfDay.now(), @@ -1065,7 +1133,8 @@ class DiaryScreen extends StatelessWidget { } } -bool checkConsumedValues(List recommendedValues, List consumedValues) { +bool checkConsumedValues( + List recommendedValues, List consumedValues) { for (int i = 0; i < recommendedValues.length; i++) { if (consumedValues[i] > recommendedValues[i]) { // Если хотя бы одно потребленное значение превышает рекомендованное diff --git a/lib/features/diary/repositories/diary_repository.dart b/lib/features/diary/repositories/diary_repository.dart index 599c0810..04a8cad0 100644 --- a/lib/features/diary/repositories/diary_repository.dart +++ b/lib/features/diary/repositories/diary_repository.dart @@ -1,6 +1,4 @@ import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:eatvio_app/features/diary/models/diary_model.dart'; import 'package:eatvio_app/features/diary/models/portion.dart'; diff --git a/lib/main.dart b/lib/main.dart index 9ce1b92e..d628b940 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,6 +18,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; import 'package:eatvio_app/locator_service.dart' as di; +import 'package:intl/date_symbol_data_local.dart'; var globalMessengerKey = GlobalKey(); @@ -34,7 +35,7 @@ void main() async { DeviceOrientation.portraitUp, ]); await PrefUtils().init(); - runApp(MyApp()); + initializeDateFormatting().then((_) => runApp(MyApp())); } class MyApp extends StatelessWidget { From 403e49d65799f23d7996566292e1814c55346fbf Mon Sep 17 00:00:00 2001 From: maxxkim Date: Wed, 31 Jul 2024 13:09:28 +0300 Subject: [PATCH 5/5] feat(calendar): Routes to diary --- .../calendar/presentation/pages/calendar_screen.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart index 646a3bb1..ab90403e 100644 --- a/lib/features/calendar/presentation/pages/calendar_screen.dart +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -133,9 +133,8 @@ Widget _buildCellDate( Color? bgclr; // Объявляем переменную bgclr здесь + final Map diary = model.diary as Map; if (model.diary is Map) { - final Map diary = model.diary as Map; - if (diary['state'] == "started") { bgclr = Colors.grey; } else if (diary['state'] == "finished") { @@ -148,7 +147,10 @@ Widget _buildCellDate( } return GestureDetector( - onTap: () => GoRouter.of(context).replace('/diary-screen'), + onTap: () => GoRouter.of(context).pushNamed( + 'diaryScreen', + extra: diary['id'], + ), child: Container( margin: const EdgeInsets.all(5), alignment: Alignment.center,