feat(profile): add subscribers and subscriptions

This commit is contained in:
mso7nueh
2024-10-16 15:52:23 +03:00
parent b0f8057aa0
commit 079a712997
11 changed files with 1046 additions and 267 deletions

View File

@@ -13,7 +13,7 @@ class ChatSelectCubit extends Cubit<ChatSelectState> {
emit(ChatSelectState.loading());
try {
emit(ChatSelectState.loaded(
chatRooms: (await chatRepository.getChatRoomPreiews(query: query)),
chatRooms: (await chatRepository.getChatRoomPreviews(query: query)),
));
} catch (e) {
emit(

View File

@@ -55,7 +55,7 @@ class ChatRepository {
}
}
Future<List<ChatRoom>> getChatRoomPreiews({String? query}) async {
Future<List<ChatRoom>> getChatRoomPreviews({String? query}) async {
try {
return (await chatService.getChatRoomPreviews(query: query)).chatRooms;
} catch (e) {
@@ -81,4 +81,13 @@ class ChatRepository {
rethrow;
}
}
Future<ChatRoomModel> getChatRoomIdByUserSlug({required String slug}) async {
try {
return (await chatService.getChatRoomIdByUserSlug(user: slug));
} catch (e) {
print(e);
rethrow;
}
}
}

View File

@@ -0,0 +1,19 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'badge_model.freezed.dart';
part 'badge_model.g.dart';
@freezed
class BadgeModel with _$BadgeModel {
const factory BadgeModel({
required int id,
required String title,
required String description,
required String image,
required String type,
required String parameters,
}) = _BadgeModel;
factory BadgeModel.fromJson(Map<String, Object?> json) => _$BadgeModelFromJson(json);
}

View File

@@ -0,0 +1,271 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'badge_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
BadgeModel _$BadgeModelFromJson(Map<String, dynamic> json) {
return _BadgeModel.fromJson(json);
}
/// @nodoc
mixin _$BadgeModel {
int get id => throw _privateConstructorUsedError;
String get title => throw _privateConstructorUsedError;
String get description => throw _privateConstructorUsedError;
String get image => throw _privateConstructorUsedError;
String get type => throw _privateConstructorUsedError;
String get parameters => throw _privateConstructorUsedError;
/// Serializes this BadgeModel to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of BadgeModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$BadgeModelCopyWith<BadgeModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $BadgeModelCopyWith<$Res> {
factory $BadgeModelCopyWith(
BadgeModel value, $Res Function(BadgeModel) then) =
_$BadgeModelCopyWithImpl<$Res, BadgeModel>;
@useResult
$Res call(
{int id,
String title,
String description,
String image,
String type,
String parameters});
}
/// @nodoc
class _$BadgeModelCopyWithImpl<$Res, $Val extends BadgeModel>
implements $BadgeModelCopyWith<$Res> {
_$BadgeModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of BadgeModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? title = null,
Object? description = null,
Object? image = null,
Object? type = null,
Object? parameters = null,
}) {
return _then(_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
description: null == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String,
image: null == image
? _value.image
: image // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
parameters: null == parameters
? _value.parameters
: parameters // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$BadgeModelImplCopyWith<$Res>
implements $BadgeModelCopyWith<$Res> {
factory _$$BadgeModelImplCopyWith(
_$BadgeModelImpl value, $Res Function(_$BadgeModelImpl) then) =
__$$BadgeModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int id,
String title,
String description,
String image,
String type,
String parameters});
}
/// @nodoc
class __$$BadgeModelImplCopyWithImpl<$Res>
extends _$BadgeModelCopyWithImpl<$Res, _$BadgeModelImpl>
implements _$$BadgeModelImplCopyWith<$Res> {
__$$BadgeModelImplCopyWithImpl(
_$BadgeModelImpl _value, $Res Function(_$BadgeModelImpl) _then)
: super(_value, _then);
/// Create a copy of BadgeModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? title = null,
Object? description = null,
Object? image = null,
Object? type = null,
Object? parameters = null,
}) {
return _then(_$BadgeModelImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
description: null == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String,
image: null == image
? _value.image
: image // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
parameters: null == parameters
? _value.parameters
: parameters // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$BadgeModelImpl implements _BadgeModel {
const _$BadgeModelImpl(
{required this.id,
required this.title,
required this.description,
required this.image,
required this.type,
required this.parameters});
factory _$BadgeModelImpl.fromJson(Map<String, dynamic> json) =>
_$$BadgeModelImplFromJson(json);
@override
final int id;
@override
final String title;
@override
final String description;
@override
final String image;
@override
final String type;
@override
final String parameters;
@override
String toString() {
return 'BadgeModel(id: $id, title: $title, description: $description, image: $image, type: $type, parameters: $parameters)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$BadgeModelImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.title, title) || other.title == title) &&
(identical(other.description, description) ||
other.description == description) &&
(identical(other.image, image) || other.image == image) &&
(identical(other.type, type) || other.type == type) &&
(identical(other.parameters, parameters) ||
other.parameters == parameters));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode =>
Object.hash(runtimeType, id, title, description, image, type, parameters);
/// Create a copy of BadgeModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$BadgeModelImplCopyWith<_$BadgeModelImpl> get copyWith =>
__$$BadgeModelImplCopyWithImpl<_$BadgeModelImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$BadgeModelImplToJson(
this,
);
}
}
abstract class _BadgeModel implements BadgeModel {
const factory _BadgeModel(
{required final int id,
required final String title,
required final String description,
required final String image,
required final String type,
required final String parameters}) = _$BadgeModelImpl;
factory _BadgeModel.fromJson(Map<String, dynamic> json) =
_$BadgeModelImpl.fromJson;
@override
int get id;
@override
String get title;
@override
String get description;
@override
String get image;
@override
String get type;
@override
String get parameters;
/// Create a copy of BadgeModel
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$BadgeModelImplCopyWith<_$BadgeModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'badge_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$BadgeModelImpl _$$BadgeModelImplFromJson(Map<String, dynamic> json) =>
_$BadgeModelImpl(
id: (json['id'] as num).toInt(),
title: json['title'] as String,
description: json['description'] as String,
image: json['image'] as String,
type: json['type'] as String,
parameters: json['parameters'] as String,
);
Map<String, dynamic> _$$BadgeModelImplToJson(_$BadgeModelImpl instance) =>
<String, dynamic>{
'id': instance.id,
'title': instance.title,
'description': instance.description,
'image': instance.image,
'type': instance.type,
'parameters': instance.parameters,
};

View File

@@ -1,3 +1,4 @@
import 'package:eatvio_app/features/profile/models/badge_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'profile_model.freezed.dart';
@@ -16,7 +17,10 @@ class ProfileModel with _$ProfileModel {
@JsonKey(name: "is_public_profile") required bool isPublicProfile,
@JsonKey(name: "slug") required String slug,
@JsonKey(name: "profile_photo_url") required String profilePhotoUrl,
required String role,
@JsonKey(name: "role") required String role,
@JsonKey(name: "badges") required List<BadgeModel> badges,
@JsonKey(name: "subscriptions") required List<ProfilePreviewModel> subscriptions,
@JsonKey(name: "subscribers") required List<ProfilePreviewModel> subscribers,
}) = _ProfileModel;
factory ProfileModel.fromJson(Map<String, dynamic> json) => _$ProfileModelFromJson(json);
@@ -56,3 +60,12 @@ class ProfileDetailsModel with _$ProfileDetailsModel {
factory ProfileDetailsModel.fromJson(Map<String, dynamic> json) => _$ProfileDetailsModelFromJson(json);
}
@freezed
class ProfilePreviewModel with _$ProfilePreviewModel {
const factory ProfilePreviewModel({
@JsonKey(name: "profile_photo_url") required String profilePhotoUrl,
}) = _ProfilePreviewModel;
factory ProfilePreviewModel.fromJson(Map<String, dynamic> json) => _$ProfilePreviewModelFromJson(json);
}

View File

@@ -38,7 +38,16 @@ mixin _$ProfileModel {
String get slug => throw _privateConstructorUsedError;
@JsonKey(name: "profile_photo_url")
String get profilePhotoUrl => throw _privateConstructorUsedError;
@JsonKey(name: "role")
String get role => throw _privateConstructorUsedError;
@JsonKey(name: "badges")
List<BadgeModel> get badges => throw _privateConstructorUsedError;
@JsonKey(name: "subscriptions")
List<ProfilePreviewModel> get subscriptions =>
throw _privateConstructorUsedError;
@JsonKey(name: "subscribers")
List<ProfilePreviewModel> get subscribers =>
throw _privateConstructorUsedError;
/// Serializes this ProfileModel to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@@ -66,7 +75,10 @@ abstract class $ProfileModelCopyWith<$Res> {
@JsonKey(name: "is_public_profile") bool isPublicProfile,
@JsonKey(name: "slug") String slug,
@JsonKey(name: "profile_photo_url") String profilePhotoUrl,
String role});
@JsonKey(name: "role") String role,
@JsonKey(name: "badges") List<BadgeModel> badges,
@JsonKey(name: "subscriptions") List<ProfilePreviewModel> subscriptions,
@JsonKey(name: "subscribers") List<ProfilePreviewModel> subscribers});
}
/// @nodoc
@@ -94,6 +106,9 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel>
Object? slug = null,
Object? profilePhotoUrl = null,
Object? role = null,
Object? badges = null,
Object? subscriptions = null,
Object? subscribers = null,
}) {
return _then(_value.copyWith(
id: null == id
@@ -136,6 +151,18 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel>
? _value.role
: role // ignore: cast_nullable_to_non_nullable
as String,
badges: null == badges
? _value.badges
: badges // ignore: cast_nullable_to_non_nullable
as List<BadgeModel>,
subscriptions: null == subscriptions
? _value.subscriptions
: subscriptions // ignore: cast_nullable_to_non_nullable
as List<ProfilePreviewModel>,
subscribers: null == subscribers
? _value.subscribers
: subscribers // ignore: cast_nullable_to_non_nullable
as List<ProfilePreviewModel>,
) as $Val);
}
}
@@ -158,7 +185,10 @@ abstract class _$$ProfileModelImplCopyWith<$Res>
@JsonKey(name: "is_public_profile") bool isPublicProfile,
@JsonKey(name: "slug") String slug,
@JsonKey(name: "profile_photo_url") String profilePhotoUrl,
String role});
@JsonKey(name: "role") String role,
@JsonKey(name: "badges") List<BadgeModel> badges,
@JsonKey(name: "subscriptions") List<ProfilePreviewModel> subscriptions,
@JsonKey(name: "subscribers") List<ProfilePreviewModel> subscribers});
}
/// @nodoc
@@ -184,6 +214,9 @@ class __$$ProfileModelImplCopyWithImpl<$Res>
Object? slug = null,
Object? profilePhotoUrl = null,
Object? role = null,
Object? badges = null,
Object? subscriptions = null,
Object? subscribers = null,
}) {
return _then(_$ProfileModelImpl(
id: null == id
@@ -226,6 +259,18 @@ class __$$ProfileModelImplCopyWithImpl<$Res>
? _value.role
: role // ignore: cast_nullable_to_non_nullable
as String,
badges: null == badges
? _value._badges
: badges // ignore: cast_nullable_to_non_nullable
as List<BadgeModel>,
subscriptions: null == subscriptions
? _value._subscriptions
: subscriptions // ignore: cast_nullable_to_non_nullable
as List<ProfilePreviewModel>,
subscribers: null == subscribers
? _value._subscribers
: subscribers // ignore: cast_nullable_to_non_nullable
as List<ProfilePreviewModel>,
));
}
}
@@ -243,7 +288,15 @@ class _$ProfileModelImpl implements _ProfileModel {
@JsonKey(name: "is_public_profile") required this.isPublicProfile,
@JsonKey(name: "slug") required this.slug,
@JsonKey(name: "profile_photo_url") required this.profilePhotoUrl,
required this.role});
@JsonKey(name: "role") required this.role,
@JsonKey(name: "badges") required final List<BadgeModel> badges,
@JsonKey(name: "subscriptions")
required final List<ProfilePreviewModel> subscriptions,
@JsonKey(name: "subscribers")
required final List<ProfilePreviewModel> subscribers})
: _badges = badges,
_subscriptions = subscriptions,
_subscribers = subscribers;
factory _$ProfileModelImpl.fromJson(Map<String, dynamic> json) =>
_$$ProfileModelImplFromJson(json);
@@ -276,11 +329,38 @@ class _$ProfileModelImpl implements _ProfileModel {
@JsonKey(name: "profile_photo_url")
final String profilePhotoUrl;
@override
@JsonKey(name: "role")
final String role;
final List<BadgeModel> _badges;
@override
@JsonKey(name: "badges")
List<BadgeModel> get badges {
if (_badges is EqualUnmodifiableListView) return _badges;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_badges);
}
final List<ProfilePreviewModel> _subscriptions;
@override
@JsonKey(name: "subscriptions")
List<ProfilePreviewModel> get subscriptions {
if (_subscriptions is EqualUnmodifiableListView) return _subscriptions;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_subscriptions);
}
final List<ProfilePreviewModel> _subscribers;
@override
@JsonKey(name: "subscribers")
List<ProfilePreviewModel> get subscribers {
if (_subscribers is EqualUnmodifiableListView) return _subscribers;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_subscribers);
}
@override
String toString() {
return 'ProfileModel(id: $id, name: $name, email: $email, emailVerifiedAt: $emailVerifiedAt, createdAt: $createdAt, updatedAt: $updatedAt, isPublicProfile: $isPublicProfile, slug: $slug, profilePhotoUrl: $profilePhotoUrl, role: $role)';
return 'ProfileModel(id: $id, name: $name, email: $email, emailVerifiedAt: $emailVerifiedAt, createdAt: $createdAt, updatedAt: $updatedAt, isPublicProfile: $isPublicProfile, slug: $slug, profilePhotoUrl: $profilePhotoUrl, role: $role, badges: $badges, subscriptions: $subscriptions, subscribers: $subscribers)';
}
@override
@@ -302,13 +382,31 @@ class _$ProfileModelImpl implements _ProfileModel {
(identical(other.slug, slug) || other.slug == slug) &&
(identical(other.profilePhotoUrl, profilePhotoUrl) ||
other.profilePhotoUrl == profilePhotoUrl) &&
(identical(other.role, role) || other.role == role));
(identical(other.role, role) || other.role == role) &&
const DeepCollectionEquality().equals(other._badges, _badges) &&
const DeepCollectionEquality()
.equals(other._subscriptions, _subscriptions) &&
const DeepCollectionEquality()
.equals(other._subscribers, _subscribers));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, id, name, email, emailVerifiedAt,
createdAt, updatedAt, isPublicProfile, slug, profilePhotoUrl, role);
int get hashCode => Object.hash(
runtimeType,
id,
name,
email,
emailVerifiedAt,
createdAt,
updatedAt,
isPublicProfile,
slug,
profilePhotoUrl,
role,
const DeepCollectionEquality().hash(_badges),
const DeepCollectionEquality().hash(_subscriptions),
const DeepCollectionEquality().hash(_subscribers));
/// Create a copy of ProfileModel
/// with the given fields replaced by the non-null parameter values.
@@ -337,7 +435,13 @@ abstract class _ProfileModel implements ProfileModel {
@JsonKey(name: "is_public_profile") required final bool isPublicProfile,
@JsonKey(name: "slug") required final String slug,
@JsonKey(name: "profile_photo_url") required final String profilePhotoUrl,
required final String role}) = _$ProfileModelImpl;
@JsonKey(name: "role") required final String role,
@JsonKey(name: "badges") required final List<BadgeModel> badges,
@JsonKey(name: "subscriptions")
required final List<ProfilePreviewModel> subscriptions,
@JsonKey(name: "subscribers")
required final List<ProfilePreviewModel>
subscribers}) = _$ProfileModelImpl;
factory _ProfileModel.fromJson(Map<String, dynamic> json) =
_$ProfileModelImpl.fromJson;
@@ -370,7 +474,17 @@ abstract class _ProfileModel implements ProfileModel {
@JsonKey(name: "profile_photo_url")
String get profilePhotoUrl;
@override
@JsonKey(name: "role")
String get role;
@override
@JsonKey(name: "badges")
List<BadgeModel> get badges;
@override
@JsonKey(name: "subscriptions")
List<ProfilePreviewModel> get subscriptions;
@override
@JsonKey(name: "subscribers")
List<ProfilePreviewModel> get subscribers;
/// Create a copy of ProfileModel
/// with the given fields replaced by the non-null parameter values.
@@ -1190,3 +1304,160 @@ abstract class _ProfileDetailsModel implements ProfileDetailsModel {
_$$ProfileDetailsModelImplCopyWith<_$ProfileDetailsModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}
ProfilePreviewModel _$ProfilePreviewModelFromJson(Map<String, dynamic> json) {
return _ProfilePreviewModel.fromJson(json);
}
/// @nodoc
mixin _$ProfilePreviewModel {
@JsonKey(name: "profile_photo_url")
String get profilePhotoUrl => throw _privateConstructorUsedError;
/// Serializes this ProfilePreviewModel to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of ProfilePreviewModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ProfilePreviewModelCopyWith<ProfilePreviewModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ProfilePreviewModelCopyWith<$Res> {
factory $ProfilePreviewModelCopyWith(
ProfilePreviewModel value, $Res Function(ProfilePreviewModel) then) =
_$ProfilePreviewModelCopyWithImpl<$Res, ProfilePreviewModel>;
@useResult
$Res call({@JsonKey(name: "profile_photo_url") String profilePhotoUrl});
}
/// @nodoc
class _$ProfilePreviewModelCopyWithImpl<$Res, $Val extends ProfilePreviewModel>
implements $ProfilePreviewModelCopyWith<$Res> {
_$ProfilePreviewModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ProfilePreviewModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? profilePhotoUrl = null,
}) {
return _then(_value.copyWith(
profilePhotoUrl: null == profilePhotoUrl
? _value.profilePhotoUrl
: profilePhotoUrl // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$ProfilePreviewModelImplCopyWith<$Res>
implements $ProfilePreviewModelCopyWith<$Res> {
factory _$$ProfilePreviewModelImplCopyWith(_$ProfilePreviewModelImpl value,
$Res Function(_$ProfilePreviewModelImpl) then) =
__$$ProfilePreviewModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({@JsonKey(name: "profile_photo_url") String profilePhotoUrl});
}
/// @nodoc
class __$$ProfilePreviewModelImplCopyWithImpl<$Res>
extends _$ProfilePreviewModelCopyWithImpl<$Res, _$ProfilePreviewModelImpl>
implements _$$ProfilePreviewModelImplCopyWith<$Res> {
__$$ProfilePreviewModelImplCopyWithImpl(_$ProfilePreviewModelImpl _value,
$Res Function(_$ProfilePreviewModelImpl) _then)
: super(_value, _then);
/// Create a copy of ProfilePreviewModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? profilePhotoUrl = null,
}) {
return _then(_$ProfilePreviewModelImpl(
profilePhotoUrl: null == profilePhotoUrl
? _value.profilePhotoUrl
: profilePhotoUrl // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ProfilePreviewModelImpl implements _ProfilePreviewModel {
const _$ProfilePreviewModelImpl(
{@JsonKey(name: "profile_photo_url") required this.profilePhotoUrl});
factory _$ProfilePreviewModelImpl.fromJson(Map<String, dynamic> json) =>
_$$ProfilePreviewModelImplFromJson(json);
@override
@JsonKey(name: "profile_photo_url")
final String profilePhotoUrl;
@override
String toString() {
return 'ProfilePreviewModel(profilePhotoUrl: $profilePhotoUrl)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ProfilePreviewModelImpl &&
(identical(other.profilePhotoUrl, profilePhotoUrl) ||
other.profilePhotoUrl == profilePhotoUrl));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, profilePhotoUrl);
/// Create a copy of ProfilePreviewModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ProfilePreviewModelImplCopyWith<_$ProfilePreviewModelImpl> get copyWith =>
__$$ProfilePreviewModelImplCopyWithImpl<_$ProfilePreviewModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ProfilePreviewModelImplToJson(
this,
);
}
}
abstract class _ProfilePreviewModel implements ProfilePreviewModel {
const factory _ProfilePreviewModel(
{@JsonKey(name: "profile_photo_url")
required final String profilePhotoUrl}) = _$ProfilePreviewModelImpl;
factory _ProfilePreviewModel.fromJson(Map<String, dynamic> json) =
_$ProfilePreviewModelImpl.fromJson;
@override
@JsonKey(name: "profile_photo_url")
String get profilePhotoUrl;
/// Create a copy of ProfilePreviewModel
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ProfilePreviewModelImplCopyWith<_$ProfilePreviewModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -24,6 +24,15 @@ _$ProfileModelImpl _$$ProfileModelImplFromJson(Map<String, dynamic> json) =>
slug: json['slug'] as String,
profilePhotoUrl: json['profile_photo_url'] as String,
role: json['role'] as String,
badges: (json['badges'] as List<dynamic>)
.map((e) => BadgeModel.fromJson(e as Map<String, dynamic>))
.toList(),
subscriptions: (json['subscriptions'] as List<dynamic>)
.map((e) => ProfilePreviewModel.fromJson(e as Map<String, dynamic>))
.toList(),
subscribers: (json['subscribers'] as List<dynamic>)
.map((e) => ProfilePreviewModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$ProfileModelImplToJson(_$ProfileModelImpl instance) =>
@@ -38,6 +47,9 @@ Map<String, dynamic> _$$ProfileModelImplToJson(_$ProfileModelImpl instance) =>
'slug': instance.slug,
'profile_photo_url': instance.profilePhotoUrl,
'role': instance.role,
'badges': instance.badges,
'subscriptions': instance.subscriptions,
'subscribers': instance.subscribers,
};
_$ProfileDetailsModelImpl _$$ProfileDetailsModelImplFromJson(
@@ -107,3 +119,15 @@ Map<String, dynamic> _$$ProfileDetailsModelImplToJson(
'is_bedtime_fillable': instance.isBedtimeFillable,
'activity_coefficient': instance.activityCoefficient,
};
_$ProfilePreviewModelImpl _$$ProfilePreviewModelImplFromJson(
Map<String, dynamic> json) =>
_$ProfilePreviewModelImpl(
profilePhotoUrl: json['profile_photo_url'] as String,
);
Map<String, dynamic> _$$ProfilePreviewModelImplToJson(
_$ProfilePreviewModelImpl instance) =>
<String, dynamic>{
'profile_photo_url': instance.profilePhotoUrl,
};

View File

@@ -1,13 +1,16 @@
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_state.dart';
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ProfileCubit extends Cubit<ProfileState> {
final ProfileRepository profileRepository;
final ChatRepository chatRepository;
String _currentPeriod = '1';
ProfileCubit({
required this.profileRepository,
required this.chatRepository,
}) : super(const ProfileState.loading());
getProfileBySlug(String slug) async {
@@ -71,4 +74,15 @@ class ProfileCubit extends Cubit<ProfileState> {
print(e);
}
}
Future<String> getChatRoomIdBySlug({
required String slug,
}) async {
try {
return (await chatRepository.getChatRoomIdByUserSlug(slug: slug)).id;
} catch (e) {
print(e);
rethrow;
}
}
}

View File

@@ -17,7 +17,10 @@ import 'package:rive/rive.dart';
class ProfileScreen extends StatefulWidget {
final Author? author;
const ProfileScreen({super.key, this.author});
const ProfileScreen({
super.key,
this.author,
});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
@@ -49,254 +52,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
circumferencePoints = state.circumferencePoints!;
weightPoints = state.weightPoints!;
}
return Scaffold(
backgroundColor: Colors.grey.shade200,
appBar: widget.author == null ? AppBar(toolbarHeight: 0) : AppBar(),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(16),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
CircleAvatar(
radius: 32,
backgroundImage: NetworkImage(state.profile.profilePhotoUrl),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
state.profile.name,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
height: 1,
),
),
const SizedBox(height: 8),
Row(
children: [
Icon(
Icons.info_outline,
size: 20,
color: Color(0xFF6D6F71),
),
const SizedBox(width: 4),
Text(
'Дополнительно',
style: TextStyle(
color: Color(0xFF6D6F71),
),
),
],
),
],
),
const Spacer(),
IconButton(
onPressed: () {},
icon: Icon(Icons.more_horiz_rounded),
),
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// Container(
// child: SvgPicture.asset(
// height: 28,
// width: 28,
// 'assets/icons/subscribers.svg',
// colorFilter: ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn),
// ),
// ),
// SizedBox(width: 8),
// Column(
// children: [
// Text(
// '123',
// style: TextStyle(
// height: 1,
// fontSize: 18,
// fontWeight: FontWeight.w500,
// color: Colors.black87,
// ),
// ),
// Text(
// 'Подписчика',
// style: TextStyle(
// height: 1,
// fontSize: 12,
// fontWeight: FontWeight.w400,
// color: Colors.black38,
// ),
// ),
// ],
// ),
// ],
// ),
// GestureDetector(
// onTap: () => Share.shareUri(
// Uri.parse(
// baseUrl + '/ru/profile/' + state.profile.slug,
// ),
// ),
// child: Container(
// padding: EdgeInsets.only(left: 16),
// child: SvgPicture.asset(
// height: 24,
// width: 24,
// 'assets/icons/share.svg',
// colorFilter: ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn),
// ),
// ),
// ),
],
),
),
if (state.profileDetails.additionalInfo.isNotEmpty)
Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.all(16),
child: Text(
state.profileDetails.additionalInfo,
style: TextStyle(
color: Colors.black.withOpacity(0.4),
height: 1,
),
),
),
if (widget.author != null) const SizedBox(height: 8),
if (widget.author != null)
Row(
children: [
SizedBox(width: 16),
GestureDetector(
onTap: () => GoRouter.of(context).pushNamed(
'chatScreen',
),
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8),
width: (MediaQuery.of(context).size.width - 40) / 2,
decoration: BoxDecoration(
color: appTheme.blueA400.withOpacity(0.1),
borderRadius: BorderRadius.circular(16),
),
child: Text(
'Сообщение',
style: TextStyle(
color: appTheme.blueA400,
),
),
),
),
SizedBox(width: 8),
Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8),
width: (MediaQuery.of(context).size.width - 40) / 2,
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.circular(16),
),
child: Text(
'Подписаться',
style: TextStyle(
color: Colors.white,
),
),
),
SizedBox(width: 16),
],
),
if (widget.author != null) SizedBox(height: 16),
if (widget.author == null) _divider(context),
if (widget.author == null)
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) {
switch (_selectedChipIndex) {
case 0:
return WeightChartWidget(
weightPoints: weightPoints,
profileCubit: profileCubit,
);
case 1:
return CircumferenceChartWidget(
circumferencePoints: circumferencePoints,
profileCubit: profileCubit,
);
case 2:
return ImtChartWidget(
weightPoints: weightPoints,
);
}
return SizedBox.shrink();
},
),
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),
],
),
),
);
return _profileScreen(state);
} else if (state is ProfileStateError) {
return Scaffold(
appBar: AppBar(),
@@ -325,13 +81,388 @@ class _ProfileScreenState extends State<ProfileScreen> {
);
}
_divider(BuildContext context) {
_profileScreen(ProfileStateLoaded state) {
return Scaffold(
backgroundColor: Colors.grey.shade200,
appBar: widget.author == null ? AppBar(toolbarHeight: 0) : AppBar(),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(16),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_header(state),
if (state.profileDetails.additionalInfo.isNotEmpty) _additionalInfo(state),
if (widget.author != null) const SizedBox(height: 8),
if (widget.author != null) _messageAndSubscribe(),
if (widget.author != null) SizedBox(height: 16),
],
),
),
_subscriptionsAndSubscribers(state),
_badges(state),
if (widget.author == null) SizedBox(height: 16),
if (widget.author == null) _charts(),
_blogPosts(state),
],
),
),
);
}
_badges(ProfileStateLoaded state) {
if (state.profile.badges.isEmpty) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(12),
child: Ink(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Достижения',
style: TextStyle(
color: Color(0xFF6D6F71),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
// CircleAvatar(
// backgroundImage: NetworkImage(
// state.profile.badges.first.image,
// ),
// radius: 20,
// ),
],
),
),
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
),
),
);
}
_subscriptionsAndSubscribers(ProfileStateLoaded state) {
return Padding(
padding: const EdgeInsets.all(4),
child: Row(
children: [
InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(12),
child: Ink(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width / 2 - 6,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Подписки',
style: TextStyle(
color: Color(0xFF6D6F71),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
Text(
'${state.profile.subscriptions.length}',
style: TextStyle(
color: Color(0xFF323F4B),
fontSize: 22,
fontWeight: FontWeight.w700,
),
),
],
),
Padding(
padding: EdgeInsets.only(right: 8),
child: _miniAvatars(state.profile.subscriptions.map((e) => e.profilePhotoUrl).toList()),
),
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
),
),
SizedBox(width: 4),
InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(12),
child: Ink(
padding: const EdgeInsets.all(8),
width: MediaQuery.of(context).size.width / 2 - 6,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Подписчики',
style: TextStyle(
color: Color(0xFF6D6F71),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
Text(
'${state.profile.subscribers.length}',
style: TextStyle(
color: Color(0xFF323F4B),
fontSize: 22,
fontWeight: FontWeight.w700,
),
),
],
),
Padding(
padding: EdgeInsets.only(right: 8),
child: _miniAvatars(state.profile.subscribers.map((e) => e.profilePhotoUrl).toList()),
),
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
),
),
],
),
);
}
_miniAvatars(List<String> urls) {
int maxLength = urls.length > 2 ? 3 : urls.length;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (int i = 0; i < maxLength; i++)
Align(
widthFactor: 0.8,
child: CircleAvatar(
radius: 14,
backgroundImage: NetworkImage(
urls[i],
),
),
),
],
);
}
_blogPosts(ProfileStateLoaded state) {
return ListView.separated(
padding: EdgeInsets.symmetric(vertical: 16),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => BlogPostWidget(feedBlogPostModel: state.blogPosts[index]),
separatorBuilder: (context, index) => SizedBox(height: 8),
itemCount: state.blogPosts.length,
);
}
_additionalInfo(ProfileStateLoaded state) {
return Container(
height: 0.4,
width: MediaQuery.of(context).size.width - 32,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(16),
alignment: Alignment.centerLeft,
padding: const EdgeInsets.all(16),
child: Text(
state.profileDetails.additionalInfo,
style: TextStyle(
color: Colors.black.withOpacity(0.4),
height: 1,
),
),
);
}
_header(ProfileStateLoaded state) {
return Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
CircleAvatar(
radius: 32,
backgroundImage: NetworkImage(state.profile.profilePhotoUrl),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
state.profile.name,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
height: 1,
),
),
const SizedBox(height: 8),
Row(
children: [
Icon(
Icons.info_outline,
size: 20,
color: Color(0xFF6D6F71),
),
const SizedBox(width: 4),
Text(
'Дополнительно',
style: TextStyle(
color: Color(0xFF6D6F71),
),
),
],
),
],
),
const Spacer(),
IconButton(
onPressed: () {},
icon: Icon(Icons.more_horiz_rounded),
),
],
),
);
}
_messageAndSubscribe() {
return Row(
children: [
SizedBox(width: 16),
GestureDetector(
onTap: () async {
GoRouter.of(context).pushNamed(
'chatScreen',
extra: await profileCubit.getChatRoomIdBySlug(slug: widget.author!.authorSlug),
);
},
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8),
width: (MediaQuery.of(context).size.width - 40) / 2,
decoration: BoxDecoration(
color: appTheme.blueA400.withOpacity(0.1),
borderRadius: BorderRadius.circular(16),
),
child: Text(
'Сообщение',
style: TextStyle(
color: appTheme.blueA400,
),
),
),
),
SizedBox(width: 8),
Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8),
width: (MediaQuery.of(context).size.width - 40) / 2,
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.circular(16),
),
child: Text(
'Подписаться',
style: TextStyle(
color: Colors.white,
),
),
),
SizedBox(width: 16),
],
);
}
_charts() {
return Material(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
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) {
switch (_selectedChipIndex) {
case 0:
return WeightChartWidget(
weightPoints: weightPoints,
profileCubit: profileCubit,
);
case 1:
return CircumferenceChartWidget(
circumferencePoints: circumferencePoints,
profileCubit: profileCubit,
);
case 2:
return ImtChartWidget(
weightPoints: weightPoints,
);
}
return SizedBox.shrink();
},
),
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),
],
),
);
}

View File

@@ -55,7 +55,7 @@ Future<void> init() async {
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl()));
sl.registerFactory<DiaryBloc>(() => DiaryBloc(diaryRepository: sl()));
sl.registerFactory<CalendarCubit>(() => CalendarCubit(calendarRepository: sl()));
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl()));
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
sl.registerFactory<ProfileAvatarCubit>(() => ProfileAvatarCubit(profileRepository: sl()));
sl.registerFactory<RecipeCreateCubit>(() => RecipeCreateCubit(recipeRepository: sl()));
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl()));