forked from eatvio/eatvio_app
feat(profile): add blogPosts of user, charts
This commit is contained in:
@@ -381,7 +381,7 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.blogPost.createdAt.format('dd MMMM', 'ru'),
|
||||
datum.createdAt.format('dd MMMM', 'ru'),
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
|
||||
@@ -497,8 +497,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'99 августа',
|
||||
// datum.createdAt.format('dd MMMM', 'ru'),
|
||||
datum.createdAt.format('dd MMMM', 'ru'),
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
|
||||
@@ -22,6 +22,7 @@ class Datum with _$Datum {
|
||||
@JsonKey(name: "author_profile_icon") required String authorProfileIcon,
|
||||
@JsonKey(name: "body") required String body,
|
||||
@JsonKey(name: "children_comments") required List<Datum> childrenComments,
|
||||
@JsonKey(name: "created_at") required DateTime createdAt,
|
||||
}) = _Datum;
|
||||
|
||||
factory Datum.fromJson(Map<String, Object?> json) => _$DatumFromJson(json);
|
||||
|
||||
@@ -247,6 +247,8 @@ mixin _$Datum {
|
||||
String get body => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "children_comments")
|
||||
List<Datum> get childrenComments => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "created_at")
|
||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
@@ -263,7 +265,8 @@ abstract class $DatumCopyWith<$Res> {
|
||||
@JsonKey(name: "author_name") String authorName,
|
||||
@JsonKey(name: "author_profile_icon") String authorProfileIcon,
|
||||
@JsonKey(name: "body") String body,
|
||||
@JsonKey(name: "children_comments") List<Datum> childrenComments});
|
||||
@JsonKey(name: "children_comments") List<Datum> childrenComments,
|
||||
@JsonKey(name: "created_at") DateTime createdAt});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -284,6 +287,7 @@ class _$DatumCopyWithImpl<$Res, $Val extends Datum>
|
||||
Object? authorProfileIcon = null,
|
||||
Object? body = null,
|
||||
Object? childrenComments = null,
|
||||
Object? createdAt = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
@@ -306,6 +310,10 @@ class _$DatumCopyWithImpl<$Res, $Val extends Datum>
|
||||
? _value.childrenComments
|
||||
: childrenComments // ignore: cast_nullable_to_non_nullable
|
||||
as List<Datum>,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -322,7 +330,8 @@ abstract class _$$DatumImplCopyWith<$Res> implements $DatumCopyWith<$Res> {
|
||||
@JsonKey(name: "author_name") String authorName,
|
||||
@JsonKey(name: "author_profile_icon") String authorProfileIcon,
|
||||
@JsonKey(name: "body") String body,
|
||||
@JsonKey(name: "children_comments") List<Datum> childrenComments});
|
||||
@JsonKey(name: "children_comments") List<Datum> childrenComments,
|
||||
@JsonKey(name: "created_at") DateTime createdAt});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -341,6 +350,7 @@ class __$$DatumImplCopyWithImpl<$Res>
|
||||
Object? authorProfileIcon = null,
|
||||
Object? body = null,
|
||||
Object? childrenComments = null,
|
||||
Object? createdAt = null,
|
||||
}) {
|
||||
return _then(_$DatumImpl(
|
||||
id: null == id
|
||||
@@ -363,6 +373,10 @@ class __$$DatumImplCopyWithImpl<$Res>
|
||||
? _value._childrenComments
|
||||
: childrenComments // ignore: cast_nullable_to_non_nullable
|
||||
as List<Datum>,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -376,7 +390,8 @@ class _$DatumImpl implements _Datum {
|
||||
@JsonKey(name: "author_profile_icon") required this.authorProfileIcon,
|
||||
@JsonKey(name: "body") required this.body,
|
||||
@JsonKey(name: "children_comments")
|
||||
required final List<Datum> childrenComments})
|
||||
required final List<Datum> childrenComments,
|
||||
@JsonKey(name: "created_at") required this.createdAt})
|
||||
: _childrenComments = childrenComments;
|
||||
|
||||
factory _$DatumImpl.fromJson(Map<String, dynamic> json) =>
|
||||
@@ -404,9 +419,13 @@ class _$DatumImpl implements _Datum {
|
||||
return EqualUnmodifiableListView(_childrenComments);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey(name: "created_at")
|
||||
final DateTime createdAt;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Datum(id: $id, authorName: $authorName, authorProfileIcon: $authorProfileIcon, body: $body, childrenComments: $childrenComments)';
|
||||
return 'Datum(id: $id, authorName: $authorName, authorProfileIcon: $authorProfileIcon, body: $body, childrenComments: $childrenComments, createdAt: $createdAt)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -421,7 +440,9 @@ class _$DatumImpl implements _Datum {
|
||||
other.authorProfileIcon == authorProfileIcon) &&
|
||||
(identical(other.body, body) || other.body == body) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._childrenComments, _childrenComments));
|
||||
.equals(other._childrenComments, _childrenComments) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@@ -432,7 +453,8 @@ class _$DatumImpl implements _Datum {
|
||||
authorName,
|
||||
authorProfileIcon,
|
||||
body,
|
||||
const DeepCollectionEquality().hash(_childrenComments));
|
||||
const DeepCollectionEquality().hash(_childrenComments),
|
||||
createdAt);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@@ -450,13 +472,15 @@ class _$DatumImpl implements _Datum {
|
||||
|
||||
abstract class _Datum implements Datum {
|
||||
const factory _Datum(
|
||||
{@JsonKey(name: "id") required final int id,
|
||||
@JsonKey(name: "author_name") required final String authorName,
|
||||
@JsonKey(name: "author_profile_icon")
|
||||
required final String authorProfileIcon,
|
||||
@JsonKey(name: "body") required final String body,
|
||||
@JsonKey(name: "children_comments")
|
||||
required final List<Datum> childrenComments}) = _$DatumImpl;
|
||||
{@JsonKey(name: "id") required final int id,
|
||||
@JsonKey(name: "author_name") required final String authorName,
|
||||
@JsonKey(name: "author_profile_icon")
|
||||
required final String authorProfileIcon,
|
||||
@JsonKey(name: "body") required final String body,
|
||||
@JsonKey(name: "children_comments")
|
||||
required final List<Datum> childrenComments,
|
||||
@JsonKey(name: "created_at") required final DateTime createdAt}) =
|
||||
_$DatumImpl;
|
||||
|
||||
factory _Datum.fromJson(Map<String, dynamic> json) = _$DatumImpl.fromJson;
|
||||
|
||||
@@ -476,6 +500,9 @@ abstract class _Datum implements Datum {
|
||||
@JsonKey(name: "children_comments")
|
||||
List<Datum> get childrenComments;
|
||||
@override
|
||||
@JsonKey(name: "created_at")
|
||||
DateTime get createdAt;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$DatumImplCopyWith<_$DatumImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
@@ -30,6 +30,7 @@ _$DatumImpl _$$DatumImplFromJson(Map<String, dynamic> json) => _$DatumImpl(
|
||||
childrenComments: (json['children_comments'] as List<dynamic>)
|
||||
.map((e) => Datum.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$DatumImplToJson(_$DatumImpl instance) =>
|
||||
@@ -39,6 +40,7 @@ Map<String, dynamic> _$$DatumImplToJson(_$DatumImpl instance) =>
|
||||
'author_profile_icon': instance.authorProfileIcon,
|
||||
'body': instance.body,
|
||||
'children_comments': instance.childrenComments,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
};
|
||||
|
||||
_$LinksImpl _$$LinksImplFromJson(Map<String, dynamic> json) => _$LinksImpl(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/constants/constants.dart';
|
||||
import 'package:eatvio_app/core/app_export.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
import 'package:eatvio_app/core/utils/image_constant.dart';
|
||||
import 'package:eatvio_app/locator_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
@@ -14,6 +13,7 @@ class MenuScreen extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: false,
|
||||
title: Text('Меню'),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
@@ -83,6 +83,7 @@ class MenuScreen extends StatelessWidget {
|
||||
leading,
|
||||
height: 24,
|
||||
width: 24,
|
||||
colorFilter: ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn),
|
||||
),
|
||||
title: Text(title),
|
||||
trailing: Icon(
|
||||
|
||||
@@ -100,8 +100,8 @@ class ChartPoint with _$ChartPoint {
|
||||
const factory 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: "weight") required double weight,
|
||||
@JsonKey(name: "bmi") required double bmi,
|
||||
@JsonKey(name: "created_at") required DateTime createdAt,
|
||||
@JsonKey(name: "updated_at") required DateTime updatedAt,
|
||||
}) = _ChartPoint;
|
||||
|
||||
@@ -2121,9 +2121,9 @@ mixin _$ChartPoint {
|
||||
@JsonKey(name: "user_id")
|
||||
int get userId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "weight")
|
||||
int get weight => throw _privateConstructorUsedError;
|
||||
double get weight => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "bmi")
|
||||
String get bmi => throw _privateConstructorUsedError;
|
||||
double get bmi => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "created_at")
|
||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "updated_at")
|
||||
@@ -2144,8 +2144,8 @@ abstract class $ChartPointCopyWith<$Res> {
|
||||
$Res call(
|
||||
{@JsonKey(name: "id") int id,
|
||||
@JsonKey(name: "user_id") int userId,
|
||||
@JsonKey(name: "weight") int weight,
|
||||
@JsonKey(name: "bmi") String bmi,
|
||||
@JsonKey(name: "weight") double weight,
|
||||
@JsonKey(name: "bmi") double bmi,
|
||||
@JsonKey(name: "created_at") DateTime createdAt,
|
||||
@JsonKey(name: "updated_at") DateTime updatedAt});
|
||||
}
|
||||
@@ -2182,11 +2182,11 @@ class _$ChartPointCopyWithImpl<$Res, $Val extends ChartPoint>
|
||||
weight: null == weight
|
||||
? _value.weight
|
||||
: weight // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
as double,
|
||||
bmi: null == bmi
|
||||
? _value.bmi
|
||||
: bmi // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
as double,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
@@ -2210,8 +2210,8 @@ abstract class _$$ChartPointImplCopyWith<$Res>
|
||||
$Res call(
|
||||
{@JsonKey(name: "id") int id,
|
||||
@JsonKey(name: "user_id") int userId,
|
||||
@JsonKey(name: "weight") int weight,
|
||||
@JsonKey(name: "bmi") String bmi,
|
||||
@JsonKey(name: "weight") double weight,
|
||||
@JsonKey(name: "bmi") double bmi,
|
||||
@JsonKey(name: "created_at") DateTime createdAt,
|
||||
@JsonKey(name: "updated_at") DateTime updatedAt});
|
||||
}
|
||||
@@ -2246,11 +2246,11 @@ class __$$ChartPointImplCopyWithImpl<$Res>
|
||||
weight: null == weight
|
||||
? _value.weight
|
||||
: weight // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
as double,
|
||||
bmi: null == bmi
|
||||
? _value.bmi
|
||||
: bmi // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
as double,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
@@ -2285,10 +2285,10 @@ class _$ChartPointImpl implements _ChartPoint {
|
||||
final int userId;
|
||||
@override
|
||||
@JsonKey(name: "weight")
|
||||
final int weight;
|
||||
final double weight;
|
||||
@override
|
||||
@JsonKey(name: "bmi")
|
||||
final String bmi;
|
||||
final double bmi;
|
||||
@override
|
||||
@JsonKey(name: "created_at")
|
||||
final DateTime createdAt;
|
||||
@@ -2339,8 +2339,8 @@ abstract class _ChartPoint implements ChartPoint {
|
||||
const factory _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: "weight") required final double weight,
|
||||
@JsonKey(name: "bmi") required final double bmi,
|
||||
@JsonKey(name: "created_at") required final DateTime createdAt,
|
||||
@JsonKey(name: "updated_at") required final DateTime updatedAt}) =
|
||||
_$ChartPointImpl;
|
||||
@@ -2356,10 +2356,10 @@ abstract class _ChartPoint implements ChartPoint {
|
||||
int get userId;
|
||||
@override
|
||||
@JsonKey(name: "weight")
|
||||
int get weight;
|
||||
double get weight;
|
||||
@override
|
||||
@JsonKey(name: "bmi")
|
||||
String get bmi;
|
||||
double get bmi;
|
||||
@override
|
||||
@JsonKey(name: "created_at")
|
||||
DateTime get createdAt;
|
||||
|
||||
@@ -168,8 +168,8 @@ _$ChartPointImpl _$$ChartPointImplFromJson(Map<String, dynamic> json) =>
|
||||
_$ChartPointImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
userId: (json['user_id'] as num).toInt(),
|
||||
weight: (json['weight'] as num).toInt(),
|
||||
bmi: json['bmi'] as String,
|
||||
weight: (json['weight'] as num).toDouble(),
|
||||
bmi: (json['bmi'] as num).toDouble(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ class ProfileCubit extends Cubit<ProfileState> {
|
||||
try {
|
||||
emit(ProfileState.loaded(
|
||||
profile: await profileRepository.getProfileBySlug(slug),
|
||||
blogPosts: await profileRepository.getBlogPostsByAuthorSlug(slug: slug),
|
||||
));
|
||||
} catch (e) {
|
||||
emit(ProfileState.error(errorMessage: e.toString()));
|
||||
@@ -22,8 +23,10 @@ class ProfileCubit extends Cubit<ProfileState> {
|
||||
|
||||
getMyProfile() async {
|
||||
try {
|
||||
final myProfile = await profileRepository.getMyProfile();
|
||||
emit(ProfileState.loaded(
|
||||
profile: await profileRepository.getMyProfile(),
|
||||
profile: myProfile,
|
||||
blogPosts: await profileRepository.getBlogPostsByAuthorSlug(slug: myProfile.user.slug),
|
||||
));
|
||||
} catch (e) {
|
||||
emit(ProfileState.error(errorMessage: e.toString()));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@@ -11,6 +12,7 @@ abstract class ProfileState with _$ProfileState {
|
||||
|
||||
const factory ProfileState.loaded({
|
||||
required ProfileModel profile,
|
||||
required List<FeedBlogPostModel> blogPosts,
|
||||
}) = ProfileStateLoaded;
|
||||
|
||||
const factory ProfileState.error({
|
||||
|
||||
@@ -20,7 +20,9 @@ mixin _$ProfileState {
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(ProfileModel profile) loaded,
|
||||
required TResult Function(
|
||||
ProfileModel profile, List<FeedBlogPostModel> blogPosts)
|
||||
loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@@ -28,7 +30,8 @@ mixin _$ProfileState {
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(ProfileModel profile)? loaded,
|
||||
TResult? Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@@ -36,7 +39,8 @@ mixin _$ProfileState {
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(ProfileModel profile)? loaded,
|
||||
TResult Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
@@ -126,7 +130,9 @@ class _$ProfileStateImpl implements _ProfileState {
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(ProfileModel profile) loaded,
|
||||
required TResult Function(
|
||||
ProfileModel profile, List<FeedBlogPostModel> blogPosts)
|
||||
loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return $default();
|
||||
@@ -137,7 +143,8 @@ class _$ProfileStateImpl implements _ProfileState {
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(ProfileModel profile)? loaded,
|
||||
TResult? Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return $default?.call();
|
||||
@@ -148,7 +155,8 @@ class _$ProfileStateImpl implements _ProfileState {
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(ProfileModel profile)? loaded,
|
||||
TResult Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -241,7 +249,9 @@ class _$ProfileStateLoadingImpl implements ProfileStateLoading {
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(ProfileModel profile) loaded,
|
||||
required TResult Function(
|
||||
ProfileModel profile, List<FeedBlogPostModel> blogPosts)
|
||||
loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return loading();
|
||||
@@ -252,7 +262,8 @@ class _$ProfileStateLoadingImpl implements ProfileStateLoading {
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(ProfileModel profile)? loaded,
|
||||
TResult? Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
@@ -263,7 +274,8 @@ class _$ProfileStateLoadingImpl implements ProfileStateLoading {
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(ProfileModel profile)? loaded,
|
||||
TResult Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@@ -321,7 +333,7 @@ abstract class _$$ProfileStateLoadedImplCopyWith<$Res> {
|
||||
$Res Function(_$ProfileStateLoadedImpl) then) =
|
||||
__$$ProfileStateLoadedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({ProfileModel profile});
|
||||
$Res call({ProfileModel profile, List<FeedBlogPostModel> blogPosts});
|
||||
|
||||
$ProfileModelCopyWith<$Res> get profile;
|
||||
}
|
||||
@@ -338,12 +350,17 @@ class __$$ProfileStateLoadedImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? profile = null,
|
||||
Object? blogPosts = null,
|
||||
}) {
|
||||
return _then(_$ProfileStateLoadedImpl(
|
||||
profile: null == profile
|
||||
? _value.profile
|
||||
: profile // ignore: cast_nullable_to_non_nullable
|
||||
as ProfileModel,
|
||||
blogPosts: null == blogPosts
|
||||
? _value._blogPosts
|
||||
: blogPosts // ignore: cast_nullable_to_non_nullable
|
||||
as List<FeedBlogPostModel>,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -359,14 +376,23 @@ class __$$ProfileStateLoadedImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
|
||||
class _$ProfileStateLoadedImpl implements ProfileStateLoaded {
|
||||
const _$ProfileStateLoadedImpl({required this.profile});
|
||||
const _$ProfileStateLoadedImpl(
|
||||
{required this.profile, required final List<FeedBlogPostModel> blogPosts})
|
||||
: _blogPosts = blogPosts;
|
||||
|
||||
@override
|
||||
final ProfileModel profile;
|
||||
final List<FeedBlogPostModel> _blogPosts;
|
||||
@override
|
||||
List<FeedBlogPostModel> get blogPosts {
|
||||
if (_blogPosts is EqualUnmodifiableListView) return _blogPosts;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_blogPosts);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProfileState.loaded(profile: $profile)';
|
||||
return 'ProfileState.loaded(profile: $profile, blogPosts: $blogPosts)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -374,11 +400,14 @@ class _$ProfileStateLoadedImpl implements ProfileStateLoaded {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ProfileStateLoadedImpl &&
|
||||
(identical(other.profile, profile) || other.profile == profile));
|
||||
(identical(other.profile, profile) || other.profile == profile) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._blogPosts, _blogPosts));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, profile);
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, profile, const DeepCollectionEquality().hash(_blogPosts));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@@ -392,10 +421,12 @@ class _$ProfileStateLoadedImpl implements ProfileStateLoaded {
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(ProfileModel profile) loaded,
|
||||
required TResult Function(
|
||||
ProfileModel profile, List<FeedBlogPostModel> blogPosts)
|
||||
loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return loaded(profile);
|
||||
return loaded(profile, blogPosts);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -403,10 +434,11 @@ class _$ProfileStateLoadedImpl implements ProfileStateLoaded {
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(ProfileModel profile)? loaded,
|
||||
TResult? Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return loaded?.call(profile);
|
||||
return loaded?.call(profile, blogPosts);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -414,12 +446,13 @@ class _$ProfileStateLoadedImpl implements ProfileStateLoaded {
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(ProfileModel profile)? loaded,
|
||||
TResult Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(profile);
|
||||
return loaded(profile, blogPosts);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
@@ -463,10 +496,13 @@ class _$ProfileStateLoadedImpl implements ProfileStateLoaded {
|
||||
}
|
||||
|
||||
abstract class ProfileStateLoaded implements ProfileState {
|
||||
const factory ProfileStateLoaded({required final ProfileModel profile}) =
|
||||
const factory ProfileStateLoaded(
|
||||
{required final ProfileModel profile,
|
||||
required final List<FeedBlogPostModel> blogPosts}) =
|
||||
_$ProfileStateLoadedImpl;
|
||||
|
||||
ProfileModel get profile;
|
||||
List<FeedBlogPostModel> get blogPosts;
|
||||
@JsonKey(ignore: true)
|
||||
_$$ProfileStateLoadedImplCopyWith<_$ProfileStateLoadedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
@@ -540,7 +576,9 @@ class _$ProfileStateErrorImpl implements ProfileStateError {
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(ProfileModel profile) loaded,
|
||||
required TResult Function(
|
||||
ProfileModel profile, List<FeedBlogPostModel> blogPosts)
|
||||
loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return error(errorMessage);
|
||||
@@ -551,7 +589,8 @@ class _$ProfileStateErrorImpl implements ProfileStateError {
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(ProfileModel profile)? loaded,
|
||||
TResult? Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return error?.call(errorMessage);
|
||||
@@ -562,7 +601,8 @@ class _$ProfileStateErrorImpl implements ProfileStateError {
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(ProfileModel profile)? loaded,
|
||||
TResult Function(ProfileModel profile, List<FeedBlogPostModel> blogPosts)?
|
||||
loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:eatvio_app/core/app_export.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart';
|
||||
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';
|
||||
@@ -21,6 +22,10 @@ class ProfileScreen extends StatefulWidget {
|
||||
class _ProfileScreenState extends State<ProfileScreen> {
|
||||
List<Circumference> chartData = [];
|
||||
List<ChartPoint> chartPoints = [];
|
||||
final List<String> chipsLabelList = ['Вес', 'Замеры', 'ИМТ'];
|
||||
final List<String> chipsIntervalLabelList = ['1М', '3М', '6М', '1Г', 'ВСЁ ВРЕМЯ'];
|
||||
int _selectedChipIndex = 0;
|
||||
int _selectedIntervalChipIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -37,23 +42,111 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
chartData = state.profile.circumferences;
|
||||
chartPoints = state.profile.chartPoints;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 0,
|
||||
),
|
||||
backgroundColor: Colors.grey.shade200,
|
||||
appBar: widget.author == null ? AppBar(toolbarHeight: 0) : AppBar(),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, bottom: 32),
|
||||
child: CircleAvatar(
|
||||
radius: 32,
|
||||
backgroundImage: NetworkImage(state.profile.user.profilePhotoUrl),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 32,
|
||||
backgroundImage: NetworkImage(state.profile.user.profilePhotoUrl),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
state.profile.user.name,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
if (state.profile.userDetails.additionalInfo.isNotEmpty)
|
||||
Text(
|
||||
state.profile.userDetails.additionalInfo,
|
||||
style: TextStyle(
|
||||
color: Colors.black.withOpacity(0.4),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
CircumferenceChartWidget(chartData: chartData),
|
||||
WeightChartWidget(chartPoints: chartPoints),
|
||||
ImtChartWidget(chartPoints: chartPoints),
|
||||
if (widget.author == null) SizedBox(height: 8),
|
||||
if (widget.author == null)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: [
|
||||
_choiceChipWidget(0),
|
||||
SizedBox(width: 8),
|
||||
_choiceChipWidget(1),
|
||||
SizedBox(width: 8),
|
||||
_choiceChipWidget(2),
|
||||
],
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (context) {
|
||||
if (_selectedChipIndex == 0) return WeightChartWidget(chartPoints: chartPoints);
|
||||
if (_selectedChipIndex == 1) return CircumferenceChartWidget(chartData: chartData);
|
||||
if (_selectedChipIndex == 2)
|
||||
return ImtChartWidget(chartPoints: chartPoints);
|
||||
else
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 16),
|
||||
_choiceIntervalChipWidget(0),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(1),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(2),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(3),
|
||||
SizedBox(width: 8),
|
||||
_choiceIntervalChipWidget(4),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => BlogPostWidget(feedBlogPostModel: state.blogPosts[index]),
|
||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||
itemCount: state.blogPosts.length,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -80,4 +173,55 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_choiceIntervalChipWidget(int index) {
|
||||
return ChoiceChip(
|
||||
selectedColor: Colors.grey.withOpacity(0.1),
|
||||
pressElevation: 0,
|
||||
showCheckmark: false,
|
||||
side: BorderSide.none,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
label: Text(chipsIntervalLabelList[index]),
|
||||
labelStyle: TextStyle(
|
||||
color: appTheme.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
),
|
||||
selected: _selectedIntervalChipIndex == index,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedIntervalChipIndex = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_choiceChipWidget(int index) {
|
||||
return ChoiceChip(
|
||||
selectedColor: appTheme.blueA400,
|
||||
pressElevation: 0,
|
||||
showCheckmark: false,
|
||||
side: BorderSide.none,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
label: Text(chipsLabelList[index]),
|
||||
labelStyle: TextStyle(
|
||||
color: index == _selectedChipIndex ? Colors.white : appTheme.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
),
|
||||
selected: _selectedChipIndex == index,
|
||||
backgroundColor: appTheme.gray100,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
_selectedChipIndex = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class CircumferenceChartWidget extends StatelessWidget {
|
||||
final List<Circumference> chartData;
|
||||
@@ -13,35 +13,103 @@ class CircumferenceChartWidget extends StatelessWidget {
|
||||
|
||||
@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,
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'Грудь ${chartData.last.chestCircumference} см',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
chartData.last.chestCircumference > chartData[chartData.length - 2].chestCircumference
|
||||
? Icon(
|
||||
Icons.arrow_drop_up,
|
||||
size: 18,
|
||||
color: Colors.grey,
|
||||
)
|
||||
: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 18,
|
||||
color: Colors.grey,
|
||||
),
|
||||
Text(
|
||||
'Талия ${chartData.last.waistCircumference} см',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
chartData.last.waistCircumference > chartData[chartData.length - 2].waistCircumference
|
||||
? Icon(
|
||||
Icons.arrow_drop_up,
|
||||
size: 18,
|
||||
color: Colors.grey,
|
||||
)
|
||||
: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 18,
|
||||
color: Colors.grey,
|
||||
),
|
||||
Text(
|
||||
'Бёдра ${chartData.last.hipCircumference} см',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
chartData.last.hipCircumference > chartData[chartData.length - 2].hipCircumference
|
||||
? Icon(
|
||||
Icons.arrow_drop_up,
|
||||
size: 18,
|
||||
color: Colors.grey,
|
||||
)
|
||||
: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 18,
|
||||
color: Colors.grey,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryYAxis: NumericAxis(
|
||||
labelFormat: '{value} см',
|
||||
axisLine: AxisLine(
|
||||
width: 1,
|
||||
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: DateTimeCategoryAxis(
|
||||
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),
|
||||
),
|
||||
majorTickLines: MajorTickLines(size: 0),
|
||||
),
|
||||
series: _getSplineSeries(),
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,35 +13,61 @@ class ImtChartWidget extends StatelessWidget {
|
||||
|
||||
@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,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'${chartPoints.last.bmi.toStringAsFixed(2)} кг/м²',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
chartPoints.last.bmi > chartPoints[chartPoints.length - 2].bmi
|
||||
? Icon(
|
||||
Icons.arrow_drop_up,
|
||||
size: 48,
|
||||
color: Colors.grey,
|
||||
)
|
||||
: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 48,
|
||||
color: Colors.grey,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryYAxis: NumericAxis(
|
||||
labelFormat: '{value} кг',
|
||||
axisLine: AxisLine(
|
||||
width: 1,
|
||||
SfCartesianChart(
|
||||
margin: EdgeInsets.zero,
|
||||
enableAxisAnimation: true,
|
||||
enableSideBySideSeriesPlacement: true,
|
||||
plotAreaBorderWidth: 0,
|
||||
trackballBehavior: TrackballBehavior(
|
||||
enable: true,
|
||||
activationMode: ActivationMode.singleTap,
|
||||
),
|
||||
primaryXAxis: DateTimeCategoryAxis(
|
||||
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),
|
||||
),
|
||||
majorTickLines: MajorTickLines(size: 0),
|
||||
),
|
||||
series: _getSplineSeries(),
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +88,7 @@ class ImtChartWidget extends StatelessWidget {
|
||||
color: Colors.blue,
|
||||
name: 'ИМТ',
|
||||
xValueMapper: (ProfileModel.ChartPoint value, int index) => value.createdAt,
|
||||
yValueMapper: (ProfileModel.ChartPoint value, int index) => double.parse(value.bmi),
|
||||
yValueMapper: (ProfileModel.ChartPoint value, int index) => value.bmi,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:eatvio_app/core/app_export.dart';
|
||||
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';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class WeightChartWidget extends StatelessWidget {
|
||||
final List<ProfileModel.ChartPoint> chartPoints;
|
||||
@@ -13,53 +14,103 @@ class WeightChartWidget extends StatelessWidget {
|
||||
|
||||
@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,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'${chartPoints.last.weight} кг',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
chartPoints.last.weight > chartPoints[chartPoints.length - 2].weight
|
||||
? Icon(
|
||||
Icons.arrow_drop_up,
|
||||
size: 48,
|
||||
color: Colors.grey.withOpacity(0.4),
|
||||
)
|
||||
: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 48,
|
||||
color: Colors.grey.withOpacity(0.4),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryYAxis: NumericAxis(
|
||||
labelFormat: '{value} кг',
|
||||
axisLine: AxisLine(
|
||||
width: 1,
|
||||
SfCartesianChart(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8),
|
||||
enableAxisAnimation: true,
|
||||
plotAreaBorderWidth: 0,
|
||||
trackballBehavior: TrackballBehavior(
|
||||
enable: true,
|
||||
activationMode: ActivationMode.singleTap,
|
||||
tooltipDisplayMode: TrackballDisplayMode.groupAllPoints,
|
||||
tooltipSettings: InteractiveTooltip(),
|
||||
lineType: TrackballLineType.vertical,
|
||||
),
|
||||
primaryXAxis: DateTimeCategoryAxis(
|
||||
initialVisibleMinimum: chartPoints.first.createdAt,
|
||||
initialVisibleMaximum: chartPoints.last.createdAt,
|
||||
tickPosition: TickPosition.inside,
|
||||
majorTickLines: MajorTickLines(
|
||||
size: 0,
|
||||
),
|
||||
edgeLabelPlacement: EdgeLabelPlacement.shift,
|
||||
dateFormat: DateFormat.MMMd('ru'),
|
||||
labelStyle: TextStyle(
|
||||
color: Colors.grey,
|
||||
),
|
||||
majorGridLines: MajorGridLines(dashArray: [1], color: Colors.grey.withOpacity(0.3)),
|
||||
axisLine: AxisLine(
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
width: 0.4,
|
||||
),
|
||||
),
|
||||
primaryYAxis: NumericAxis(
|
||||
isVisible: false,
|
||||
labelFormat: '{value} кг',
|
||||
majorGridLines: MajorGridLines(dashArray: [1], color: Colors.grey),
|
||||
axisLine: AxisLine(
|
||||
width: 1,
|
||||
),
|
||||
majorTickLines: MajorTickLines(size: 0),
|
||||
),
|
||||
series: _getSplineSeries(),
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
),
|
||||
majorTickLines: MajorTickLines(size: 0),
|
||||
),
|
||||
series: _getSplineSeries(),
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<CartesianSeries<ProfileModel.ChartPoint, DateTime>> _getSplineSeries() {
|
||||
return <CartesianSeries<ProfileModel.ChartPoint, DateTime>>[
|
||||
SplineSeries<ProfileModel.ChartPoint, DateTime>(
|
||||
SplineAreaSeries<ProfileModel.ChartPoint, DateTime>(
|
||||
markerSettings: MarkerSettings(
|
||||
isVisible: true,
|
||||
color: Colors.blue,
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: appTheme.blueA400,
|
||||
height: 8,
|
||||
width: 8,
|
||||
),
|
||||
dataLabelSettings: DataLabelSettings(
|
||||
labelAlignment: ChartDataLabelAlignment.top,
|
||||
isVisible: true,
|
||||
),
|
||||
dataSource: chartPoints,
|
||||
color: Colors.blue,
|
||||
borderColor: appTheme.blueA400,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
appTheme.blueA400.withOpacity(0.14),
|
||||
Colors.transparent,
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment(0, 0.6),
|
||||
),
|
||||
name: 'Вес',
|
||||
xValueMapper: (ProfileModel.ChartPoint value, int index) => value.createdAt,
|
||||
yValueMapper: (ProfileModel.ChartPoint value, int index) => value.weight,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:eatvio_app/features/profile/services/profile_service.dart';
|
||||
|
||||
@@ -53,4 +54,17 @@ class ProfileRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<FeedBlogPostModel>> getBlogPostsByAuthorSlug({
|
||||
required String slug,
|
||||
}) async {
|
||||
try {
|
||||
return (await profileService.getBlogPostByAuthorSlug(
|
||||
slug: slug,
|
||||
))
|
||||
.feedBlogPostList;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
@@ -27,4 +28,9 @@ abstract class ProfileService {
|
||||
Future<Map<String, ChartPoint>> addWeight({
|
||||
@Part() required int weight,
|
||||
});
|
||||
|
||||
@GET('/api/blogPosts/search_by_author/{slug}')
|
||||
Future<FeedBlogPostSettingsModel> getBlogPostByAuthorSlug({
|
||||
@Path() required String slug,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -175,6 +175,40 @@ class _ProfileService implements ProfileService {
|
||||
return _value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<FeedBlogPostSettingsModel> getBlogPostByAuthorSlug(
|
||||
{required String slug}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
const Map<String, dynamic>? _data = null;
|
||||
final _options = _setStreamType<FeedBlogPostSettingsModel>(Options(
|
||||
method: 'GET',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/blogPosts/search_by_author/${slug}',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
)));
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
|
||||
late FeedBlogPostSettingsModel _value;
|
||||
try {
|
||||
_value = FeedBlogPostSettingsModel.fromJson(_result.data!);
|
||||
} on Object catch (e, s) {
|
||||
errorLogger?.logError(e, s, _options);
|
||||
rethrow;
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
|
||||
@@ -455,7 +455,7 @@ class _AboutRecipesScreenState extends State<AboutRecipesScreen> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.recipes.createdAt.format('dd MMMM', 'ru'),
|
||||
datum.createdAt.format('dd MMMM', 'ru'),
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
|
||||
Reference in New Issue
Block a user