From f994589baa0f3e984a84510ce2a97559e107790b Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Wed, 28 Aug 2024 15:55:08 +0300 Subject: [PATCH] feat(profile): add weight and imt charts, menu add dividers --- .../initialization_cubit.dart | 2 +- .../notifications_cubit.dart | 11 ++- .../notifications_state.dart | 1 + .../notifications_state.freezed.dart | 87 ++++++++++++++----- .../menu/presentation/pages/menu_screen.dart | 23 +++++ .../pages/notifications_screen.dart | 21 ++++- .../profile/models/profile_model.dart | 1 + .../profile/models/profile_model.freezed.dart | 27 +++++- .../profile/models/profile_model.g.dart | 2 + .../presentation/pages/profile_screen.dart | 6 ++ .../widgets/imt_chart_widget.dart | 69 +++++++++++++++ .../widgets/weight_chart_widget.dart | 69 +++++++++++++++ 12 files changed, 287 insertions(+), 32 deletions(-) create mode 100644 lib/features/profile/presentation/widgets/imt_chart_widget.dart create mode 100644 lib/features/profile/presentation/widgets/weight_chart_widget.dart diff --git a/lib/core/initialization_cubit/initialization_cubit.dart b/lib/core/initialization_cubit/initialization_cubit.dart index 29a42f69..518abeba 100644 --- a/lib/core/initialization_cubit/initialization_cubit.dart +++ b/lib/core/initialization_cubit/initialization_cubit.dart @@ -27,7 +27,7 @@ class InitializationCubit extends Cubit { privateNotificationChannel.subscribe(); privateNotificationChannel.bindToAll().listen((event) { - sl().incrementCounter(); + sl().incrementCounter(event.name); }); } diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart index ba5634cc..8a22b6d5 100644 --- a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart @@ -3,11 +3,18 @@ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/noti class NotificationsCubit extends Cubit { int _notificationsCount = 0; + List notifications = []; NotificationsCubit() : super(const NotificationsState.empty()); - incrementCounter() { + incrementCounter(String data) { _notificationsCount++; - emit(NotificationsState.loaded(notificationsCount: _notificationsCount)); + notifications.add(data); + emit( + NotificationsState.loaded( + notifications: notifications, + notificationsCount: _notificationsCount, + ), + ); } } diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart index 0f20a051..d44c7b2b 100644 --- a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart @@ -9,6 +9,7 @@ abstract class NotificationsState with _$NotificationsState { const factory NotificationsState.empty() = NotificationsStateEmpty; const factory NotificationsState.loaded({ + required List notifications, required int notificationsCount, }) = NotificationsStateLoaded; diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart index 0deeebbd..4ba18f06 100644 --- a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.freezed.dart @@ -20,7 +20,9 @@ mixin _$NotificationsState { TResult when( TResult Function() $default, { required TResult Function() empty, - required TResult Function(int notificationsCount) loaded, + required TResult Function( + List notifications, int notificationsCount) + loaded, required TResult Function(String errorMessage) error, }) => throw _privateConstructorUsedError; @@ -28,7 +30,8 @@ mixin _$NotificationsState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? empty, - TResult? Function(int notificationsCount)? loaded, + TResult? Function(List notifications, int notificationsCount)? + loaded, TResult? Function(String errorMessage)? error, }) => throw _privateConstructorUsedError; @@ -36,7 +39,8 @@ mixin _$NotificationsState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? empty, - TResult Function(int notificationsCount)? loaded, + TResult Function(List notifications, int notificationsCount)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) => @@ -126,7 +130,9 @@ class _$NotificationsStateImpl implements _NotificationsState { TResult when( TResult Function() $default, { required TResult Function() empty, - required TResult Function(int notificationsCount) loaded, + required TResult Function( + List notifications, int notificationsCount) + loaded, required TResult Function(String errorMessage) error, }) { return $default(); @@ -137,7 +143,8 @@ class _$NotificationsStateImpl implements _NotificationsState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? empty, - TResult? Function(int notificationsCount)? loaded, + TResult? Function(List notifications, int notificationsCount)? + loaded, TResult? Function(String errorMessage)? error, }) { return $default?.call(); @@ -148,7 +155,8 @@ class _$NotificationsStateImpl implements _NotificationsState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? empty, - TResult Function(int notificationsCount)? loaded, + TResult Function(List notifications, int notificationsCount)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -244,7 +252,9 @@ class _$NotificationsStateEmptyImpl implements NotificationsStateEmpty { TResult when( TResult Function() $default, { required TResult Function() empty, - required TResult Function(int notificationsCount) loaded, + required TResult Function( + List notifications, int notificationsCount) + loaded, required TResult Function(String errorMessage) error, }) { return empty(); @@ -255,7 +265,8 @@ class _$NotificationsStateEmptyImpl implements NotificationsStateEmpty { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? empty, - TResult? Function(int notificationsCount)? loaded, + TResult? Function(List notifications, int notificationsCount)? + loaded, TResult? Function(String errorMessage)? error, }) { return empty?.call(); @@ -266,7 +277,8 @@ class _$NotificationsStateEmptyImpl implements NotificationsStateEmpty { TResult maybeWhen( TResult Function()? $default, { TResult Function()? empty, - TResult Function(int notificationsCount)? loaded, + TResult Function(List notifications, int notificationsCount)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -325,7 +337,7 @@ abstract class _$$NotificationsStateLoadedImplCopyWith<$Res> { $Res Function(_$NotificationsStateLoadedImpl) then) = __$$NotificationsStateLoadedImplCopyWithImpl<$Res>; @useResult - $Res call({int notificationsCount}); + $Res call({List notifications, int notificationsCount}); } /// @nodoc @@ -341,9 +353,14 @@ class __$$NotificationsStateLoadedImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ + Object? notifications = null, Object? notificationsCount = null, }) { return _then(_$NotificationsStateLoadedImpl( + notifications: null == notifications + ? _value._notifications + : notifications // ignore: cast_nullable_to_non_nullable + as List, notificationsCount: null == notificationsCount ? _value.notificationsCount : notificationsCount // ignore: cast_nullable_to_non_nullable @@ -355,14 +372,25 @@ class __$$NotificationsStateLoadedImplCopyWithImpl<$Res> /// @nodoc class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { - const _$NotificationsStateLoadedImpl({required this.notificationsCount}); + const _$NotificationsStateLoadedImpl( + {required final List notifications, + required this.notificationsCount}) + : _notifications = notifications; + + final List _notifications; + @override + List get notifications { + if (_notifications is EqualUnmodifiableListView) return _notifications; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_notifications); + } @override final int notificationsCount; @override String toString() { - return 'NotificationsState.loaded(notificationsCount: $notificationsCount)'; + return 'NotificationsState.loaded(notifications: $notifications, notificationsCount: $notificationsCount)'; } @override @@ -370,12 +398,15 @@ class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$NotificationsStateLoadedImpl && + const DeepCollectionEquality() + .equals(other._notifications, _notifications) && (identical(other.notificationsCount, notificationsCount) || other.notificationsCount == notificationsCount)); } @override - int get hashCode => Object.hash(runtimeType, notificationsCount); + int get hashCode => Object.hash(runtimeType, + const DeepCollectionEquality().hash(_notifications), notificationsCount); @JsonKey(ignore: true) @override @@ -389,10 +420,12 @@ class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { TResult when( TResult Function() $default, { required TResult Function() empty, - required TResult Function(int notificationsCount) loaded, + required TResult Function( + List notifications, int notificationsCount) + loaded, required TResult Function(String errorMessage) error, }) { - return loaded(notificationsCount); + return loaded(notifications, notificationsCount); } @override @@ -400,10 +433,11 @@ class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? empty, - TResult? Function(int notificationsCount)? loaded, + TResult? Function(List notifications, int notificationsCount)? + loaded, TResult? Function(String errorMessage)? error, }) { - return loaded?.call(notificationsCount); + return loaded?.call(notifications, notificationsCount); } @override @@ -411,12 +445,13 @@ class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { TResult maybeWhen( TResult Function()? $default, { TResult Function()? empty, - TResult Function(int notificationsCount)? loaded, + TResult Function(List notifications, int notificationsCount)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { if (loaded != null) { - return loaded(notificationsCount); + return loaded(notifications, notificationsCount); } return orElse(); } @@ -461,8 +496,10 @@ class _$NotificationsStateLoadedImpl implements NotificationsStateLoaded { abstract class NotificationsStateLoaded implements NotificationsState { const factory NotificationsStateLoaded( - {required final int notificationsCount}) = _$NotificationsStateLoadedImpl; + {required final List notifications, + required final int notificationsCount}) = _$NotificationsStateLoadedImpl; + List get notifications; int get notificationsCount; @JsonKey(ignore: true) _$$NotificationsStateLoadedImplCopyWith<_$NotificationsStateLoadedImpl> @@ -540,7 +577,9 @@ class _$NotificationsStateErrorImpl implements NotificationsStateError { TResult when( TResult Function() $default, { required TResult Function() empty, - required TResult Function(int notificationsCount) loaded, + required TResult Function( + List notifications, int notificationsCount) + loaded, required TResult Function(String errorMessage) error, }) { return error(errorMessage); @@ -551,7 +590,8 @@ class _$NotificationsStateErrorImpl implements NotificationsStateError { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? empty, - TResult? Function(int notificationsCount)? loaded, + TResult? Function(List notifications, int notificationsCount)? + loaded, TResult? Function(String errorMessage)? error, }) { return error?.call(errorMessage); @@ -562,7 +602,8 @@ class _$NotificationsStateErrorImpl implements NotificationsStateError { TResult maybeWhen( TResult Function()? $default, { TResult Function()? empty, - TResult Function(int notificationsCount)? loaded, + TResult Function(List notifications, int notificationsCount)? + loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { diff --git a/lib/features/menu/presentation/pages/menu_screen.dart b/lib/features/menu/presentation/pages/menu_screen.dart index d7074834..010bf6d3 100644 --- a/lib/features/menu/presentation/pages/menu_screen.dart +++ b/lib/features/menu/presentation/pages/menu_screen.dart @@ -24,36 +24,43 @@ class MenuScreen extends StatelessWidget { leading: ImageConstant.icnProfileSettings, onTap: () => GoRouter.of(context).push('/my-settings-screen'), ), + _divider(context), _tile( leading: ImageConstant.icnRecipes, title: 'Мои рецепты', onTap: () => GoRouter.of(context).push('/recipe-select-screen'), ), + _divider(context), _tile( leading: 'assets/icons/diets.svg', title: 'Мои диеты', onTap: () => GoRouter.of(context).push('/diet-select-screen'), ), + _divider(context), _tile( leading: ImageConstant.icnPlans, title: 'Мои планы', onTap: () => GoRouter.of(context).push('/plan-select-screen'), ), + _divider(context), _tile( leading: 'assets/icons/calendar.svg', title: 'Календарь', onTap: () => GoRouter.of(context).push('/calendar-screen'), ), + _divider(context), _tile( leading: ImageConstant.icnGlossary, title: 'Глоссарий', onTap: () => GoRouter.of(context).push('/glossary-screen'), ), + _divider(context), _tile( leading: ImageConstant.icnSupport, title: 'Поддержка', onTap: () {}, ), + _divider(context), _tile( leading: ImageConstant.icnExit, title: 'Выход', @@ -78,6 +85,22 @@ class MenuScreen extends StatelessWidget { width: 24, ), title: Text(title), + trailing: Icon( + Icons.arrow_forward_ios_rounded, + size: 12, + color: Colors.black38, + ), + ); + } + + _divider(BuildContext context) { + return Container( + height: 0.4, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + color: Colors.black26, + borderRadius: BorderRadius.circular(16), + ), ); } diff --git a/lib/features/notifications/presentation/pages/notifications_screen.dart b/lib/features/notifications/presentation/pages/notifications_screen.dart index 6d979118..10947cbf 100644 --- a/lib/features/notifications/presentation/pages/notifications_screen.dart +++ b/lib/features/notifications/presentation/pages/notifications_screen.dart @@ -1,3 +1,6 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart'; import 'package:flutter/material.dart'; class NotificationsScreen extends StatelessWidget { @@ -5,10 +8,20 @@ class NotificationsScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Уведомления'), - ), + return BlocBuilder( + builder: (BuildContext context, NotificationsState state) { + return Scaffold( + appBar: AppBar( + title: Text('Уведомления'), + ), + body: SingleChildScrollView( + padding: EdgeInsets.all(16), + child: Text( + state is NotificationsStateLoaded ? state.notifications.toString() : 'Уведомлений нет', + ), + ), + ); + }, ); } } diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart index 742c9c90..6c72a1fa 100644 --- a/lib/features/profile/models/profile_model.dart +++ b/lib/features/profile/models/profile_model.dart @@ -101,6 +101,7 @@ class ChartPoint with _$ChartPoint { @JsonKey(name: "id") required int id, @JsonKey(name: "user_id") required int userId, @JsonKey(name: "weight") required int weight, + @JsonKey(name: "bmi") required String bmi, @JsonKey(name: "created_at") required DateTime createdAt, @JsonKey(name: "updated_at") required DateTime updatedAt, }) = _ChartPoint; diff --git a/lib/features/profile/models/profile_model.freezed.dart b/lib/features/profile/models/profile_model.freezed.dart index 4fe3b775..0e5607b4 100644 --- a/lib/features/profile/models/profile_model.freezed.dart +++ b/lib/features/profile/models/profile_model.freezed.dart @@ -2122,6 +2122,8 @@ mixin _$ChartPoint { int get userId => throw _privateConstructorUsedError; @JsonKey(name: "weight") int get weight => throw _privateConstructorUsedError; + @JsonKey(name: "bmi") + String get bmi => throw _privateConstructorUsedError; @JsonKey(name: "created_at") DateTime get createdAt => throw _privateConstructorUsedError; @JsonKey(name: "updated_at") @@ -2143,6 +2145,7 @@ abstract class $ChartPointCopyWith<$Res> { {@JsonKey(name: "id") int id, @JsonKey(name: "user_id") int userId, @JsonKey(name: "weight") int weight, + @JsonKey(name: "bmi") String bmi, @JsonKey(name: "created_at") DateTime createdAt, @JsonKey(name: "updated_at") DateTime updatedAt}); } @@ -2163,6 +2166,7 @@ class _$ChartPointCopyWithImpl<$Res, $Val extends ChartPoint> Object? id = null, Object? userId = null, Object? weight = null, + Object? bmi = null, Object? createdAt = null, Object? updatedAt = null, }) { @@ -2179,6 +2183,10 @@ class _$ChartPointCopyWithImpl<$Res, $Val extends ChartPoint> ? _value.weight : weight // ignore: cast_nullable_to_non_nullable as int, + bmi: null == bmi + ? _value.bmi + : bmi // ignore: cast_nullable_to_non_nullable + as String, createdAt: null == createdAt ? _value.createdAt : createdAt // ignore: cast_nullable_to_non_nullable @@ -2203,6 +2211,7 @@ abstract class _$$ChartPointImplCopyWith<$Res> {@JsonKey(name: "id") int id, @JsonKey(name: "user_id") int userId, @JsonKey(name: "weight") int weight, + @JsonKey(name: "bmi") String bmi, @JsonKey(name: "created_at") DateTime createdAt, @JsonKey(name: "updated_at") DateTime updatedAt}); } @@ -2221,6 +2230,7 @@ class __$$ChartPointImplCopyWithImpl<$Res> Object? id = null, Object? userId = null, Object? weight = null, + Object? bmi = null, Object? createdAt = null, Object? updatedAt = null, }) { @@ -2237,6 +2247,10 @@ class __$$ChartPointImplCopyWithImpl<$Res> ? _value.weight : weight // ignore: cast_nullable_to_non_nullable as int, + bmi: null == bmi + ? _value.bmi + : bmi // ignore: cast_nullable_to_non_nullable + as String, createdAt: null == createdAt ? _value.createdAt : createdAt // ignore: cast_nullable_to_non_nullable @@ -2256,6 +2270,7 @@ class _$ChartPointImpl implements _ChartPoint { {@JsonKey(name: "id") required this.id, @JsonKey(name: "user_id") required this.userId, @JsonKey(name: "weight") required this.weight, + @JsonKey(name: "bmi") required this.bmi, @JsonKey(name: "created_at") required this.createdAt, @JsonKey(name: "updated_at") required this.updatedAt}); @@ -2272,6 +2287,9 @@ class _$ChartPointImpl implements _ChartPoint { @JsonKey(name: "weight") final int weight; @override + @JsonKey(name: "bmi") + final String bmi; + @override @JsonKey(name: "created_at") final DateTime createdAt; @override @@ -2280,7 +2298,7 @@ class _$ChartPointImpl implements _ChartPoint { @override String toString() { - return 'ChartPoint(id: $id, userId: $userId, weight: $weight, createdAt: $createdAt, updatedAt: $updatedAt)'; + return 'ChartPoint(id: $id, userId: $userId, weight: $weight, bmi: $bmi, createdAt: $createdAt, updatedAt: $updatedAt)'; } @override @@ -2291,6 +2309,7 @@ class _$ChartPointImpl implements _ChartPoint { (identical(other.id, id) || other.id == id) && (identical(other.userId, userId) || other.userId == userId) && (identical(other.weight, weight) || other.weight == weight) && + (identical(other.bmi, bmi) || other.bmi == bmi) && (identical(other.createdAt, createdAt) || other.createdAt == createdAt) && (identical(other.updatedAt, updatedAt) || @@ -2300,7 +2319,7 @@ class _$ChartPointImpl implements _ChartPoint { @JsonKey(ignore: true) @override int get hashCode => - Object.hash(runtimeType, id, userId, weight, createdAt, updatedAt); + Object.hash(runtimeType, id, userId, weight, bmi, createdAt, updatedAt); @JsonKey(ignore: true) @override @@ -2321,6 +2340,7 @@ abstract class _ChartPoint implements ChartPoint { {@JsonKey(name: "id") required final int id, @JsonKey(name: "user_id") required final int userId, @JsonKey(name: "weight") required final int weight, + @JsonKey(name: "bmi") required final String bmi, @JsonKey(name: "created_at") required final DateTime createdAt, @JsonKey(name: "updated_at") required final DateTime updatedAt}) = _$ChartPointImpl; @@ -2338,6 +2358,9 @@ abstract class _ChartPoint implements ChartPoint { @JsonKey(name: "weight") int get weight; @override + @JsonKey(name: "bmi") + String get bmi; + @override @JsonKey(name: "created_at") DateTime get createdAt; @override diff --git a/lib/features/profile/models/profile_model.g.dart b/lib/features/profile/models/profile_model.g.dart index 5f3293aa..af1c1c4d 100644 --- a/lib/features/profile/models/profile_model.g.dart +++ b/lib/features/profile/models/profile_model.g.dart @@ -169,6 +169,7 @@ _$ChartPointImpl _$$ChartPointImplFromJson(Map json) => id: (json['id'] as num).toInt(), userId: (json['user_id'] as num).toInt(), weight: (json['weight'] as num).toInt(), + bmi: json['bmi'] as String, createdAt: DateTime.parse(json['created_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String), ); @@ -178,6 +179,7 @@ Map _$$ChartPointImplToJson(_$ChartPointImpl instance) => 'id': instance.id, 'user_id': instance.userId, 'weight': instance.weight, + 'bmi': instance.bmi, 'created_at': instance.createdAt.toIso8601String(), 'updated_at': instance.updatedAt.toIso8601String(), }; diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index a6a78342..e9e37c56 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -4,6 +4,8 @@ import 'package:eatvio_app/features/profile/models/profile_model.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_state.dart'; import 'package:eatvio_app/features/profile/presentation/widgets/circumference_chart_widget.dart'; +import 'package:eatvio_app/features/profile/presentation/widgets/imt_chart_widget.dart'; +import 'package:eatvio_app/features/profile/presentation/widgets/weight_chart_widget.dart'; import 'package:eatvio_app/locator_service.dart'; import 'package:flutter/material.dart'; @@ -18,6 +20,7 @@ class ProfileScreen extends StatefulWidget { class _ProfileScreenState extends State { List chartData = []; + List chartPoints = []; @override Widget build(BuildContext context) { @@ -32,6 +35,7 @@ class _ProfileScreenState extends State { builder: (BuildContext context, ProfileState state) { if (state is ProfileStateLoaded) { chartData = state.profile.circumferences; + chartPoints = state.profile.chartPoints; return Scaffold( appBar: AppBar( toolbarHeight: 0, @@ -48,6 +52,8 @@ class _ProfileScreenState extends State { ), ), CircumferenceChartWidget(chartData: chartData), + WeightChartWidget(chartPoints: chartPoints), + ImtChartWidget(chartPoints: chartPoints), ], ), ), diff --git a/lib/features/profile/presentation/widgets/imt_chart_widget.dart b/lib/features/profile/presentation/widgets/imt_chart_widget.dart new file mode 100644 index 00000000..275a5810 --- /dev/null +++ b/lib/features/profile/presentation/widgets/imt_chart_widget.dart @@ -0,0 +1,69 @@ +import 'package:eatvio_app/features/profile/models/profile_model.dart' as ProfileModel; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:intl/intl.dart'; + +class ImtChartWidget extends StatelessWidget { + final List chartPoints; + + const ImtChartWidget({ + super.key, + required this.chartPoints, + }); + + @override + Widget build(BuildContext context) { + return SfCartesianChart( + margin: EdgeInsets.zero, + enableAxisAnimation: true, + enableSideBySideSeriesPlacement: true, + legend: const Legend( + isVisible: true, + opacity: 0.7, + position: LegendPosition.bottom, + ), + plotAreaBorderWidth: 0, + trackballBehavior: TrackballBehavior( + enable: true, + activationMode: ActivationMode.singleTap, + ), + primaryXAxis: DateTimeAxis( + dateFormat: DateFormat.MMMd('ru'), + axisLine: AxisLine( + width: 1, + ), + ), + primaryYAxis: NumericAxis( + labelFormat: '{value} кг', + axisLine: AxisLine( + width: 1, + ), + majorTickLines: MajorTickLines(size: 0), + ), + series: _getSplineSeries(), + tooltipBehavior: TooltipBehavior(enable: true), + ); + } + + List> _getSplineSeries() { + return >[ + SplineSeries( + markerSettings: MarkerSettings( + isVisible: true, + color: Colors.blue, + height: 12, + width: 12, + ), + dataLabelSettings: DataLabelSettings( + labelAlignment: ChartDataLabelAlignment.top, + isVisible: true, + ), + dataSource: chartPoints, + color: Colors.blue, + name: 'ИМТ', + xValueMapper: (ProfileModel.ChartPoint value, int index) => value.createdAt, + yValueMapper: (ProfileModel.ChartPoint value, int index) => double.parse(value.bmi), + ), + ]; + } +} diff --git a/lib/features/profile/presentation/widgets/weight_chart_widget.dart b/lib/features/profile/presentation/widgets/weight_chart_widget.dart new file mode 100644 index 00000000..eabad3ec --- /dev/null +++ b/lib/features/profile/presentation/widgets/weight_chart_widget.dart @@ -0,0 +1,69 @@ +import 'package:eatvio_app/features/profile/models/profile_model.dart' as ProfileModel; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:intl/intl.dart'; + +class WeightChartWidget extends StatelessWidget { + final List chartPoints; + + const WeightChartWidget({ + super.key, + required this.chartPoints, + }); + + @override + Widget build(BuildContext context) { + return SfCartesianChart( + margin: EdgeInsets.zero, + enableAxisAnimation: true, + enableSideBySideSeriesPlacement: true, + legend: const Legend( + isVisible: true, + opacity: 0.7, + position: LegendPosition.bottom, + ), + plotAreaBorderWidth: 0, + trackballBehavior: TrackballBehavior( + enable: true, + activationMode: ActivationMode.singleTap, + ), + primaryXAxis: DateTimeAxis( + dateFormat: DateFormat.MMMd('ru'), + axisLine: AxisLine( + width: 1, + ), + ), + primaryYAxis: NumericAxis( + labelFormat: '{value} кг', + axisLine: AxisLine( + width: 1, + ), + majorTickLines: MajorTickLines(size: 0), + ), + series: _getSplineSeries(), + tooltipBehavior: TooltipBehavior(enable: true), + ); + } + + List> _getSplineSeries() { + return >[ + SplineSeries( + markerSettings: MarkerSettings( + isVisible: true, + color: Colors.blue, + height: 12, + width: 12, + ), + dataLabelSettings: DataLabelSettings( + labelAlignment: ChartDataLabelAlignment.top, + isVisible: true, + ), + dataSource: chartPoints, + color: Colors.blue, + name: 'Вес', + xValueMapper: (ProfileModel.ChartPoint value, int index) => value.createdAt, + yValueMapper: (ProfileModel.ChartPoint value, int index) => value.weight, + ), + ]; + } +}